@oeronteros-1/opencode-orchestra 1.0.22 → 1.0.24
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/README.md +19 -5
- package/dashboard-dist/assets/index-Dc5lp8wX.js +124 -0
- package/dashboard-dist/index.html +1 -1
- package/dist/agents/build.js +4 -0
- package/dist/agents/build.js.map +1 -1
- package/dist/agents/editor.d.ts +3 -0
- package/dist/agents/editor.js +12 -0
- package/dist/agents/editor.js.map +1 -0
- package/dist/agents/integrator.d.ts +3 -0
- package/dist/agents/integrator.js +12 -0
- package/dist/agents/integrator.js.map +1 -0
- package/dist/agents/lead.js +3 -1
- package/dist/agents/lead.js.map +1 -1
- package/dist/agents/workers.js +1 -6
- package/dist/agents/workers.js.map +1 -1
- package/dist/cache-refresh.d.ts +42 -0
- package/dist/cache-refresh.js +130 -0
- package/dist/cache-refresh.js.map +1 -0
- package/dist/cli.d.ts +16 -2
- package/dist/cli.js +59 -26
- package/dist/cli.js.map +1 -1
- package/dist/config/schema.d.ts +11 -1
- package/dist/config/schema.js +30 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/dashboard/server.js +2 -2
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +35 -12
- package/dist/index.js.map +1 -1
- package/dist/orchestration/ownership.d.ts +7 -0
- package/dist/orchestration/ownership.js +45 -0
- package/dist/orchestration/ownership.js.map +1 -0
- package/dist/orchestration/worktree-adapter.d.ts +3 -0
- package/dist/orchestration/worktree-adapter.js +45 -0
- package/dist/orchestration/worktree-adapter.js.map +1 -0
- package/dist/orchestration/worktrees.d.ts +22 -0
- package/dist/orchestration/worktrees.js +27 -0
- package/dist/orchestration/worktrees.js.map +1 -0
- package/dist/pricing/cost.d.ts +29 -0
- package/dist/pricing/cost.js +47 -0
- package/dist/pricing/cost.js.map +1 -0
- package/dist/pricing/model-match.d.ts +59 -0
- package/dist/pricing/model-match.js +134 -0
- package/dist/pricing/model-match.js.map +1 -0
- package/dist/pricing/openrouter.d.ts +60 -0
- package/dist/pricing/openrouter.js +150 -0
- package/dist/pricing/openrouter.js.map +1 -0
- package/dist/pricing/resolver.d.ts +50 -0
- package/dist/pricing/resolver.js +145 -0
- package/dist/pricing/resolver.js.map +1 -0
- package/dist/prompts/load.js +1 -1
- package/dist/prompts/load.js.map +1 -1
- package/dist/routing/planner.d.ts +14 -1
- package/dist/routing/planner.js +23 -1
- package/dist/routing/planner.js.map +1 -1
- package/dist/routing/pricing/estimate.d.ts +14 -1
- package/dist/routing/pricing/estimate.js +81 -20
- package/dist/routing/pricing/estimate.js.map +1 -1
- package/dist/telemetry/ledger.d.ts +6 -1
- package/dist/telemetry/ledger.js +15 -3
- package/dist/telemetry/ledger.js.map +1 -1
- package/dist/tools.d.ts +3 -0
- package/dist/tools.js +44 -1
- package/dist/tools.js.map +1 -1
- package/package.json +16 -2
- package/prompts/lead.md +1 -0
- package/schema/opencode-orchestra.schema.json +23 -1
- package/dashboard-dist/assets/index-BZTn_d2K.js +0 -124
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// OpenRouter pricing source. The models list is a public, keyless endpoint;
|
|
2
|
+
// prices arrive as decimal strings in USD per single token and are converted
|
|
3
|
+
// here to USD per 1M tokens, matching the plugin's internal unit everywhere
|
|
4
|
+
// else. Per-request prices (request/image/audio) stay in their own units and
|
|
5
|
+
// are never multiplied by token counts. Fetching is cached with a TTL and
|
|
6
|
+
// single-flight; failures keep the previous snapshot so offline estimation
|
|
7
|
+
// keeps working.
|
|
8
|
+
import { normalizeModelName, splitProviderId } from "./model-match.js";
|
|
9
|
+
function toPrice(value) {
|
|
10
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
11
|
+
return undefined;
|
|
12
|
+
const parsed = Number(value);
|
|
13
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Convert a per-token string price to USD per 1M, rounded to micro-dollars. */
|
|
16
|
+
function toPerMillion(value) {
|
|
17
|
+
const parsed = toPrice(value);
|
|
18
|
+
if (parsed === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
return Math.round(parsed * 1_000_000 * 1_000_000) / 1_000_000;
|
|
21
|
+
}
|
|
22
|
+
function splitVariant(id) {
|
|
23
|
+
const idx = id.lastIndexOf(":");
|
|
24
|
+
if (idx === -1)
|
|
25
|
+
return { base: id };
|
|
26
|
+
return { base: id.slice(0, idx), variant: id.slice(idx + 1) };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse an OpenRouter `/api/v1/models` response into normalized models.
|
|
30
|
+
* Missing or invalid price fields become undefined (never 0, never throws).
|
|
31
|
+
*/
|
|
32
|
+
export function parseOpenRouterModels(text) {
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
parsed = JSON.parse(text);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
41
|
+
return [];
|
|
42
|
+
const data = parsed.data;
|
|
43
|
+
if (!Array.isArray(data))
|
|
44
|
+
return [];
|
|
45
|
+
const models = [];
|
|
46
|
+
for (const item of data) {
|
|
47
|
+
if (typeof item !== "object" || item === null)
|
|
48
|
+
continue;
|
|
49
|
+
const raw = item;
|
|
50
|
+
if (typeof raw.id !== "string" || !raw.id)
|
|
51
|
+
continue;
|
|
52
|
+
const { base, variant } = splitVariant(raw.id);
|
|
53
|
+
const pricingRaw = (typeof raw.pricing === "object" && raw.pricing !== null ? raw.pricing : {});
|
|
54
|
+
const input = toPerMillion(pricingRaw.prompt);
|
|
55
|
+
const output = toPerMillion(pricingRaw.completion);
|
|
56
|
+
const cacheRead = toPerMillion(pricingRaw.input_cache_read);
|
|
57
|
+
const reasoning = toPerMillion(pricingRaw.internal_reasoning);
|
|
58
|
+
const request = toPrice(pricingRaw.request);
|
|
59
|
+
const image = toPrice(pricingRaw.image);
|
|
60
|
+
const audio = toPrice(pricingRaw.audio);
|
|
61
|
+
models.push({
|
|
62
|
+
id: base.toLowerCase(),
|
|
63
|
+
...(variant ? { variant } : {}),
|
|
64
|
+
...(typeof raw.name === "string" && raw.name ? { name: raw.name } : {}),
|
|
65
|
+
...(typeof raw.canonical_slug === "string" && raw.canonical_slug
|
|
66
|
+
? { canonicalSlug: splitProviderId(raw.canonical_slug).rest }
|
|
67
|
+
: {}),
|
|
68
|
+
...(typeof raw.context_length === "number" ? { contextLength: raw.context_length } : {}),
|
|
69
|
+
isFreeVariant: variant === "free",
|
|
70
|
+
pricing: {
|
|
71
|
+
...(input !== undefined ? { input } : {}),
|
|
72
|
+
...(output !== undefined ? { output } : {}),
|
|
73
|
+
...(cacheRead !== undefined ? { cacheRead } : {}),
|
|
74
|
+
...(reasoning !== undefined ? { reasoning } : {}),
|
|
75
|
+
...(request !== undefined ? { request } : {}),
|
|
76
|
+
...(image !== undefined ? { image } : {}),
|
|
77
|
+
...(audio !== undefined ? { audio } : {}),
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return models;
|
|
82
|
+
}
|
|
83
|
+
/** Build matchModel catalog entries from a parsed OpenRouter list. */
|
|
84
|
+
export function toModelEntries(models) {
|
|
85
|
+
const entries = [];
|
|
86
|
+
for (const model of models) {
|
|
87
|
+
const { provider, rest } = splitProviderId(model.id);
|
|
88
|
+
const aliases = [];
|
|
89
|
+
if (model.name)
|
|
90
|
+
aliases.push(model.name);
|
|
91
|
+
if (model.canonicalSlug)
|
|
92
|
+
aliases.push(model.canonicalSlug);
|
|
93
|
+
entries.push({
|
|
94
|
+
id: normalizeModelName(rest),
|
|
95
|
+
...(provider ? { provider } : {}),
|
|
96
|
+
...(aliases.length ? { aliases } : {}),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return entries;
|
|
100
|
+
}
|
|
101
|
+
export const DEFAULT_OPENROUTER_ENDPOINT = "https://openrouter.ai/api/v1/models";
|
|
102
|
+
/**
|
|
103
|
+
* TTL-on-data cache over the OpenRouter models list. Concurrent callers
|
|
104
|
+
* share one in-flight fetch; a failed refresh keeps the previous snapshot.
|
|
105
|
+
*/
|
|
106
|
+
export function createOpenRouterCache(options) {
|
|
107
|
+
const endpoint = options.endpoint ?? DEFAULT_OPENROUTER_ENDPOINT;
|
|
108
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
109
|
+
const now = options.now ?? Date.now;
|
|
110
|
+
let models;
|
|
111
|
+
let fetchedAt;
|
|
112
|
+
let lastError;
|
|
113
|
+
let inFlight;
|
|
114
|
+
const refresh = () => {
|
|
115
|
+
inFlight = (async () => {
|
|
116
|
+
try {
|
|
117
|
+
const response = await fetchImpl(endpoint);
|
|
118
|
+
if (!response.ok)
|
|
119
|
+
throw new Error(`openrouter ${response.status}`);
|
|
120
|
+
models = parseOpenRouterModels(await response.text());
|
|
121
|
+
fetchedAt = now();
|
|
122
|
+
lastError = undefined;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
126
|
+
}
|
|
127
|
+
return models ?? [];
|
|
128
|
+
})().finally(() => {
|
|
129
|
+
inFlight = undefined;
|
|
130
|
+
});
|
|
131
|
+
return inFlight;
|
|
132
|
+
};
|
|
133
|
+
const getModels = (force = false) => {
|
|
134
|
+
if (inFlight)
|
|
135
|
+
return inFlight;
|
|
136
|
+
if (force || models === undefined || now() - (fetchedAt ?? 0) >= options.ttlMs)
|
|
137
|
+
return refresh();
|
|
138
|
+
return Promise.resolve(models);
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
getModels,
|
|
142
|
+
get fetchedAt() {
|
|
143
|
+
return fetchedAt;
|
|
144
|
+
},
|
|
145
|
+
get lastError() {
|
|
146
|
+
return lastError;
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/pricing/openrouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PriceSnapshot } from "../routing/pricing/prices.js";
|
|
2
|
+
import type { ModelCost } from "../config/schema.js";
|
|
3
|
+
import { type MatchMethod } from "./model-match.js";
|
|
4
|
+
import { type OpenRouterModel } from "./openrouter.js";
|
|
5
|
+
import type { PricingResolution } from "./cost.js";
|
|
6
|
+
export interface ModelAliasEntry {
|
|
7
|
+
/** Canonical model id the aliases point at, e.g. "gpt-5-6-sol". */
|
|
8
|
+
canonical: string;
|
|
9
|
+
/** Raw names that map to the canonical id. */
|
|
10
|
+
aliases: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface OpenRouterSource {
|
|
13
|
+
getModels(force?: boolean): Promise<OpenRouterModel[]>;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolverConfig {
|
|
16
|
+
snapshot: PriceSnapshot;
|
|
17
|
+
aliases?: ModelAliasEntry[];
|
|
18
|
+
openRouter?: OpenRouterSource;
|
|
19
|
+
}
|
|
20
|
+
export interface ResolverInput {
|
|
21
|
+
/** Raw id, optionally provider-prefixed ("CX/GPT-5.6 Sol"). */
|
|
22
|
+
id?: string;
|
|
23
|
+
providerID?: string;
|
|
24
|
+
modelID?: string;
|
|
25
|
+
/** Config-declared cost class when known (routing pools, provider catalog). */
|
|
26
|
+
declaredCost?: ModelCost;
|
|
27
|
+
/** Explicit configured USD/1M prices; beat every lookup source. */
|
|
28
|
+
explicitPrice?: {
|
|
29
|
+
input: number;
|
|
30
|
+
output: number;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface ResolvedPricing extends PricingResolution {
|
|
34
|
+
/** Canonical normalized model id ("gpt-5-6-sol"). */
|
|
35
|
+
canonicalId?: string;
|
|
36
|
+
/** Where the price came from. */
|
|
37
|
+
source?: "config" | "snapshot" | "openrouter";
|
|
38
|
+
/** How the model identity was matched. */
|
|
39
|
+
method?: MatchMethod;
|
|
40
|
+
familyAmbiguous?: boolean;
|
|
41
|
+
/** True when the async OpenRouter tier should still be tried. */
|
|
42
|
+
needsFallback?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Sync tier: config declarations + user aliases + the price snapshot. */
|
|
45
|
+
export declare function resolvePricingSync(input: ResolverInput, config: ResolverConfig): ResolvedPricing;
|
|
46
|
+
/**
|
|
47
|
+
* Full resolution: sync tier first, then the cached OpenRouter catalog when
|
|
48
|
+
* the price is still unknown. Never fetches when OpenRouter is disabled.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolvePricing(input: ResolverInput, config: ResolverConfig): Promise<ResolvedPricing>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Pricing Resolver: turns a raw model id (any spelling, any provider prefix)
|
|
2
|
+
// into a PricingResolution. Precedence, highest first:
|
|
3
|
+
//
|
|
4
|
+
// 1. config-declared cost class (free / subscription)
|
|
5
|
+
// 2. explicit configured price (priceInput/priceOutput)
|
|
6
|
+
// 3. ":free" variant suffix in the raw id
|
|
7
|
+
// 4. user-defined model aliases (they beat every external source)
|
|
8
|
+
// 5. built-in / operator-refreshed price snapshot (provider pricing)
|
|
9
|
+
// 6. OpenRouter fallback (opt-in; cached; async)
|
|
10
|
+
// 7. unknown — tokens still counted, cost null, never silently free
|
|
11
|
+
//
|
|
12
|
+
// Free models and subscription models are priced $0 with their status kept;
|
|
13
|
+
// "unknown" is a distinct state so callers can surface "no price" honestly.
|
|
14
|
+
import { matchModel, normalizeModelName, parseModelId, splitProviderId, } from "./model-match.js";
|
|
15
|
+
import { toModelEntries } from "./openrouter.js";
|
|
16
|
+
function snapshotCatalog(snapshot) {
|
|
17
|
+
const entries = [];
|
|
18
|
+
const keyByEntryId = new Map();
|
|
19
|
+
for (const key of Object.keys(snapshot.prices)) {
|
|
20
|
+
const { provider, rest } = splitProviderId(key);
|
|
21
|
+
const entryId = normalizeModelName(rest);
|
|
22
|
+
entries.push({
|
|
23
|
+
id: entryId,
|
|
24
|
+
...(provider ? { provider: normalizeModelName(provider) } : {}),
|
|
25
|
+
});
|
|
26
|
+
keyByEntryId.set(entryId, key);
|
|
27
|
+
}
|
|
28
|
+
return { entries, keyByEntryId };
|
|
29
|
+
}
|
|
30
|
+
function rawIdOf(input) {
|
|
31
|
+
if (input.id)
|
|
32
|
+
return input.id;
|
|
33
|
+
if (input.providerID && input.modelID)
|
|
34
|
+
return `${input.providerID}/${input.modelID}`;
|
|
35
|
+
return input.modelID ?? "";
|
|
36
|
+
}
|
|
37
|
+
function resolveFromSnapshot(entryId, method, catalog, snapshot) {
|
|
38
|
+
const key = catalog.keyByEntryId.get(entryId);
|
|
39
|
+
const price = key ? snapshot.prices[key] : undefined;
|
|
40
|
+
if (!key || !price) {
|
|
41
|
+
return { status: "unknown", canonicalId: entryId, method, needsFallback: true };
|
|
42
|
+
}
|
|
43
|
+
if (price.input === 0 && price.output === 0) {
|
|
44
|
+
return { status: "free", canonicalId: entryId, source: "snapshot", method };
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
status: "paid",
|
|
48
|
+
input: price.input,
|
|
49
|
+
output: price.output,
|
|
50
|
+
canonicalId: entryId,
|
|
51
|
+
source: "snapshot",
|
|
52
|
+
method,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Sync tier: config declarations + user aliases + the price snapshot. */
|
|
56
|
+
export function resolvePricingSync(input, config) {
|
|
57
|
+
const raw = rawIdOf(input);
|
|
58
|
+
const parsed = parseModelId(raw);
|
|
59
|
+
if (input.declaredCost === "subscription")
|
|
60
|
+
return { status: "subscription", canonicalId: parsed.model };
|
|
61
|
+
if (input.declaredCost === "free")
|
|
62
|
+
return { status: "free", canonicalId: parsed.model };
|
|
63
|
+
const explicit = input.explicitPrice;
|
|
64
|
+
if (explicit && explicit.input >= 0 && explicit.output >= 0) {
|
|
65
|
+
if (explicit.input === 0 && explicit.output === 0) {
|
|
66
|
+
return { status: "free", canonicalId: parsed.model, source: "config" };
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
status: "paid",
|
|
70
|
+
input: explicit.input,
|
|
71
|
+
output: explicit.output,
|
|
72
|
+
canonicalId: parsed.model,
|
|
73
|
+
source: "config",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (parsed.variant === "free")
|
|
77
|
+
return { status: "free", canonicalId: parsed.model };
|
|
78
|
+
const catalog = snapshotCatalog(config.snapshot);
|
|
79
|
+
for (const aliasEntry of config.aliases ?? []) {
|
|
80
|
+
const hit = (aliasEntry.aliases ?? []).some((alias) => normalizeModelName(alias) === parsed.model);
|
|
81
|
+
if (hit)
|
|
82
|
+
return resolveFromSnapshot(aliasEntry.canonical, "alias", catalog, config.snapshot);
|
|
83
|
+
}
|
|
84
|
+
const match = matchModel(raw, catalog.entries);
|
|
85
|
+
if (match.method !== "none") {
|
|
86
|
+
return resolveFromSnapshot(match.canonical, match.method, catalog, config.snapshot);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
status: "unknown",
|
|
90
|
+
canonicalId: match.canonical,
|
|
91
|
+
...(match.familyAmbiguous ? { familyAmbiguous: true } : {}),
|
|
92
|
+
needsFallback: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function classifyOpenRouter(model, match) {
|
|
96
|
+
const pricing = model.pricing;
|
|
97
|
+
if (model.isFreeVariant) {
|
|
98
|
+
return { status: "free", canonicalId: match.canonical, source: "openrouter", method: match.method };
|
|
99
|
+
}
|
|
100
|
+
const hasMediaPrice = (pricing.request ?? 0) > 0 || (pricing.image ?? 0) > 0 || (pricing.audio ?? 0) > 0;
|
|
101
|
+
if (pricing.input !== undefined && pricing.output !== undefined) {
|
|
102
|
+
if (pricing.input === 0 && pricing.output === 0) {
|
|
103
|
+
// Zero token prices alone do not prove a model is free: media models
|
|
104
|
+
// bill per request/image instead. Keep those unknown, never silent $0.
|
|
105
|
+
if (hasMediaPrice) {
|
|
106
|
+
return { status: "unknown", canonicalId: match.canonical, source: "openrouter", method: match.method };
|
|
107
|
+
}
|
|
108
|
+
return { status: "free", canonicalId: match.canonical, source: "openrouter", method: match.method };
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
status: "paid",
|
|
112
|
+
input: pricing.input,
|
|
113
|
+
output: pricing.output,
|
|
114
|
+
...(pricing.cacheRead !== undefined ? { cacheRead: pricing.cacheRead } : {}),
|
|
115
|
+
...(pricing.reasoning !== undefined ? { reasoning: pricing.reasoning } : {}),
|
|
116
|
+
canonicalId: match.canonical,
|
|
117
|
+
source: "openrouter",
|
|
118
|
+
method: match.method,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return { status: "unknown", canonicalId: match.canonical, source: "openrouter", method: match.method };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Full resolution: sync tier first, then the cached OpenRouter catalog when
|
|
125
|
+
* the price is still unknown. Never fetches when OpenRouter is disabled.
|
|
126
|
+
*/
|
|
127
|
+
export async function resolvePricing(input, config) {
|
|
128
|
+
const sync = resolvePricingSync(input, config);
|
|
129
|
+
if (sync.status !== "unknown" || !sync.needsFallback || !config.openRouter)
|
|
130
|
+
return sync;
|
|
131
|
+
const models = await config.openRouter.getModels(false);
|
|
132
|
+
const entries = toModelEntries(models);
|
|
133
|
+
const match = matchModel(rawIdOf(input), entries);
|
|
134
|
+
if (match.method === "none")
|
|
135
|
+
return sync;
|
|
136
|
+
const modelByEntryId = new Map();
|
|
137
|
+
for (const model of models) {
|
|
138
|
+
modelByEntryId.set(normalizeModelName(splitProviderId(model.id).rest), model);
|
|
139
|
+
}
|
|
140
|
+
const model = modelByEntryId.get(match.canonical);
|
|
141
|
+
if (!model)
|
|
142
|
+
return sync;
|
|
143
|
+
return classifyOpenRouter(model, { canonical: match.canonical, method: match.method });
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/pricing/resolver.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,uDAAuD;AACvD,EAAE;AACF,wDAAwD;AACxD,0DAA0D;AAC1D,4CAA4C;AAC5C,oEAAoE;AACpE,uEAAuE;AACvE,mDAAmD;AACnD,sEAAsE;AACtE,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAI5E,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,eAAe,GAGhB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,cAAc,EAAwB,MAAM,iBAAiB,CAAA;AAgDtE,SAAS,eAAe,CAAC,QAAuB;IAC9C,MAAM,OAAO,GAAiB,EAAE,CAAA;IAChC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/C,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QACxC,OAAO,CAAC,IAAI,CAAC;YACX,EAAE,EAAE,OAAO;YACX,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChE,CAAC,CAAA;QACF,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IAChC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA;AAClC,CAAC;AAED,SAAS,OAAO,CAAC,KAAoB;IACnC,IAAI,KAAK,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC,EAAE,CAAA;IAC7B,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,GAAG,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,EAAE,CAAA;IACpF,OAAO,KAAK,CAAC,OAAO,IAAI,EAAE,CAAA;AAC5B,CAAC;AAED,SAAS,mBAAmB,CAC1B,OAAe,EACf,MAAmB,EACnB,OAAwB,EACxB,QAAuB;IAEvB,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACpD,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,CAAA;IACjF,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAA;IAC7E,CAAC;IACD,OAAO;QACL,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,OAAO;QACpB,MAAM,EAAE,UAAU;QAClB,MAAM;KACP,CAAA;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,kBAAkB,CAAC,KAAoB,EAAE,MAAsB;IAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IAC1B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAEhC,IAAI,KAAK,CAAC,YAAY,KAAK,cAAc;QAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,CAAA;IACvG,IAAI,KAAK,CAAC,YAAY,KAAK,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,CAAA;IAEvF,MAAM,QAAQ,GAAG,KAAK,CAAC,aAAa,CAAA;IACpC,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5D,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;QACxE,CAAC;QACD,OAAO;YACL,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,WAAW,EAAE,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,QAAQ;SACjB,CAAA;IACH,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,CAAA;IAEnF,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAChD,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,CAAA;QAClG,IAAI,GAAG;YAAE,OAAO,mBAAmB,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC9F,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9C,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,mBAAmB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;IACrF,CAAC;IAED,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,KAAK,CAAC,SAAS;QAC5B,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,aAAa,EAAE,IAAI;KACpB,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAsB,EAAE,KAAiD;IACnG,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;IAC7B,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAA;IACrG,CAAC;IACD,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IACxG,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChE,IAAI,OAAO,CAAC,KAAK,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,qEAAqE;YACrE,uEAAuE;YACvE,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAA;YACxG,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAA;QACrG,CAAC;QACD,OAAO;YACL,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,WAAW,EAAE,KAAK,CAAC,SAAS;YAC5B,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAA;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAA;AACxG,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAoB,EAAE,MAAsB;IAC/E,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,IAAI,CAAA;IAEvF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACvD,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;IACtC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAA;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAExC,MAAM,cAAc,GAAG,IAAI,GAAG,EAA2B,CAAA;IACzD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,cAAc,CAAC,GAAG,CAAC,kBAAkB,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAA;IAC/E,CAAC;IACD,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACjD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,kBAAkB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;AACxF,CAAC"}
|
package/dist/prompts/load.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
const FALLBACK_LEAD = `You are orch-lead, an evidence-driven primary implementation agent.
|
|
3
3
|
Classify the task by intellectual work profile, dispatch the smallest useful specialist team, synthesize their evidence, implement the requested change, and verify it.
|
|
4
4
|
Use workers for independent evidence, not ceremonial duplication. Never invoke yourself or bypass user instructions, active skills, plans, TDD, or review workflows.
|
|
5
|
-
Escalate to orch-judge only for critical risk or unresolved disagreement. For implementation tasks, continue through editing and verification instead of stopping at a handoff.`;
|
|
5
|
+
Escalate to orch-judge only for critical risk or unresolved disagreement. For implementation tasks, continue through editing and verification instead of stopping at a handoff. Parallel editors require explicit non-overlapping ownership, one experimental git worktree per editor, git-derived diff validation, and a single integrator; retain worktrees on failure.`;
|
|
6
6
|
const FALLBACK_JUDGE = `You are orch-judge, a costly independent arbiter.
|
|
7
7
|
You receive conflicting worker findings. Inspect only the evidence needed to resolve the disagreement.
|
|
8
8
|
Do not delegate and do not edit. State which claims are supported, which are rejected, remaining uncertainty, and the safest recommendation.`;
|
package/dist/prompts/load.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/prompts/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE3C,MAAM,aAAa,GAAG;;;
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/prompts/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE3C,MAAM,aAAa,GAAG;;;0WAGoV,CAAA;AAE1W,MAAM,cAAc,GAAG;;6IAEsH,CAAA;AAE7I,KAAK,UAAU,UAAU,CAAC,YAAoB,EAAE,QAAgB;IAC9D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,iBAAiB,YAAY,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACrE,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAA;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtC,UAAU,CAAC,SAAS,EAAE,aAAa,CAAC;QACpC,UAAU,CAAC,UAAU,EAAE,cAAc,CAAC;KACvC,CAAC,CAAA;IACF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;AACxB,CAAC"}
|
|
@@ -5,7 +5,13 @@ export interface PlanNode {
|
|
|
5
5
|
description: string;
|
|
6
6
|
worker: string;
|
|
7
7
|
dependsOn: string[];
|
|
8
|
-
role: "specialist" | "reviewer" | "merger";
|
|
8
|
+
role: "specialist" | "reviewer" | "merger" | "editor" | "integrator";
|
|
9
|
+
ownership?: string[];
|
|
10
|
+
worktree?: {
|
|
11
|
+
branch: string;
|
|
12
|
+
path: string;
|
|
13
|
+
baseRevision: string;
|
|
14
|
+
};
|
|
9
15
|
}
|
|
10
16
|
export interface TaskPlan {
|
|
11
17
|
nodes: PlanNode[];
|
|
@@ -13,12 +19,19 @@ export interface TaskPlan {
|
|
|
13
19
|
levels: string[][];
|
|
14
20
|
maxParallel: number;
|
|
15
21
|
mergerNodeId?: string;
|
|
22
|
+
integratorNodeId?: string;
|
|
16
23
|
}
|
|
17
24
|
export interface PlanOptions {
|
|
18
25
|
secondaryWorkers?: string[];
|
|
19
26
|
maxNodes?: number;
|
|
20
27
|
dependencyAware?: boolean;
|
|
21
28
|
includeMerger?: boolean;
|
|
29
|
+
editorPartitions?: Array<{
|
|
30
|
+
id?: string;
|
|
31
|
+
description: string;
|
|
32
|
+
ownership: string[];
|
|
33
|
+
}>;
|
|
34
|
+
includeIntegrator?: boolean;
|
|
22
35
|
}
|
|
23
36
|
export declare function planTask(profile: ProfileName, secondaryProfiles?: ProfileName[], options?: PlanOptions): TaskPlan;
|
|
24
37
|
export declare function validatePlan(plan: TaskPlan): string[];
|
package/dist/routing/planner.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateOwnership } from "../orchestration/ownership.js";
|
|
1
2
|
const PROFILE_WORKERS = {
|
|
2
3
|
architecture: ["orch-repo", "orch-research", "orch-critic"],
|
|
3
4
|
debug: ["orch-repo", "orch-tests", "orch-critic"],
|
|
@@ -64,7 +65,25 @@ export function planTask(profile, secondaryProfiles = [], options = {}) {
|
|
|
64
65
|
nodes.push({ id: mergerNodeId, description: "Merge all completed specialist outputs into one evidence-backed handoff, preserving conflicts and provenance.", worker: "orch-merge", dependsOn: evidence, role: "merger" });
|
|
65
66
|
levels.push([mergerNodeId]);
|
|
66
67
|
}
|
|
67
|
-
|
|
68
|
+
let integratorNodeId;
|
|
69
|
+
const partitions = options.editorPartitions ?? [];
|
|
70
|
+
if (partitions.length) {
|
|
71
|
+
const editorDeps = mergerNodeId ? [mergerNodeId] : evidence;
|
|
72
|
+
const editorIds = [];
|
|
73
|
+
for (let i = 0; i < partitions.length; i++) {
|
|
74
|
+
const partition = partitions[i];
|
|
75
|
+
const id = partition.id ?? "editor-" + i;
|
|
76
|
+
nodes.push({ id, description: partition.description, worker: "orch-editor", dependsOn: editorDeps, role: "editor", ownership: partition.ownership });
|
|
77
|
+
editorIds.push(id);
|
|
78
|
+
}
|
|
79
|
+
levels.push(editorIds);
|
|
80
|
+
if (options.includeIntegrator ?? true) {
|
|
81
|
+
integratorNodeId = "integrator";
|
|
82
|
+
nodes.push({ id: integratorNodeId, description: "Integrate validated editor commits in deterministic order.", worker: "orch-integrator", dependsOn: editorIds, role: "integrator" });
|
|
83
|
+
levels.push([integratorNodeId]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { nodes, levels, maxParallel: levels.reduce((max, level) => Math.max(max, level.length), 0), ...(mergerNodeId ? { mergerNodeId } : {}), ...(integratorNodeId ? { integratorNodeId } : {}) };
|
|
68
87
|
}
|
|
69
88
|
export function validatePlan(plan) {
|
|
70
89
|
const byId = new Map();
|
|
@@ -72,8 +91,11 @@ export function validatePlan(plan) {
|
|
|
72
91
|
for (const node of plan.nodes) {
|
|
73
92
|
if (byId.has(node.id))
|
|
74
93
|
problems.push("duplicate node " + node.id);
|
|
94
|
+
if (node.role === "editor" && (!node.ownership || node.ownership.length === 0))
|
|
95
|
+
problems.push("editor node " + node.id + " has no ownership");
|
|
75
96
|
byId.set(node.id, node);
|
|
76
97
|
}
|
|
98
|
+
problems.push(...validateOwnership(plan.nodes.filter((node) => node.role === "editor").map((node) => ({ id: node.id, paths: node.ownership ?? [] }))));
|
|
77
99
|
const visiting = new Set(), visited = new Set();
|
|
78
100
|
const visit = (id) => {
|
|
79
101
|
if (visiting.has(id)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/routing/planner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/routing/planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import type { BudgetMode, ModelCandidateInput } from "../../config/schema.js";
|
|
|
2
2
|
import { resolveModel } from "../model-resolver.js";
|
|
3
3
|
import type { PriceSnapshot } from "./prices.js";
|
|
4
4
|
import type { TaskPlan } from "../planner.js";
|
|
5
|
+
import { type ModelAliasEntry, type OpenRouterSource } from "../../pricing/resolver.js";
|
|
5
6
|
export interface PriceResolution {
|
|
6
7
|
/** Price source used for the estimate (where a paid price was found). */
|
|
7
8
|
source: "snapshot" | "remote";
|
|
@@ -34,6 +35,10 @@ export interface CostEstimateInput {
|
|
|
34
35
|
workerCapabilityOf?: (worker: string) => Parameters<typeof resolveModel>[0]["capability"];
|
|
35
36
|
snapshot: PriceSnapshot;
|
|
36
37
|
tokens?: TokenEstimates;
|
|
38
|
+
/** User-defined model aliases (config pricing.aliases). */
|
|
39
|
+
aliases?: ModelAliasEntry[];
|
|
40
|
+
/** Optional OpenRouter fallback source (config pricing.openrouter). */
|
|
41
|
+
openRouter?: OpenRouterSource;
|
|
37
42
|
}
|
|
38
43
|
export interface CostBreakdown {
|
|
39
44
|
workers: number;
|
|
@@ -43,6 +48,14 @@ export interface CostBreakdown {
|
|
|
43
48
|
subtotal: number;
|
|
44
49
|
/** Conservative +20% buffer for retries / cache misses / reasoning tokens. */
|
|
45
50
|
total: number;
|
|
51
|
+
/** Calls whose price could not be determined; excluded from all totals. */
|
|
52
|
+
unknownCalls: number;
|
|
53
|
+
/** Calls priced $0 because the model is free (tokens still counted). */
|
|
54
|
+
freeCalls: number;
|
|
55
|
+
/** Calls priced $0 because the model runs inside a subscription. */
|
|
56
|
+
subscriptionCalls: number;
|
|
57
|
+
/** Calls priced with a known USD rate. */
|
|
58
|
+
paidCalls: number;
|
|
46
59
|
}
|
|
47
60
|
export interface CostEstimate {
|
|
48
61
|
budget: BudgetMode;
|
|
@@ -52,7 +65,7 @@ export interface CostEstimate {
|
|
|
52
65
|
/** Human-readable summary line for pre-run confirmation. */
|
|
53
66
|
summary: string;
|
|
54
67
|
}
|
|
55
|
-
export declare function estimateCost(input: CostEstimateInput): CostEstimate
|
|
68
|
+
export declare function estimateCost(input: CostEstimateInput): Promise<CostEstimate>;
|
|
56
69
|
/** Compare an estimate against a warning threshold; returns a pre-run message. */
|
|
57
70
|
export declare function formatEstimateWarning(estimate: CostEstimate, thresholdUSD?: number): string | undefined;
|
|
58
71
|
/** Total combined price for a model id or 0 when unknown/free. */
|