@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 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
- * "career.recommendation", "chat.message". Opaque to Intelligo —
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 { MODEL_CONFIGS, MODEL_OUTPUT_BUDGET, DEFAULT_BILLING_MARGIN, DEFAULT_USD_TO_MNT_RATE, calculateCost, calculateChargedMnt, estimateWorstCaseChargedMnt, } from "./pricing";
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
@@ -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,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
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 { MODEL_CONFIGS, MODEL_OUTPUT_BUDGET, DEFAULT_BILLING_MARGIN, DEFAULT_USD_TO_MNT_RATE, calculateCost, calculateChargedMnt, estimateWorstCaseChargedMnt, } from "./pricing";
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,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,WAAW,CAAC"}
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"}
@@ -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 careerAgent.generate(messages); // native
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. "career.recommendation". */
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;
@@ -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,0DAA0D;IAC1D,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"}
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 careerAgent.generate(messages); // native
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
- * Deliberately a leaf module — no database, no provider SDK, no
10
- * imports at all — and reachable as `@intelligo-dev/executions/pricing`
11
- * so a client bundle can read a display name or a price without
12
- * pulling in Drizzle. `@intelligo-dev/ai` re-exports it, so the ids that
13
- * pick a provider and the ids that carry a price stay one list; two
14
- * lists is how a model runs on Gemini and bills at Claude rates.
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
- * Model configuration with display information and cost tracking
66
+ * A model id is now any string, because the registry is open.
18
67
  *
19
- * 6 models, 3 providers: Google (2), OpenAI (3), Anthropic (1)
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 declare const MODEL_CONFIGS: {
22
- readonly "google/gemini-2.5-flash": {
23
- readonly provider: "google";
24
- readonly model: "gemini-2.5-flash";
25
- readonly displayName: "Gemini 2.5 Flash";
26
- readonly costPerMInputTokens: 0.3;
27
- readonly costPerMOutputTokens: 2.5;
28
- readonly capabilities: {
29
- readonly thinking: true;
30
- readonly toolCall: true;
31
- readonly vision: true;
32
- readonly webSearch: true;
33
- readonly codeExec: true;
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
- * Calculate the dollar cost for a given model and token counts.
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
- * We must keep gross_margin ≥ 0.65 across every model in MODEL_CONFIGS,
121
- * which means multiplier 1/0.35 2.857. The current value of 4
122
- * yields 75%, leaving comfortable buffer above the floor for FX moves
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 MNT user-facing charged amount.
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 1 MNT.
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 MNT cost estimate for a single chat turn against a given
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 we burn provider tokens. Uses the
155
- * full MODEL_OUTPUT_BUDGET as the output side and a generous 16K input
156
- * budget to cover system prompt + conversation history.
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
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwFhB,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,aAAa,CAAC;AAEjD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAkBR;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAOvD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;GAOG;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;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAgC,EACxC,MAAM,GAAE,MAA+B,GACtC,MAAM,CAKR"}
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
- * Deliberately a leaf module — no database, no provider SDK, no
10
- * imports at all — and reachable as `@intelligo-dev/executions/pricing`
11
- * so a client bundle can read a display name or a price without
12
- * pulling in Drizzle. `@intelligo-dev/ai` re-exports it, so the ids that
13
- * pick a provider and the ids that carry a price stay one list; two
14
- * lists is how a model runs on Gemini and bills at Claude rates.
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
- * Model configuration with display information and cost tracking
76
+ * The catalogue the framework ships, as data.
18
77
  *
19
- * 6 models, 3 providers: Google (2), OpenAI (3), Anthropic (1)
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 MODEL_CONFIGS = {
22
- // Google Gemini
23
- "google/gemini-2.5-flash": {
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
- "google/gemini-2.5-pro": {
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
- // OpenAI
52
- "openai/gpt-5-mini": {
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
- "openai/gpt-5.4-mini": {
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
- "openai/o4-mini": {
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
- // Anthropic
95
- "anthropic/claude-sonnet-4-6": {
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
- * Calculate the dollar cost for a given model and token counts.
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 = MODEL_CONFIGS[modelId];
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
- * We must keep gross_margin ≥ 0.65 across every model in MODEL_CONFIGS,
137
- * which means multiplier 1/0.35 2.857. The current value of 4
138
- * yields 75%, leaving comfortable buffer above the floor for FX moves
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
- * Per-model maximum output budget used for worst-case pre-request cost
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 1 MNT.
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 MNT cost estimate for a single chat turn against a given
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 we burn provider tokens. Uses the
178
- * full MODEL_OUTPUT_BUDGET as the output side and a generous 16K input
179
- * budget to cover system prompt + conversation history.
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 = MODEL_OUTPUT_BUDGET[modelId] ?? 8000;
240
+ const outputBudget = requireModel(modelId).maxOutputTokens;
183
241
  const inputBudget = 16000;
184
242
  return calculateChargedMnt(modelId, inputBudget, outputBudget, fxRate, margin)
185
243
  .chargedMnt;
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
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.2",
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
- "drizzle-orm": "^0.45.1",
31
- "@intelligo-dev/audit": "1.0.0-beta.2",
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
  }