@intelligo-dev/executions 1.0.0-beta.2 → 1.0.0-beta.5
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 +36 -0
- package/dist/db/schema.js +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +2 -2
- package/dist/pricing.d.ts +98 -113
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +114 -56
- package/dist/pricing.js.map +1 -1
- package/dist/queries.js +1 -1
- package/package.json +16 -6
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @intelligo-dev/executions
|
|
2
|
+
|
|
3
|
+
The execution lifecycle — admission, running, settlement — and the model cost registry.
|
|
4
|
+
|
|
5
|
+
Part of [Intelligo](https://github.com/intelligo-mn/framework), an application
|
|
6
|
+
framework and operational platform for vertical AI SaaS products. This package
|
|
7
|
+
is published from that repository and is not meant to be used on its own.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @intelligo-dev/executions
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## The boundary
|
|
16
|
+
|
|
17
|
+
Intelligo records what an AI execution cost and whether it was allowed. It does
|
|
18
|
+
not wrap the AI framework: prompts, tools and orchestration stay native
|
|
19
|
+
(ADR-0003).
|
|
20
|
+
|
|
21
|
+
`createExecutions(ports)` takes four optional ports — `checkEntitlement`,
|
|
22
|
+
`settleUsage`, `findSettlement`, `releaseHold` — so this package never imports
|
|
23
|
+
billing. The lifecycle claims each transition with a compare-and-swap before
|
|
24
|
+
money is spent, and `reconcile` uses `findSettlement` to tell an abandoned run
|
|
25
|
+
from a settled one.
|
|
26
|
+
|
|
27
|
+
## Model pricing
|
|
28
|
+
|
|
29
|
+
`@intelligo-dev/executions/pricing` is a deliberate zero-import leaf that
|
|
30
|
+
client bundles can reach. Model ids are registry keys: an unregistered id has
|
|
31
|
+
no price, and guessing one is how a model runs on the cheapest provider and
|
|
32
|
+
bills at the most expensive rate.
|
|
33
|
+
|
|
34
|
+
## Licence
|
|
35
|
+
|
|
36
|
+
Apache-2.0
|
package/dist/db/schema.js
CHANGED
|
@@ -32,7 +32,7 @@ export const executions = pgTable("executions", {
|
|
|
32
32
|
}),
|
|
33
33
|
/**
|
|
34
34
|
* What the caller asked for, in the product's own vocabulary:
|
|
35
|
-
* "
|
|
35
|
+
* "support.reply", "chat.message". Opaque to Intelligo —
|
|
36
36
|
* used for entitlement decisions, grouping, and admin filtering.
|
|
37
37
|
*/
|
|
38
38
|
capability: text("capability").notNull(),
|
package/dist/index.d.ts
CHANGED
|
@@ -12,18 +12,18 @@
|
|
|
12
12
|
* settleUsage: billingSettlementPort,
|
|
13
13
|
* });
|
|
14
14
|
*/
|
|
15
|
-
export { createExecutions } from "./lifecycle";
|
|
16
|
-
export type { Executions, ExecutionStatus, ExecutionRun, ReconcileResult, BeginExecutionInput, CompleteExecutionInput, } from "./lifecycle";
|
|
17
|
-
export type { ExecutionPorts, EntitlementDecision, EntitlementRequest, UsageSettlement, SettlementResult, SettlementQuery, } from "./ports";
|
|
18
|
-
export { listExecutions, getExecutionByRequestId, summarizeExecutions, findStaleExecutions, summarizeExecutionsByDay, } from "./queries";
|
|
19
|
-
export type { ListExecutionsOptions } from "./queries";
|
|
20
|
-
export { executions } from "./db/schema";
|
|
21
|
-
export type { Execution, InsertExecution } from "./db/schema";
|
|
15
|
+
export { createExecutions } from "./lifecycle.js";
|
|
16
|
+
export type { Executions, ExecutionStatus, ExecutionRun, ReconcileResult, BeginExecutionInput, CompleteExecutionInput, } from "./lifecycle.js";
|
|
17
|
+
export type { ExecutionPorts, EntitlementDecision, EntitlementRequest, UsageSettlement, SettlementResult, SettlementQuery, } from "./ports.js";
|
|
18
|
+
export { listExecutions, getExecutionByRequestId, summarizeExecutions, findStaleExecutions, summarizeExecutionsByDay, } from "./queries.js";
|
|
19
|
+
export type { ListExecutionsOptions } from "./queries.js";
|
|
20
|
+
export { executions } from "./db/schema.js";
|
|
21
|
+
export type { Execution, InsertExecution } from "./db/schema.js";
|
|
22
22
|
/**
|
|
23
23
|
* Model registry and cost accounting. Also reachable as
|
|
24
24
|
* `@intelligo-dev/executions/pricing`, which is the import to use from
|
|
25
25
|
* anything that reaches a browser — this barrel pulls in the database.
|
|
26
26
|
*/
|
|
27
|
-
export {
|
|
28
|
-
export type { ModelId, ChargedAmount } from "./pricing";
|
|
27
|
+
export { DEFAULT_MODELS, UnknownModelError, registerModel, registerModels, getModelPricing, isModelRegistered, listModels, registeredModelIds, clearModels, DEFAULT_BILLING_MARGIN, DEFAULT_USD_TO_MNT_RATE, calculateCost, calculateChargedMnt, estimateWorstCaseChargedMnt, } from "./pricing.js";
|
|
28
|
+
export type { ModelId, ModelPricing, ModelCapabilities, ChargedAmount, } from "./pricing.js";
|
|
29
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;GAIG;AACH,OAAO,EACL,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;GAIG;AACH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,OAAO,EACP,YAAY,EACZ,iBAAiB,EACjB,aAAa,GACd,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
* settleUsage: billingSettlementPort,
|
|
13
13
|
* });
|
|
14
14
|
*/
|
|
15
|
-
export { createExecutions } from "./lifecycle";
|
|
16
|
-
export { listExecutions, getExecutionByRequestId, summarizeExecutions, findStaleExecutions, summarizeExecutionsByDay, } from "./queries";
|
|
17
|
-
export { executions } from "./db/schema";
|
|
15
|
+
export { createExecutions } from "./lifecycle.js";
|
|
16
|
+
export { listExecutions, getExecutionByRequestId, summarizeExecutions, findStaleExecutions, summarizeExecutionsByDay, } from "./queries.js";
|
|
17
|
+
export { executions } from "./db/schema.js";
|
|
18
18
|
/**
|
|
19
19
|
* Model registry and cost accounting. Also reachable as
|
|
20
20
|
* `@intelligo-dev/executions/pricing`, which is the import to use from
|
|
21
21
|
* anything that reaches a browser — this barrel pulls in the database.
|
|
22
22
|
*/
|
|
23
|
-
export {
|
|
23
|
+
export { DEFAULT_MODELS, UnknownModelError, registerModel, registerModels, getModelPricing, isModelRegistered, listModels, registeredModelIds, clearModels, DEFAULT_BILLING_MARGIN, DEFAULT_USD_TO_MNT_RATE, calculateCost, calculateChargedMnt, estimateWorstCaseChargedMnt, } from "./pricing.js";
|
|
24
24
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAmB/C,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;GAIG;AACH,OAAO,EACL,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAmB/C,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;GAIG;AACH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,WAAW,CAAC"}
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* const run = await executions.begin({ workspaceId, userId, capability });
|
|
5
5
|
* if (!run.allowed) return refuse(run.reason);
|
|
6
6
|
* try {
|
|
7
|
-
* const result = await
|
|
7
|
+
* const result = await supportAgent.generate(messages); // native
|
|
8
8
|
* await run.complete({ usage: result.usage, model: result.model });
|
|
9
9
|
* return result;
|
|
10
10
|
* } catch (error) {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* abort, error) and must be able to fire whichever arrives first
|
|
23
23
|
* without racing.
|
|
24
24
|
*/
|
|
25
|
-
import type { ExecutionPorts } from "./ports";
|
|
25
|
+
import type { ExecutionPorts } from "./ports.js";
|
|
26
26
|
/**
|
|
27
27
|
* Row lifecycle. `settling` is non-terminal and deliberate: it marks
|
|
28
28
|
* the window where usage is being charged, so a second complete() or a
|
|
@@ -34,7 +34,7 @@ export type ExecutionStatus = "running" | "settling" | "succeeded" | "failed" |
|
|
|
34
34
|
export type BeginExecutionInput = {
|
|
35
35
|
workspaceId: string;
|
|
36
36
|
userId?: string | null;
|
|
37
|
-
/** Product-defined verb, e.g. "
|
|
37
|
+
/** Product-defined verb, e.g. "support.reply". */
|
|
38
38
|
capability: string;
|
|
39
39
|
/** Supply to reuse an existing correlation id; generated otherwise. */
|
|
40
40
|
requestId?: string;
|
package/dist/lifecycle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI9C;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,UAAU,GACV,WAAW,GACX,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI9C;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,UAAU,GACV,WAAW,GACX,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,CAAC,EAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD,CAAC;AAMF,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,cAAmB;mBAC7B,mBAAmB,KAAG,OAAO,CAAC,YAAY,CAAC;6BAgQxD,MAAM,YACV;QAAE,qBAAqB,CAAC,EAAE,MAAM,CAAA;KAAE,KAC1C,OAAO,CAAC,eAAe,CAAC;EAoI5B;AAED,MAAM,MAAM,eAAe,GACvB;IACE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACH,+DAA+D;GAC7D;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AAC9C,qDAAqD;GACnD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AAC5C,8DAA8D;GAC5D;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAE5B,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
|
package/dist/lifecycle.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* const run = await executions.begin({ workspaceId, userId, capability });
|
|
5
5
|
* if (!run.allowed) return refuse(run.reason);
|
|
6
6
|
* try {
|
|
7
|
-
* const result = await
|
|
7
|
+
* const result = await supportAgent.generate(messages); // native
|
|
8
8
|
* await run.complete({ usage: result.usage, model: result.model });
|
|
9
9
|
* return result;
|
|
10
10
|
* } catch (error) {
|
|
@@ -26,7 +26,7 @@ import { db } from "@intelligo-dev/core/db";
|
|
|
26
26
|
import { createLogger } from "@intelligo-dev/core/logger";
|
|
27
27
|
import { recordAuditEvent } from "@intelligo-dev/audit";
|
|
28
28
|
import { and, eq } from "drizzle-orm";
|
|
29
|
-
import { executions } from "./db/schema";
|
|
29
|
+
import { executions } from "./db/schema.js";
|
|
30
30
|
const log = createLogger("Executions");
|
|
31
31
|
function errorMessage(error) {
|
|
32
32
|
return error instanceof Error ? error.message : String(error);
|
package/dist/pricing.d.ts
CHANGED
|
@@ -6,107 +6,96 @@
|
|
|
6
6
|
* boundary records actor, workspace, capability, usage and cost
|
|
7
7
|
* (ADR-0003), and the price of a token is the last of those.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* Still a leaf: no database, no provider SDK. Its one import is
|
|
10
|
+
* `@intelligo-dev/core/registry`, which is itself dependency-free, so
|
|
11
|
+
* `@intelligo-dev/executions/pricing` remains something a client bundle
|
|
12
|
+
* can read a display name or a price from without pulling in Drizzle.
|
|
13
|
+
*
|
|
14
|
+
* ## The registry is open
|
|
15
|
+
*
|
|
16
|
+
* It used to be a closed `as const` object of six models, with
|
|
17
|
+
* `ModelId = keyof typeof`. A product that wanted Bedrock, Groq,
|
|
18
|
+
* Mistral, a self-hosted model — or simply a newer Claude — could not
|
|
19
|
+
* add one without a pull request to the framework, and an architecture
|
|
20
|
+
* test enforced that. For a framework meant to underpin ten products
|
|
21
|
+
* from one cost basis, the list cannot be the framework's to close.
|
|
22
|
+
*
|
|
23
|
+
* `registerModels(DEFAULT_MODELS)` from the composition root gets the
|
|
24
|
+
* old behaviour back in one line. Nothing self-registers: an import
|
|
25
|
+
* that populates a registry is the side effect ADR-0005 bans, and it
|
|
26
|
+
* is also how a deployment ends up billing against a catalogue it
|
|
27
|
+
* never chose.
|
|
28
|
+
*
|
|
29
|
+
* ## An unregistered id throws
|
|
30
|
+
*
|
|
31
|
+
* The old `calculateCost` warned and priced an unknown id at the
|
|
32
|
+
* worst-case Claude rate, while the model resolver warned and fell
|
|
33
|
+
* back to Gemini Flash. So the call ran on the cheapest model and
|
|
34
|
+
* billed for the most expensive one, and the only symptom was a
|
|
35
|
+
* console warning on a server nobody reads. Whatever that is, it is
|
|
36
|
+
* not pricing. An id with no price now throws, at the point where the
|
|
37
|
+
* price is needed, naming the id and what to do about it.
|
|
15
38
|
*/
|
|
39
|
+
export type ModelCapabilities = {
|
|
40
|
+
thinking: boolean;
|
|
41
|
+
toolCall: boolean;
|
|
42
|
+
vision: boolean;
|
|
43
|
+
webSearch: boolean;
|
|
44
|
+
codeExec: boolean;
|
|
45
|
+
};
|
|
46
|
+
export type ModelPricing = {
|
|
47
|
+
/** Provider-prefixed id, e.g. `google/gemini-2.5-flash`. */
|
|
48
|
+
id: string;
|
|
49
|
+
provider: string;
|
|
50
|
+
/** The id the provider's own SDK expects, which is often dated. */
|
|
51
|
+
model: string;
|
|
52
|
+
displayName: string;
|
|
53
|
+
/** USD per million input tokens, as the provider quotes it. */
|
|
54
|
+
costPerMInputTokens: number;
|
|
55
|
+
/** USD per million output tokens. */
|
|
56
|
+
costPerMOutputTokens: number;
|
|
57
|
+
/**
|
|
58
|
+
* The ceiling on streamed output used for worst-case pre-request
|
|
59
|
+
* estimation. Was a separate `MODEL_OUTPUT_BUDGET` map, which is one
|
|
60
|
+
* more list that could disagree with this one.
|
|
61
|
+
*/
|
|
62
|
+
maxOutputTokens: number;
|
|
63
|
+
capabilities: ModelCapabilities;
|
|
64
|
+
};
|
|
16
65
|
/**
|
|
17
|
-
*
|
|
66
|
+
* A model id is now any string, because the registry is open.
|
|
18
67
|
*
|
|
19
|
-
*
|
|
68
|
+
* Kept as a named type for the call sites that read better with it.
|
|
69
|
+
* `Record<ModelId, T>` no longer means anything — which is a useful
|
|
70
|
+
* compile error in the places that used to enumerate the catalogue.
|
|
20
71
|
*/
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
readonly "google/gemini-2.5-pro": {
|
|
37
|
-
readonly provider: "google";
|
|
38
|
-
readonly model: "gemini-2.5-pro";
|
|
39
|
-
readonly displayName: "Gemini 2.5 Pro";
|
|
40
|
-
readonly costPerMInputTokens: 1.25;
|
|
41
|
-
readonly costPerMOutputTokens: 10;
|
|
42
|
-
readonly capabilities: {
|
|
43
|
-
readonly thinking: true;
|
|
44
|
-
readonly toolCall: true;
|
|
45
|
-
readonly vision: true;
|
|
46
|
-
readonly webSearch: true;
|
|
47
|
-
readonly codeExec: true;
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
readonly "openai/gpt-5-mini": {
|
|
51
|
-
readonly provider: "openai";
|
|
52
|
-
readonly model: "gpt-5-mini";
|
|
53
|
-
readonly displayName: "GPT-5 Mini";
|
|
54
|
-
readonly costPerMInputTokens: 0.25;
|
|
55
|
-
readonly costPerMOutputTokens: 2;
|
|
56
|
-
readonly capabilities: {
|
|
57
|
-
readonly thinking: true;
|
|
58
|
-
readonly toolCall: true;
|
|
59
|
-
readonly vision: true;
|
|
60
|
-
readonly webSearch: false;
|
|
61
|
-
readonly codeExec: false;
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
readonly "openai/gpt-5.4-mini": {
|
|
65
|
-
readonly provider: "openai";
|
|
66
|
-
readonly model: "gpt-5.4-mini";
|
|
67
|
-
readonly displayName: "GPT-5.4 Mini";
|
|
68
|
-
readonly costPerMInputTokens: 0.75;
|
|
69
|
-
readonly costPerMOutputTokens: 4.5;
|
|
70
|
-
readonly capabilities: {
|
|
71
|
-
readonly thinking: true;
|
|
72
|
-
readonly toolCall: true;
|
|
73
|
-
readonly vision: true;
|
|
74
|
-
readonly webSearch: true;
|
|
75
|
-
readonly codeExec: true;
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
|
-
readonly "openai/o4-mini": {
|
|
79
|
-
readonly provider: "openai";
|
|
80
|
-
readonly model: "o4-mini";
|
|
81
|
-
readonly displayName: "o4-mini";
|
|
82
|
-
readonly costPerMInputTokens: 1.1;
|
|
83
|
-
readonly costPerMOutputTokens: 4.4;
|
|
84
|
-
readonly capabilities: {
|
|
85
|
-
readonly thinking: true;
|
|
86
|
-
readonly toolCall: true;
|
|
87
|
-
readonly vision: true;
|
|
88
|
-
readonly webSearch: true;
|
|
89
|
-
readonly codeExec: true;
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
readonly "anthropic/claude-sonnet-4-6": {
|
|
93
|
-
readonly provider: "anthropic";
|
|
94
|
-
readonly model: "claude-sonnet-4-6-20260214";
|
|
95
|
-
readonly displayName: "Claude Sonnet 4.6";
|
|
96
|
-
readonly costPerMInputTokens: 3;
|
|
97
|
-
readonly costPerMOutputTokens: 15;
|
|
98
|
-
readonly capabilities: {
|
|
99
|
-
readonly thinking: true;
|
|
100
|
-
readonly toolCall: true;
|
|
101
|
-
readonly vision: true;
|
|
102
|
-
readonly webSearch: true;
|
|
103
|
-
readonly codeExec: true;
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
export type ModelId = keyof typeof MODEL_CONFIGS;
|
|
72
|
+
export type ModelId = string;
|
|
73
|
+
export declare class UnknownModelError extends Error {
|
|
74
|
+
readonly code = "unknown_model";
|
|
75
|
+
readonly modelId: string;
|
|
76
|
+
constructor(modelId: string, registered: readonly string[]);
|
|
77
|
+
}
|
|
78
|
+
/** Register (or replace) one model's price and capabilities. */
|
|
79
|
+
export declare function registerModel(pricing: ModelPricing): void;
|
|
80
|
+
export declare function registerModels(pricings: readonly ModelPricing[]): void;
|
|
81
|
+
export declare function getModelPricing(modelId: string): ModelPricing | undefined;
|
|
82
|
+
export declare function isModelRegistered(modelId: string): boolean;
|
|
83
|
+
export declare function listModels(): readonly ModelPricing[];
|
|
84
|
+
export declare function registeredModelIds(): readonly string[];
|
|
85
|
+
/** For tests composing a fresh root. */
|
|
86
|
+
export declare function clearModels(): void;
|
|
108
87
|
/**
|
|
109
|
-
*
|
|
88
|
+
* The catalogue the framework ships, as data.
|
|
89
|
+
*
|
|
90
|
+
* Prices are the providers' published USD rates and go stale; a
|
|
91
|
+
* deployment that cares about the third decimal should register its own
|
|
92
|
+
* contracted rates over these.
|
|
93
|
+
*/
|
|
94
|
+
export declare const DEFAULT_MODELS: readonly ModelPricing[];
|
|
95
|
+
/**
|
|
96
|
+
* Raw provider cost in USD.
|
|
97
|
+
*
|
|
98
|
+
* @throws {UnknownModelError} when the id has no registered price.
|
|
110
99
|
*/
|
|
111
100
|
export declare function calculateCost(modelId: string, inputTokens: number, outputTokens: number): number;
|
|
112
101
|
/**
|
|
@@ -117,11 +106,9 @@ export declare function calculateCost(modelId: string, inputTokens: number, outp
|
|
|
117
106
|
*
|
|
118
107
|
* INVARIANT — 65% gross margin floor (founder contract):
|
|
119
108
|
* gross_margin = 1 − 1/multiplier
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* and unexpected provider price hikes. The Vitest assertion in
|
|
124
|
-
* models.test.ts pins this — drop below 2.857 at your own risk.
|
|
109
|
+
* Keeping gross_margin ≥ 0.65 means multiplier ≥ 1/0.35 ≈ 2.857. The
|
|
110
|
+
* current value of 4 yields 75%, leaving buffer above the floor for
|
|
111
|
+
* FX moves and provider price rises. `pricing.test.ts` pins it.
|
|
125
112
|
*/
|
|
126
113
|
export declare const DEFAULT_BILLING_MARGIN = 4;
|
|
127
114
|
/**
|
|
@@ -129,31 +116,29 @@ export declare const DEFAULT_BILLING_MARGIN = 4;
|
|
|
129
116
|
* billing_settings.usd_to_mnt_rate and is read per request.
|
|
130
117
|
*/
|
|
131
118
|
export declare const DEFAULT_USD_TO_MNT_RATE = 3450;
|
|
132
|
-
/**
|
|
133
|
-
* Per-model maximum output budget used for worst-case pre-request cost
|
|
134
|
-
* estimation in checkQuota. Numbers are conservative — cap on streamed
|
|
135
|
-
* output tokens we'd actually let a single chat turn produce.
|
|
136
|
-
*/
|
|
137
|
-
export declare const MODEL_OUTPUT_BUDGET: Record<ModelId, number>;
|
|
138
119
|
export type ChargedAmount = {
|
|
139
120
|
rawCostUsd: number;
|
|
140
121
|
chargedMnt: number;
|
|
141
122
|
};
|
|
142
123
|
/**
|
|
143
|
-
* Convert raw model cost to
|
|
124
|
+
* Convert raw model cost to the user-facing charged amount.
|
|
144
125
|
*
|
|
145
126
|
* chargedMnt = ceil( rawCostUsd × margin × fxRate )
|
|
146
127
|
*
|
|
147
128
|
* The rounding is upward so micro-fractions never let a free request
|
|
148
|
-
* slip through; over-billing per request is at most
|
|
129
|
+
* slip through; over-billing per request is at most one unit.
|
|
130
|
+
*
|
|
131
|
+
* @throws {UnknownModelError} when the id has no registered price.
|
|
149
132
|
*/
|
|
150
133
|
export declare function calculateChargedMnt(modelId: string, inputTokens: number, outputTokens: number, fxRate?: number, margin?: number): ChargedAmount;
|
|
151
134
|
/**
|
|
152
|
-
* Worst-case
|
|
135
|
+
* Worst-case cost estimate for a single chat turn against a given
|
|
153
136
|
* model. Used by checkQuota to refuse requests whose ceiling cost would
|
|
154
|
-
* exceed remaining balance, before
|
|
155
|
-
*
|
|
156
|
-
*
|
|
137
|
+
* exceed the remaining balance, before provider tokens are burnt. Uses
|
|
138
|
+
* the model's own `maxOutputTokens` and a generous 16K input budget to
|
|
139
|
+
* cover system prompt plus conversation history.
|
|
140
|
+
*
|
|
141
|
+
* @throws {UnknownModelError} when the id has no registered price.
|
|
157
142
|
*/
|
|
158
143
|
export declare function estimateWorstCaseChargedMnt(modelId: string, fxRate?: number, margin?: number): number;
|
|
159
144
|
//# sourceMappingURL=pricing.d.ts.map
|
package/dist/pricing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE;CAS3D;AAID,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEzD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI,CAEtE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEzE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,UAAU,IAAI,SAAS,YAAY,EAAE,CAEpD;AAED,wBAAgB,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAEtD;AAED,wCAAwC;AACxC,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAiGjD,CAAC;AASF;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAMR;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,MAAM,GAAE,MAAgC,EACxC,MAAM,GAAE,MAA+B,GACtC,aAAa,CAIf;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAgC,EACxC,MAAM,GAAE,MAA+B,GACtC,MAAM,CAKR"}
|
package/dist/pricing.js
CHANGED
|
@@ -6,26 +6,88 @@
|
|
|
6
6
|
* boundary records actor, workspace, capability, usage and cost
|
|
7
7
|
* (ADR-0003), and the price of a token is the last of those.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* Still a leaf: no database, no provider SDK. Its one import is
|
|
10
|
+
* `@intelligo-dev/core/registry`, which is itself dependency-free, so
|
|
11
|
+
* `@intelligo-dev/executions/pricing` remains something a client bundle
|
|
12
|
+
* can read a display name or a price from without pulling in Drizzle.
|
|
13
|
+
*
|
|
14
|
+
* ## The registry is open
|
|
15
|
+
*
|
|
16
|
+
* It used to be a closed `as const` object of six models, with
|
|
17
|
+
* `ModelId = keyof typeof`. A product that wanted Bedrock, Groq,
|
|
18
|
+
* Mistral, a self-hosted model — or simply a newer Claude — could not
|
|
19
|
+
* add one without a pull request to the framework, and an architecture
|
|
20
|
+
* test enforced that. For a framework meant to underpin ten products
|
|
21
|
+
* from one cost basis, the list cannot be the framework's to close.
|
|
22
|
+
*
|
|
23
|
+
* `registerModels(DEFAULT_MODELS)` from the composition root gets the
|
|
24
|
+
* old behaviour back in one line. Nothing self-registers: an import
|
|
25
|
+
* that populates a registry is the side effect ADR-0005 bans, and it
|
|
26
|
+
* is also how a deployment ends up billing against a catalogue it
|
|
27
|
+
* never chose.
|
|
28
|
+
*
|
|
29
|
+
* ## An unregistered id throws
|
|
30
|
+
*
|
|
31
|
+
* The old `calculateCost` warned and priced an unknown id at the
|
|
32
|
+
* worst-case Claude rate, while the model resolver warned and fell
|
|
33
|
+
* back to Gemini Flash. So the call ran on the cheapest model and
|
|
34
|
+
* billed for the most expensive one, and the only symptom was a
|
|
35
|
+
* console warning on a server nobody reads. Whatever that is, it is
|
|
36
|
+
* not pricing. An id with no price now throws, at the point where the
|
|
37
|
+
* price is needed, naming the id and what to do about it.
|
|
15
38
|
*/
|
|
39
|
+
import { createRegistry } from "@intelligo-dev/core/registry";
|
|
40
|
+
export class UnknownModelError extends Error {
|
|
41
|
+
constructor(modelId, registered) {
|
|
42
|
+
super(`No price registered for model "${modelId}". ` +
|
|
43
|
+
`Registered: ${registered.length > 0 ? registered.join(", ") : "none"}. ` +
|
|
44
|
+
`Call registerModels(DEFAULT_MODELS) — or your own catalogue — from the composition root.`);
|
|
45
|
+
this.code = "unknown_model";
|
|
46
|
+
this.name = "UnknownModelError";
|
|
47
|
+
this.modelId = modelId;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const models = createRegistry("executions/model-pricing");
|
|
51
|
+
/** Register (or replace) one model's price and capabilities. */
|
|
52
|
+
export function registerModel(pricing) {
|
|
53
|
+
models.set(pricing.id, pricing);
|
|
54
|
+
}
|
|
55
|
+
export function registerModels(pricings) {
|
|
56
|
+
for (const pricing of pricings)
|
|
57
|
+
registerModel(pricing);
|
|
58
|
+
}
|
|
59
|
+
export function getModelPricing(modelId) {
|
|
60
|
+
return models.get(modelId);
|
|
61
|
+
}
|
|
62
|
+
export function isModelRegistered(modelId) {
|
|
63
|
+
return models.has(modelId);
|
|
64
|
+
}
|
|
65
|
+
export function listModels() {
|
|
66
|
+
return [...models.values()];
|
|
67
|
+
}
|
|
68
|
+
export function registeredModelIds() {
|
|
69
|
+
return [...models.keys()];
|
|
70
|
+
}
|
|
71
|
+
/** For tests composing a fresh root. */
|
|
72
|
+
export function clearModels() {
|
|
73
|
+
models.clear();
|
|
74
|
+
}
|
|
16
75
|
/**
|
|
17
|
-
*
|
|
76
|
+
* The catalogue the framework ships, as data.
|
|
18
77
|
*
|
|
19
|
-
*
|
|
78
|
+
* Prices are the providers' published USD rates and go stale; a
|
|
79
|
+
* deployment that cares about the third decimal should register its own
|
|
80
|
+
* contracted rates over these.
|
|
20
81
|
*/
|
|
21
|
-
export const
|
|
22
|
-
|
|
23
|
-
|
|
82
|
+
export const DEFAULT_MODELS = [
|
|
83
|
+
{
|
|
84
|
+
id: "google/gemini-2.5-flash",
|
|
24
85
|
provider: "google",
|
|
25
86
|
model: "gemini-2.5-flash",
|
|
26
87
|
displayName: "Gemini 2.5 Flash",
|
|
27
88
|
costPerMInputTokens: 0.3,
|
|
28
89
|
costPerMOutputTokens: 2.5,
|
|
90
|
+
maxOutputTokens: 8000,
|
|
29
91
|
capabilities: {
|
|
30
92
|
thinking: true,
|
|
31
93
|
toolCall: true,
|
|
@@ -34,12 +96,14 @@ export const MODEL_CONFIGS = {
|
|
|
34
96
|
codeExec: true,
|
|
35
97
|
},
|
|
36
98
|
},
|
|
37
|
-
|
|
99
|
+
{
|
|
100
|
+
id: "google/gemini-2.5-pro",
|
|
38
101
|
provider: "google",
|
|
39
102
|
model: "gemini-2.5-pro",
|
|
40
103
|
displayName: "Gemini 2.5 Pro",
|
|
41
104
|
costPerMInputTokens: 1.25,
|
|
42
105
|
costPerMOutputTokens: 10,
|
|
106
|
+
maxOutputTokens: 8000,
|
|
43
107
|
capabilities: {
|
|
44
108
|
thinking: true,
|
|
45
109
|
toolCall: true,
|
|
@@ -48,13 +112,14 @@ export const MODEL_CONFIGS = {
|
|
|
48
112
|
codeExec: true,
|
|
49
113
|
},
|
|
50
114
|
},
|
|
51
|
-
|
|
52
|
-
|
|
115
|
+
{
|
|
116
|
+
id: "openai/gpt-5-mini",
|
|
53
117
|
provider: "openai",
|
|
54
118
|
model: "gpt-5-mini",
|
|
55
119
|
displayName: "GPT-5 Mini",
|
|
56
120
|
costPerMInputTokens: 0.25,
|
|
57
121
|
costPerMOutputTokens: 2.0,
|
|
122
|
+
maxOutputTokens: 8000,
|
|
58
123
|
capabilities: {
|
|
59
124
|
thinking: true,
|
|
60
125
|
toolCall: true,
|
|
@@ -63,12 +128,14 @@ export const MODEL_CONFIGS = {
|
|
|
63
128
|
codeExec: false,
|
|
64
129
|
},
|
|
65
130
|
},
|
|
66
|
-
|
|
131
|
+
{
|
|
132
|
+
id: "openai/gpt-5.4-mini",
|
|
67
133
|
provider: "openai",
|
|
68
134
|
model: "gpt-5.4-mini",
|
|
69
135
|
displayName: "GPT-5.4 Mini",
|
|
70
136
|
costPerMInputTokens: 0.75,
|
|
71
137
|
costPerMOutputTokens: 4.5,
|
|
138
|
+
maxOutputTokens: 8000,
|
|
72
139
|
capabilities: {
|
|
73
140
|
thinking: true,
|
|
74
141
|
toolCall: true,
|
|
@@ -77,12 +144,14 @@ export const MODEL_CONFIGS = {
|
|
|
77
144
|
codeExec: true,
|
|
78
145
|
},
|
|
79
146
|
},
|
|
80
|
-
|
|
147
|
+
{
|
|
148
|
+
id: "openai/o4-mini",
|
|
81
149
|
provider: "openai",
|
|
82
150
|
model: "o4-mini",
|
|
83
151
|
displayName: "o4-mini",
|
|
84
152
|
costPerMInputTokens: 1.1,
|
|
85
153
|
costPerMOutputTokens: 4.4,
|
|
154
|
+
maxOutputTokens: 8000,
|
|
86
155
|
capabilities: {
|
|
87
156
|
thinking: true,
|
|
88
157
|
toolCall: true,
|
|
@@ -91,13 +160,14 @@ export const MODEL_CONFIGS = {
|
|
|
91
160
|
codeExec: true,
|
|
92
161
|
},
|
|
93
162
|
},
|
|
94
|
-
|
|
95
|
-
|
|
163
|
+
{
|
|
164
|
+
id: "anthropic/claude-sonnet-4-6",
|
|
96
165
|
provider: "anthropic",
|
|
97
166
|
model: "claude-sonnet-4-6-20260214",
|
|
98
167
|
displayName: "Claude Sonnet 4.6",
|
|
99
168
|
costPerMInputTokens: 3.0,
|
|
100
169
|
costPerMOutputTokens: 15.0,
|
|
170
|
+
maxOutputTokens: 8000,
|
|
101
171
|
capabilities: {
|
|
102
172
|
thinking: true,
|
|
103
173
|
toolCall: true,
|
|
@@ -106,22 +176,21 @@ export const MODEL_CONFIGS = {
|
|
|
106
176
|
codeExec: true,
|
|
107
177
|
},
|
|
108
178
|
},
|
|
109
|
-
|
|
179
|
+
];
|
|
180
|
+
/** The price of a model, or a loud failure naming the id. */
|
|
181
|
+
function requireModel(modelId) {
|
|
182
|
+
const pricing = models.get(modelId);
|
|
183
|
+
if (!pricing)
|
|
184
|
+
throw new UnknownModelError(modelId, registeredModelIds());
|
|
185
|
+
return pricing;
|
|
186
|
+
}
|
|
110
187
|
/**
|
|
111
|
-
*
|
|
188
|
+
* Raw provider cost in USD.
|
|
189
|
+
*
|
|
190
|
+
* @throws {UnknownModelError} when the id has no registered price.
|
|
112
191
|
*/
|
|
113
192
|
export function calculateCost(modelId, inputTokens, outputTokens) {
|
|
114
|
-
const config =
|
|
115
|
-
if (!config) {
|
|
116
|
-
// Loud fallback: an unknown model ID means somewhere upstream is
|
|
117
|
-
// shipping a stale string that doesn't match MODEL_CONFIGS. We
|
|
118
|
-
// price it at the highest known rate so we don't accidentally give
|
|
119
|
-
// away expensive completions for free, but the warning here is the
|
|
120
|
-
// contract — silent fallback is how we ended up over-billing every
|
|
121
|
-
// free Gemini turn at Claude prices.
|
|
122
|
-
console.warn(`[calculateCost] Unknown model "${modelId}" — pricing at worst-case Claude rate ($3/$15 per M). Add it to MODEL_CONFIGS.`);
|
|
123
|
-
return (inputTokens / 1000000) * 3.0 + (outputTokens / 1000000) * 15.0;
|
|
124
|
-
}
|
|
193
|
+
const config = requireModel(modelId);
|
|
125
194
|
return ((inputTokens / 1000000) * config.costPerMInputTokens +
|
|
126
195
|
(outputTokens / 1000000) * config.costPerMOutputTokens);
|
|
127
196
|
}
|
|
@@ -133,11 +202,9 @@ export function calculateCost(modelId, inputTokens, outputTokens) {
|
|
|
133
202
|
*
|
|
134
203
|
* INVARIANT — 65% gross margin floor (founder contract):
|
|
135
204
|
* gross_margin = 1 − 1/multiplier
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* and unexpected provider price hikes. The Vitest assertion in
|
|
140
|
-
* models.test.ts pins this — drop below 2.857 at your own risk.
|
|
205
|
+
* Keeping gross_margin ≥ 0.65 means multiplier ≥ 1/0.35 ≈ 2.857. The
|
|
206
|
+
* current value of 4 yields 75%, leaving buffer above the floor for
|
|
207
|
+
* FX moves and provider price rises. `pricing.test.ts` pins it.
|
|
141
208
|
*/
|
|
142
209
|
export const DEFAULT_BILLING_MARGIN = 4;
|
|
143
210
|
/**
|
|
@@ -146,25 +213,14 @@ export const DEFAULT_BILLING_MARGIN = 4;
|
|
|
146
213
|
*/
|
|
147
214
|
export const DEFAULT_USD_TO_MNT_RATE = 3450;
|
|
148
215
|
/**
|
|
149
|
-
*
|
|
150
|
-
* estimation in checkQuota. Numbers are conservative — cap on streamed
|
|
151
|
-
* output tokens we'd actually let a single chat turn produce.
|
|
152
|
-
*/
|
|
153
|
-
export const MODEL_OUTPUT_BUDGET = {
|
|
154
|
-
"google/gemini-2.5-flash": 8000,
|
|
155
|
-
"google/gemini-2.5-pro": 8000,
|
|
156
|
-
"openai/gpt-5-mini": 8000,
|
|
157
|
-
"openai/gpt-5.4-mini": 8000,
|
|
158
|
-
"openai/o4-mini": 8000,
|
|
159
|
-
"anthropic/claude-sonnet-4-6": 8000,
|
|
160
|
-
};
|
|
161
|
-
/**
|
|
162
|
-
* Convert raw model cost to MNT user-facing charged amount.
|
|
216
|
+
* Convert raw model cost to the user-facing charged amount.
|
|
163
217
|
*
|
|
164
218
|
* chargedMnt = ceil( rawCostUsd × margin × fxRate )
|
|
165
219
|
*
|
|
166
220
|
* The rounding is upward so micro-fractions never let a free request
|
|
167
|
-
* slip through; over-billing per request is at most
|
|
221
|
+
* slip through; over-billing per request is at most one unit.
|
|
222
|
+
*
|
|
223
|
+
* @throws {UnknownModelError} when the id has no registered price.
|
|
168
224
|
*/
|
|
169
225
|
export function calculateChargedMnt(modelId, inputTokens, outputTokens, fxRate = DEFAULT_USD_TO_MNT_RATE, margin = DEFAULT_BILLING_MARGIN) {
|
|
170
226
|
const rawCostUsd = calculateCost(modelId, inputTokens, outputTokens);
|
|
@@ -172,14 +228,16 @@ export function calculateChargedMnt(modelId, inputTokens, outputTokens, fxRate =
|
|
|
172
228
|
return { rawCostUsd, chargedMnt };
|
|
173
229
|
}
|
|
174
230
|
/**
|
|
175
|
-
* Worst-case
|
|
231
|
+
* Worst-case cost estimate for a single chat turn against a given
|
|
176
232
|
* model. Used by checkQuota to refuse requests whose ceiling cost would
|
|
177
|
-
* exceed remaining balance, before
|
|
178
|
-
*
|
|
179
|
-
*
|
|
233
|
+
* exceed the remaining balance, before provider tokens are burnt. Uses
|
|
234
|
+
* the model's own `maxOutputTokens` and a generous 16K input budget to
|
|
235
|
+
* cover system prompt plus conversation history.
|
|
236
|
+
*
|
|
237
|
+
* @throws {UnknownModelError} when the id has no registered price.
|
|
180
238
|
*/
|
|
181
239
|
export function estimateWorstCaseChargedMnt(modelId, fxRate = DEFAULT_USD_TO_MNT_RATE, margin = DEFAULT_BILLING_MARGIN) {
|
|
182
|
-
const outputBudget =
|
|
240
|
+
const outputBudget = requireModel(modelId).maxOutputTokens;
|
|
183
241
|
const inputBudget = 16000;
|
|
184
242
|
return calculateChargedMnt(modelId, inputBudget, outputBudget, fxRate, margin)
|
|
185
243
|
.chargedMnt;
|
package/dist/pricing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
|
package/dist/queries.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { db } from "@intelligo-dev/core/db";
|
|
6
6
|
import { and, desc, eq, gte, inArray, lt, lte, sql } from "drizzle-orm";
|
|
7
|
-
import { executions } from "./db/schema";
|
|
7
|
+
import { executions } from "./db/schema.js";
|
|
8
8
|
export async function listExecutions(options = {}) {
|
|
9
9
|
const filters = [
|
|
10
10
|
options.workspaceId
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intelligo-dev/executions",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,25 +27,35 @@
|
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"
|
|
31
|
-
"@intelligo-dev/audit": "1.0.0-beta.
|
|
32
|
-
"@intelligo-dev/core": "1.0.0-beta.2"
|
|
30
|
+
"@intelligo-dev/core": "1.0.0-beta.5",
|
|
31
|
+
"@intelligo-dev/audit": "1.0.0-beta.5"
|
|
33
32
|
},
|
|
34
33
|
"devDependencies": {
|
|
35
34
|
"@types/node": "^22.0.0",
|
|
36
35
|
"@types/pg": "^8.16.0",
|
|
36
|
+
"drizzle-orm": "^0.45.1",
|
|
37
37
|
"pg": "^8.18.0",
|
|
38
38
|
"typescript": "^5.7.2"
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
|
-
"dist"
|
|
41
|
+
"dist",
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"README.md",
|
|
44
|
+
"!dist/**/*.tsbuildinfo"
|
|
42
45
|
],
|
|
43
46
|
"publishConfig": {
|
|
44
47
|
"access": "public"
|
|
45
48
|
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"drizzle-orm": "^0.45.1"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"sideEffects": false,
|
|
46
56
|
"scripts": {
|
|
47
57
|
"type-check": "tsc --noEmit",
|
|
48
58
|
"lint": "eslint .",
|
|
49
|
-
"build": "tsc -p tsconfig.build.json"
|
|
59
|
+
"build": "tsc -p tsconfig.build.json && node ../../scripts/fix-esm-extensions.mjs dist"
|
|
50
60
|
}
|
|
51
61
|
}
|