@memberjunction/core-entities-server 6.1.0-edge.4 → 6.1.0-edge.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/dist/custom/MJAIPromptRunEntityServer.server.d.ts +76 -0
- package/dist/custom/MJAIPromptRunEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIPromptRunEntityServer.server.js +164 -28
- package/dist/custom/MJAIPromptRunEntityServer.server.js.map +1 -1
- package/dist/custom/MJConversationDetailEntityServer.server.d.ts +14 -2
- package/dist/custom/MJConversationDetailEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJConversationDetailEntityServer.server.js +14 -2
- package/dist/custom/MJConversationDetailEntityServer.server.js.map +1 -1
- package/package.json +28 -28
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
import { EntitySaveOptions } from "@memberjunction/core";
|
|
2
|
+
import { ModelUsageUnitKind } from "@memberjunction/ai";
|
|
2
3
|
import { MJAIPromptRunEntityExtended } from "@memberjunction/ai-core-plus";
|
|
4
|
+
import { BasePriceUnitType, NormalizedUsage } from "@memberjunction/ai-engine-base";
|
|
5
|
+
/**
|
|
6
|
+
* What a prompt run recorded about the work it did, in whichever measure applies.
|
|
7
|
+
*
|
|
8
|
+
* Token counts and continuous units are both present because they are not alternatives at the
|
|
9
|
+
* schema level — the usage type is what says which pair is meaningful.
|
|
10
|
+
*
|
|
11
|
+
* Carried as the measure NAME, not as `UsageTypeID`. The pricing drivers are keyed on the measure
|
|
12
|
+
* (`ModelUsageUnitKind`); resolving the foreign key once, here at the storage boundary, keeps every
|
|
13
|
+
* pure function below independent of how the catalog is persisted — and keeps them testable without
|
|
14
|
+
* a loaded engine.
|
|
15
|
+
*/
|
|
16
|
+
export type RecordedRunUsage = {
|
|
17
|
+
tokensPrompt: number;
|
|
18
|
+
tokensCacheRead: number;
|
|
19
|
+
tokensCacheWrite: number;
|
|
20
|
+
tokensCompletion: number;
|
|
21
|
+
/**
|
|
22
|
+
* Null means a set `UsageTypeID` could not be resolved against the loaded catalog — never an
|
|
23
|
+
* unset column, which is read as `Tokens` before this type is built; see `RecordedUsage`.
|
|
24
|
+
*/
|
|
25
|
+
unitsKind: ModelUsageUnitKind | null;
|
|
26
|
+
inputUnits: number;
|
|
27
|
+
outputUnits: number;
|
|
28
|
+
};
|
|
29
|
+
/** Either the quantities to price, or the reason they cannot be priced. */
|
|
30
|
+
export type NormalizeUsageResult = {
|
|
31
|
+
ok: true;
|
|
32
|
+
usage: NormalizedUsage;
|
|
33
|
+
} | {
|
|
34
|
+
ok: false;
|
|
35
|
+
reason: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Whether a run recorded any work at all worth pricing.
|
|
39
|
+
*
|
|
40
|
+
* Token input is the TOTAL the provider processed: net-new plus cache reads plus cache writes. A
|
|
41
|
+
* heavily-cached call can have zero net-new prompt tokens and still incur input cost, so the gate
|
|
42
|
+
* is on the total rather than net-new alone. Continuous-media runs legitimately record zero tokens
|
|
43
|
+
* — their work is measured in seconds or images — so units count as usage too.
|
|
44
|
+
*/
|
|
45
|
+
export declare function hasRecordedUsage(recorded: RecordedRunUsage): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Maps a run's recorded usage onto the quantities a driver of `driverUnitKind` prices, refusing
|
|
48
|
+
* when the two disagree about what is being measured.
|
|
49
|
+
*
|
|
50
|
+
* The refusal matters: a transcription run measured in seconds, handed to a per-1M-tokens driver,
|
|
51
|
+
* would be priced by dividing seconds by a million — a cost of approximately zero that looks like
|
|
52
|
+
* a real answer. Refusing surfaces the misconfigured cost row instead of hiding it behind a number.
|
|
53
|
+
*/
|
|
54
|
+
export declare function normalizeRecordedUsage(recorded: RecordedRunUsage, driverUnitKind: ModelUsageUnitKind): NormalizeUsageResult;
|
|
3
55
|
/**
|
|
4
56
|
* Server-side subclass for MJAIPromptRunEntity that automatically calculates costs
|
|
5
57
|
* when a prompt run is completed or errors out. The cost calculation is based on
|
|
@@ -21,6 +73,30 @@ export declare class MJAIPromptRunEntityServer extends MJAIPromptRunEntityExtend
|
|
|
21
73
|
* Calculates the cost for this prompt run based on token usage and active pricing
|
|
22
74
|
*/
|
|
23
75
|
protected CalculateAndSetCost(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* This run's recorded usage, with nulls collapsed to zero for the pure helpers above.
|
|
78
|
+
*
|
|
79
|
+
* `UsageTypeID` is resolved to its measure NAME here, through the engine's cached catalog, so
|
|
80
|
+
* the pure functions never see a foreign key. This is the ONE seam that reads an unset column
|
|
81
|
+
* as `Tokens`, and it is the only place allowed to: the column is nullable until the release
|
|
82
|
+
* after the AI Usage Types seed ships, and every row written before it existed was token-billed
|
|
83
|
+
* — the schema had no way to say anything else.
|
|
84
|
+
*
|
|
85
|
+
* A SET id that the catalog does not contain is a different situation and stays null: that is a
|
|
86
|
+
* real fault — a stale cache or a deleted row — so it is logged, and `normalizeRecordedUsage`
|
|
87
|
+
* refuses to price units recorded against it. Collapsing the two would price seconds as tokens
|
|
88
|
+
* and write a confident zero.
|
|
89
|
+
*/
|
|
90
|
+
protected RecordedUsage(): RecordedRunUsage;
|
|
91
|
+
/**
|
|
92
|
+
* Turns this run's recorded usage into the quantities the resolved calculator prices, or null
|
|
93
|
+
* (having logged why) when the two disagree about what is being measured.
|
|
94
|
+
*
|
|
95
|
+
* Takes the recorded usage as a parameter rather than re-reading it: `CalculateAndSetCost` needs
|
|
96
|
+
* the measure BEFORE it can select a cost row, and `RecordedUsage` logs when a `UsageTypeID`
|
|
97
|
+
* fails to resolve — calling it twice would report the same fault twice for one save.
|
|
98
|
+
*/
|
|
99
|
+
protected BuildNormalizedUsage(priceCalculator: BasePriceUnitType, recorded?: RecordedRunUsage): NormalizedUsage | null;
|
|
24
100
|
/**
|
|
25
101
|
* Triggers cost rollup calculation on the parent prompt run
|
|
26
102
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJAIPromptRunEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAkD,MAAM,sBAAsB,CAAC;AAErH,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"MJAIPromptRunEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAkD,MAAM,sBAAsB,CAAC;AAErH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAgB,iBAAiB,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAElG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,oBAAoB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAIpE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAClC,QAAQ,EAAE,gBAAgB,EAC1B,cAAc,EAAE,kBAAkB,GACnC,oBAAoB,CA0EtB;AAED;;;;;;GAMG;AACH,qBACa,yBAA0B,SAAQ,2BAA2B;IAEtE;;OAEG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA6BlE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,OAAO;IAkCxC;;OAEG;cACa,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IA+DpD;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,aAAa,IAAI,gBAAgB;IAmB3C;;;;;;;OAOG;IACH,SAAS,CAAC,oBAAoB,CAC1B,eAAe,EAAE,iBAAiB,EAClC,QAAQ,GAAE,gBAAuC,GAClD,eAAe,GAAG,IAAI;IASzB;;OAEG;cACa,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBxD;;;;OAIG;IACU,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BlD;;;;OAIG;IACH,IAAW,cAAc,CAAC,KAAK,EAAE,MAAM,EAGtC;IAED,IAAW,cAAc,IAAI,MAAM,CAElC;IAED;;;;OAIG;IACH,IAAW,IAAI,CAAC,KAAK,EAAE,MAAM,EAG5B;IAED,IAAW,IAAI,IAAI,MAAM,CAExB;IACD;;;;;OAKG;IACH,SAAS,CAAC,eAAe,IAAI,IAAI;CAKpC"}
|
|
@@ -5,9 +5,99 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { BaseEntity, LogError } from "@memberjunction/core";
|
|
8
|
-
import { RegisterClass
|
|
8
|
+
import { RegisterClass } from "@memberjunction/global";
|
|
9
9
|
import { MJAIPromptRunEntityExtended } from "@memberjunction/ai-core-plus";
|
|
10
|
-
import { AIEngineBase
|
|
10
|
+
import { AIEngineBase } from "@memberjunction/ai-engine-base";
|
|
11
|
+
/**
|
|
12
|
+
* Whether a run recorded any work at all worth pricing.
|
|
13
|
+
*
|
|
14
|
+
* Token input is the TOTAL the provider processed: net-new plus cache reads plus cache writes. A
|
|
15
|
+
* heavily-cached call can have zero net-new prompt tokens and still incur input cost, so the gate
|
|
16
|
+
* is on the total rather than net-new alone. Continuous-media runs legitimately record zero tokens
|
|
17
|
+
* — their work is measured in seconds or images — so units count as usage too.
|
|
18
|
+
*/
|
|
19
|
+
export function hasRecordedUsage(recorded) {
|
|
20
|
+
const totalInputTokens = recorded.tokensPrompt + recorded.tokensCacheRead + recorded.tokensCacheWrite;
|
|
21
|
+
const totalUnits = recorded.inputUnits + recorded.outputUnits;
|
|
22
|
+
return totalInputTokens > 0 || recorded.tokensCompletion > 0 || totalUnits > 0;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Maps a run's recorded usage onto the quantities a driver of `driverUnitKind` prices, refusing
|
|
26
|
+
* when the two disagree about what is being measured.
|
|
27
|
+
*
|
|
28
|
+
* The refusal matters: a transcription run measured in seconds, handed to a per-1M-tokens driver,
|
|
29
|
+
* would be priced by dividing seconds by a million — a cost of approximately zero that looks like
|
|
30
|
+
* a real answer. Refusing surfaces the misconfigured cost row instead of hiding it behind a number.
|
|
31
|
+
*/
|
|
32
|
+
export function normalizeRecordedUsage(recorded, driverUnitKind) {
|
|
33
|
+
// Units whose measure could not be RESOLVED name nothing: nothing says what they are counted in,
|
|
34
|
+
// so there is no driver they can honestly be handed to. This is not "the producer forgot to set
|
|
35
|
+
// it" — an unset column is read as Tokens at the storage seam and caught by the next guard — it
|
|
36
|
+
// is an id absent from the loaded catalog: a deleted row or a stale cache. Falling through would
|
|
37
|
+
// treat them as Tokens and price the run's (zero) token counts, writing Cost = 0 for billed work.
|
|
38
|
+
if (recorded.unitsKind == null && (recorded.inputUnits > 0 || recorded.outputUnits > 0)) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
reason: `run recorded ${recorded.inputUnits} input / ${recorded.outputUnits} output units but no ` +
|
|
42
|
+
`resolvable usage type, so there is no measure to price them in`
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const recordedKind = recorded.unitsKind ?? 'Tokens';
|
|
46
|
+
// "The producer never said what these units are" and "the producer said they are tokens" arrive
|
|
47
|
+
// here as the same value, because an unset `UsageTypeID` is read as Tokens at the storage seam.
|
|
48
|
+
// Both are refused for the same reason: units counted in anything are not token
|
|
49
|
+
// counts — `TokensPrompt`/`TokensCompletion` carry those — so populated units against the Tokens
|
|
50
|
+
// measure is a contradiction, not a quantity to price.
|
|
51
|
+
//
|
|
52
|
+
// Why it is reachable at all, given the measure-filtered row selection: for a model whose only
|
|
53
|
+
// active row is media-priced, selection finds no Tokens-priced row and the run is refused with a
|
|
54
|
+
// logged reason — safe. But a model carrying an active token row ALONGSIDE a media one selects
|
|
55
|
+
// the token row, matches measures (both say Tokens), normalizes the token buckets to
|
|
56
|
+
// {0, 0, 0, 0}, and persists Cost = 0 against a run that recorded thousands of units of billed
|
|
57
|
+
// work. No shipped model+vendor pair carries two measures today, so it cannot occur on current
|
|
58
|
+
// data — and the deferred image-generation work is exactly where multi-measure models arrive.
|
|
59
|
+
if (recordedKind === 'Tokens' && (recorded.inputUnits > 0 || recorded.outputUnits > 0)) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
reason: `run recorded ${recorded.inputUnits} input / ${recorded.outputUnits} output units against the ` +
|
|
63
|
+
`Tokens measure, which counts tokens rather than units; set UsageTypeID to the measure they were ` +
|
|
64
|
+
`actually counted in`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// The mirror of the check above, and the same defect through the other side: a kind with no
|
|
68
|
+
// quantity. `hasRecordedUsage` is satisfied by token counts alone, so a run naming `Seconds`
|
|
69
|
+
// that reports zero seconds reaches here, normalizes to {input: 0, output: 0}, and persists
|
|
70
|
+
// `Cost = 0` — "free" written against work that was billed. This is the path that actually
|
|
71
|
+
// WRITES the column, so the guard has to be here and not only on the standalone costing
|
|
72
|
+
// surface; a run that gets this far has already declared a non-token measure, so a zero
|
|
73
|
+
// quantity is a producer that set the kind and forgot the amount.
|
|
74
|
+
if (recordedKind !== 'Tokens' && recorded.inputUnits === 0 && recorded.outputUnits === 0) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
reason: `run recorded usage in ${recordedKind} but no unit quantity, so there is nothing to ` +
|
|
78
|
+
`price; refusing rather than recording a cost of 0`
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (driverUnitKind !== recordedKind) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
reason: `run recorded usage in ${recordedKind} but its cost row is priced in ${driverUnitKind}` +
|
|
85
|
+
`; correct the cost row's unit type`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (recordedKind === 'Tokens') {
|
|
89
|
+
return {
|
|
90
|
+
ok: true,
|
|
91
|
+
usage: {
|
|
92
|
+
input: recorded.tokensPrompt,
|
|
93
|
+
output: recorded.tokensCompletion,
|
|
94
|
+
cacheRead: recorded.tokensCacheRead,
|
|
95
|
+
cacheWrite: recorded.tokensCacheWrite
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, usage: { input: recorded.inputUnits, output: recorded.outputUnits } };
|
|
100
|
+
}
|
|
11
101
|
/**
|
|
12
102
|
* Server-side subclass for MJAIPromptRunEntity that automatically calculates costs
|
|
13
103
|
* when a prompt run is completed or errors out. The cost calculation is based on
|
|
@@ -62,13 +152,9 @@ let MJAIPromptRunEntityServer = class MJAIPromptRunEntityServer extends MJAIProm
|
|
|
62
152
|
if (this.Cost != null && this.Cost > 0) {
|
|
63
153
|
return false;
|
|
64
154
|
}
|
|
65
|
-
// Must have
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
// tokens, so we gate on the total rather than net-new alone.
|
|
69
|
-
const totalInputTokens = (this.TokensPrompt ?? 0) + (this.TokensCacheRead ?? 0) + (this.TokensCacheWrite ?? 0);
|
|
70
|
-
const totalCompletionTokens = this.TokensCompletion ?? 0;
|
|
71
|
-
if (totalInputTokens <= 0 && totalCompletionTokens <= 0) {
|
|
155
|
+
// Must have recorded usage of SOME kind — tokens for an LLM run, seconds or images for a
|
|
156
|
+
// continuous-media one. Gating on tokens alone is what left media runs silently uncosted.
|
|
157
|
+
if (!hasRecordedUsage(this.RecordedUsage())) {
|
|
72
158
|
return false;
|
|
73
159
|
}
|
|
74
160
|
// Must have model and vendor information
|
|
@@ -84,32 +170,36 @@ let MJAIPromptRunEntityServer = class MJAIPromptRunEntityServer extends MJAIProm
|
|
|
84
170
|
try {
|
|
85
171
|
// Ensure AI metadata is loaded
|
|
86
172
|
await AIEngineBase.Instance.Config(false, this.ContextCurrentUser);
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
173
|
+
// Select the cost row by the measure this run actually recorded, not just by
|
|
174
|
+
// model+vendor: a model with rows in two measures would otherwise hand back whichever
|
|
175
|
+
// started most recently and be refused below, reporting a measure mismatch where the
|
|
176
|
+
// real answer was "pick the other row".
|
|
177
|
+
const recorded = this.RecordedUsage();
|
|
178
|
+
const activeCost = AIEngineBase.Instance.GetActiveModelCost(this.ModelID, this.VendorID, 'Realtime', // For now, assume all prompt runs are realtime
|
|
179
|
+
recorded.unitsKind ?? 'Tokens');
|
|
90
180
|
if (!activeCost) {
|
|
91
|
-
LogError(`No active cost configuration
|
|
181
|
+
LogError(`No active cost configuration priced in ${recorded.unitsKind ?? 'Tokens'} found for ` +
|
|
182
|
+
`Model: ${this.ModelID}, Vendor: ${this.VendorID}`);
|
|
92
183
|
return;
|
|
93
184
|
}
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
185
|
+
// Resolve the calculator the cost row's unit type names (logs and returns null when
|
|
186
|
+
// the unit type or its driver class is missing)
|
|
187
|
+
const priceCalculator = AIEngineBase.Instance.GetPriceCalculator(activeCost);
|
|
188
|
+
if (!priceCalculator) {
|
|
98
189
|
return;
|
|
99
190
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (!priceCalculator) {
|
|
103
|
-
LogError(`Failed to create price calculator for driver class: ${priceUnitType.DriverClass}`);
|
|
191
|
+
const usage = this.BuildNormalizedUsage(priceCalculator, recorded);
|
|
192
|
+
if (!usage) {
|
|
104
193
|
return;
|
|
105
194
|
}
|
|
106
|
-
//
|
|
107
|
-
// standard input rate, cache reads/writes at CacheReadPricePerUnit/
|
|
108
|
-
// when the cost row records them. When those cache rates are NULL
|
|
109
|
-
// back to the input rate, so the result is identical to the prior
|
|
110
|
-
// for models without cache pricing — while models that DO have
|
|
111
|
-
// (usually much cheaper) cached-token cost instead of being billed as
|
|
112
|
-
|
|
195
|
+
// Token pricing prices each input bucket at its own rate: uncached/net-new (TokensPrompt)
|
|
196
|
+
// at the standard input rate, cache reads/writes at CacheReadPricePerUnit /
|
|
197
|
+
// CacheWritePricePerUnit when the cost row records them. When those cache rates are NULL
|
|
198
|
+
// the calculator falls back to the input rate, so the result is identical to the prior
|
|
199
|
+
// single-bucket behavior for models without cache pricing — while models that DO have
|
|
200
|
+
// cache rates get the (usually much cheaper) cached-token cost instead of being billed as
|
|
201
|
+
// full input. Continuous-media pricing ignores the cache buckets entirely.
|
|
202
|
+
const normalizedCost = priceCalculator.CalculateCost(activeCost, usage);
|
|
113
203
|
// Set the cost fields
|
|
114
204
|
this.Cost = normalizedCost;
|
|
115
205
|
this.CostCurrency = activeCost.Currency;
|
|
@@ -125,6 +215,52 @@ let MJAIPromptRunEntityServer = class MJAIPromptRunEntityServer extends MJAIProm
|
|
|
125
215
|
// Don't throw - we don't want to prevent saving just because cost calc failed
|
|
126
216
|
}
|
|
127
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* This run's recorded usage, with nulls collapsed to zero for the pure helpers above.
|
|
220
|
+
*
|
|
221
|
+
* `UsageTypeID` is resolved to its measure NAME here, through the engine's cached catalog, so
|
|
222
|
+
* the pure functions never see a foreign key. This is the ONE seam that reads an unset column
|
|
223
|
+
* as `Tokens`, and it is the only place allowed to: the column is nullable until the release
|
|
224
|
+
* after the AI Usage Types seed ships, and every row written before it existed was token-billed
|
|
225
|
+
* — the schema had no way to say anything else.
|
|
226
|
+
*
|
|
227
|
+
* A SET id that the catalog does not contain is a different situation and stays null: that is a
|
|
228
|
+
* real fault — a stale cache or a deleted row — so it is logged, and `normalizeRecordedUsage`
|
|
229
|
+
* refuses to price units recorded against it. Collapsing the two would price seconds as tokens
|
|
230
|
+
* and write a confident zero.
|
|
231
|
+
*/
|
|
232
|
+
RecordedUsage() {
|
|
233
|
+
const usageTypeName = this.UsageTypeID ? AIEngineBase.Instance.UsageTypeName(this.UsageTypeID) : 'Tokens';
|
|
234
|
+
if (usageTypeName === null) {
|
|
235
|
+
LogError(`AIPromptRun ${this.ID} references usage type ${this.UsageTypeID}, which is not in the ` +
|
|
236
|
+
`loaded catalog; its units cannot be priced.`);
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
tokensPrompt: this.TokensPrompt ?? 0,
|
|
240
|
+
tokensCacheRead: this.TokensCacheRead ?? 0,
|
|
241
|
+
tokensCacheWrite: this.TokensCacheWrite ?? 0,
|
|
242
|
+
tokensCompletion: this.TokensCompletion ?? 0,
|
|
243
|
+
unitsKind: usageTypeName,
|
|
244
|
+
inputUnits: this.InputUnitsUsed ?? 0,
|
|
245
|
+
outputUnits: this.OutputUnitsUsed ?? 0
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Turns this run's recorded usage into the quantities the resolved calculator prices, or null
|
|
250
|
+
* (having logged why) when the two disagree about what is being measured.
|
|
251
|
+
*
|
|
252
|
+
* Takes the recorded usage as a parameter rather than re-reading it: `CalculateAndSetCost` needs
|
|
253
|
+
* the measure BEFORE it can select a cost row, and `RecordedUsage` logs when a `UsageTypeID`
|
|
254
|
+
* fails to resolve — calling it twice would report the same fault twice for one save.
|
|
255
|
+
*/
|
|
256
|
+
BuildNormalizedUsage(priceCalculator, recorded = this.RecordedUsage()) {
|
|
257
|
+
const result = normalizeRecordedUsage(recorded, priceCalculator.UnitKind);
|
|
258
|
+
if (result.ok === false) {
|
|
259
|
+
LogError(`Cannot cost AIPromptRun ${this.ID}: ${result.reason}.`);
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
return result.usage;
|
|
263
|
+
}
|
|
128
264
|
/**
|
|
129
265
|
* Triggers cost rollup calculation on the parent prompt run
|
|
130
266
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJAIPromptRunEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAqB,QAAQ,EAAwC,MAAM,sBAAsB,CAAC;AACrH,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"MJAIPromptRunEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EntitySaveOptions } from "@memberjunction/core";
|
|
2
|
-
import {
|
|
2
|
+
import { MJConversationDetailEntityExtended } from "@memberjunction/core-entities";
|
|
3
3
|
/**
|
|
4
4
|
* Server-side subclass of MJConversationDetailEntity that automatically tracks
|
|
5
5
|
* when the original message content has been modified.
|
|
@@ -12,8 +12,20 @@ import { MJConversationDetailEntity } from "@memberjunction/core-entities";
|
|
|
12
12
|
* UI can derive "edited after summarization" from the flag plus the row's Sequence
|
|
13
13
|
* being below the current summary boundary — no summary regeneration required (the
|
|
14
14
|
* summary is explicitly lossy; agents page in exact rows via the retrieval tools).
|
|
15
|
+
*
|
|
16
|
+
* Extends {@link MJConversationDetailEntityExtended} rather than the generated entity
|
|
17
|
+
* directly. Both classes register for `BaseEntity` under the key
|
|
18
|
+
* `'MJ: Conversation Details'`, and `@RegisterClass` passes `priority = 0`, which routes
|
|
19
|
+
* to the auto-increment branch — so whichever registers LAST wins outright. On the server
|
|
20
|
+
* this package loads after `@memberjunction/core-entities`, which meant this class replaced
|
|
21
|
+
* the Extended one and its `Save`/`Delete` permission gate never ran. That gate is the check
|
|
22
|
+
* that only a conversation's owner may set `UserRating` / `UserFeedback`, and that a
|
|
23
|
+
* non-owner without a resource grant cannot write at all — and it is explicitly designed to
|
|
24
|
+
* run server-side (`ProviderType === 'Database'`), which is exactly where it was being
|
|
25
|
+
* shadowed out. Inheriting composes the two behaviors instead: this class flags the edit,
|
|
26
|
+
* then delegates to the permission gate via `super.Save`.
|
|
15
27
|
*/
|
|
16
|
-
export declare class MJConversationDetailEntityServer extends
|
|
28
|
+
export declare class MJConversationDetailEntityServer extends MJConversationDetailEntityExtended {
|
|
17
29
|
/**
|
|
18
30
|
* Override Save to detect message changes and set the OriginalMessageChanged flag.
|
|
19
31
|
* This is done as pre-processing before calling super.Save() to ensure it's a single DB round trip.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJConversationDetailEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJConversationDetailEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"MJConversationDetailEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJConversationDetailEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAE,kCAAkC,EAAE,MAAM,+BAA+B,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBACa,gCAAiC,SAAQ,kCAAkC;IACpF;;;OAGG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQlE;;;;;;;;;;;OAWG;IACI,gCAAgC,IAAI,OAAO;CAiBrD"}
|
|
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { BaseEntity } from "@memberjunction/core";
|
|
8
8
|
import { RegisterClass } from "@memberjunction/global";
|
|
9
|
-
import {
|
|
9
|
+
import { MJConversationDetailEntityExtended } from "@memberjunction/core-entities";
|
|
10
10
|
/**
|
|
11
11
|
* Server-side subclass of MJConversationDetailEntity that automatically tracks
|
|
12
12
|
* when the original message content has been modified.
|
|
@@ -19,8 +19,20 @@ import { MJConversationDetailEntity } from "@memberjunction/core-entities";
|
|
|
19
19
|
* UI can derive "edited after summarization" from the flag plus the row's Sequence
|
|
20
20
|
* being below the current summary boundary — no summary regeneration required (the
|
|
21
21
|
* summary is explicitly lossy; agents page in exact rows via the retrieval tools).
|
|
22
|
+
*
|
|
23
|
+
* Extends {@link MJConversationDetailEntityExtended} rather than the generated entity
|
|
24
|
+
* directly. Both classes register for `BaseEntity` under the key
|
|
25
|
+
* `'MJ: Conversation Details'`, and `@RegisterClass` passes `priority = 0`, which routes
|
|
26
|
+
* to the auto-increment branch — so whichever registers LAST wins outright. On the server
|
|
27
|
+
* this package loads after `@memberjunction/core-entities`, which meant this class replaced
|
|
28
|
+
* the Extended one and its `Save`/`Delete` permission gate never ran. That gate is the check
|
|
29
|
+
* that only a conversation's owner may set `UserRating` / `UserFeedback`, and that a
|
|
30
|
+
* non-owner without a resource grant cannot write at all — and it is explicitly designed to
|
|
31
|
+
* run server-side (`ProviderType === 'Database'`), which is exactly where it was being
|
|
32
|
+
* shadowed out. Inheriting composes the two behaviors instead: this class flags the edit,
|
|
33
|
+
* then delegates to the permission gate via `super.Save`.
|
|
22
34
|
*/
|
|
23
|
-
let MJConversationDetailEntityServer = class MJConversationDetailEntityServer extends
|
|
35
|
+
let MJConversationDetailEntityServer = class MJConversationDetailEntityServer extends MJConversationDetailEntityExtended {
|
|
24
36
|
/**
|
|
25
37
|
* Override Save to detect message changes and set the OriginalMessageChanged flag.
|
|
26
38
|
* This is done as pre-processing before calling super.Save() to ensure it's a single DB round trip.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJConversationDetailEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJConversationDetailEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAqB,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"MJConversationDetailEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJConversationDetailEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAqB,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,kCAAkC,EAAE,MAAM,+BAA+B,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEI,IAAM,gCAAgC,GAAtC,MAAM,gCAAiC,SAAQ,kCAAkC;IACpF;;;OAGG;IACM,KAAK,CAAC,IAAI,CAAC,OAA2B;QAC3C,IAAI,IAAI,CAAC,gCAAgC,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACvC,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED;;;;;;;;;;;OAWG;IACI,gCAAgC;QACnC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC9E,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,WAAW,EAAE,KAAK,EAAE,CAAC;YACrB,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAA;AA1CY,gCAAgC;IAD5C,aAAa,CAAC,UAAU,EAAE,0BAA0B,CAAC;GACzC,gCAAgC,CA0C5C"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/core-entities-server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.1.0-edge.
|
|
4
|
+
"version": "6.1.0-edge.5",
|
|
5
5
|
"description": "Entity subclasses for the metadata layer of MemberJunction that are only used on server side applications like MJAPI, distributed as part of each release of MemberJunction",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -15,33 +15,33 @@
|
|
|
15
15
|
"typescript": "^5.9.3"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@memberjunction/actions-base": "6.1.0-edge.
|
|
19
|
-
"@memberjunction/ai": "6.1.0-edge.
|
|
20
|
-
"@memberjunction/ai-core-plus": "6.1.0-edge.
|
|
21
|
-
"@memberjunction/ai-engine-base": "6.1.0-edge.
|
|
22
|
-
"@memberjunction/ai-prompts": "6.1.0-edge.
|
|
23
|
-
"@memberjunction/ai-provider-bundle": "6.1.0-edge.
|
|
24
|
-
"@memberjunction/ai-vector-dupe": "6.1.0-edge.
|
|
25
|
-
"@memberjunction/ai-vectordb": "6.1.0-edge.
|
|
26
|
-
"@memberjunction/ai-vectors-memory": "6.1.0-edge.
|
|
27
|
-
"@memberjunction/aiengine": "6.1.0-edge.
|
|
28
|
-
"@memberjunction/core": "6.1.0-edge.
|
|
29
|
-
"@memberjunction/core-entities": "6.1.0-edge.
|
|
30
|
-
"@memberjunction/predictive-studio-core": "6.1.0-edge.
|
|
31
|
-
"@memberjunction/doc-utils": "6.1.0-edge.
|
|
32
|
-
"@memberjunction/generic-database-provider": "6.1.0-edge.
|
|
33
|
-
"@memberjunction/global": "6.1.0-edge.
|
|
34
|
-
"@memberjunction/integration-engine": "6.1.0-edge.
|
|
35
|
-
"@memberjunction/integration-pk-classifier": "6.1.0-edge.
|
|
36
|
-
"@memberjunction/scheduling-engine": "6.1.0-edge.
|
|
37
|
-
"@memberjunction/sql-converter": "6.1.0-edge.
|
|
38
|
-
"@memberjunction/sql-dialect": "6.1.0-edge.
|
|
39
|
-
"@memberjunction/sql-parser": "6.1.0-edge.
|
|
40
|
-
"@memberjunction/sqlserver-dataprovider": "6.1.0-edge.
|
|
41
|
-
"@memberjunction/tag-engine": "6.1.0-edge.
|
|
42
|
-
"@memberjunction/communication-engine": "6.1.0-edge.
|
|
43
|
-
"@memberjunction/communication-types": "6.1.0-edge.
|
|
44
|
-
"@memberjunction/templates": "6.1.0-edge.
|
|
18
|
+
"@memberjunction/actions-base": "6.1.0-edge.5",
|
|
19
|
+
"@memberjunction/ai": "6.1.0-edge.5",
|
|
20
|
+
"@memberjunction/ai-core-plus": "6.1.0-edge.5",
|
|
21
|
+
"@memberjunction/ai-engine-base": "6.1.0-edge.5",
|
|
22
|
+
"@memberjunction/ai-prompts": "6.1.0-edge.5",
|
|
23
|
+
"@memberjunction/ai-provider-bundle": "6.1.0-edge.5",
|
|
24
|
+
"@memberjunction/ai-vector-dupe": "6.1.0-edge.5",
|
|
25
|
+
"@memberjunction/ai-vectordb": "6.1.0-edge.5",
|
|
26
|
+
"@memberjunction/ai-vectors-memory": "6.1.0-edge.5",
|
|
27
|
+
"@memberjunction/aiengine": "6.1.0-edge.5",
|
|
28
|
+
"@memberjunction/core": "6.1.0-edge.5",
|
|
29
|
+
"@memberjunction/core-entities": "6.1.0-edge.5",
|
|
30
|
+
"@memberjunction/predictive-studio-core": "6.1.0-edge.5",
|
|
31
|
+
"@memberjunction/doc-utils": "6.1.0-edge.5",
|
|
32
|
+
"@memberjunction/generic-database-provider": "6.1.0-edge.5",
|
|
33
|
+
"@memberjunction/global": "6.1.0-edge.5",
|
|
34
|
+
"@memberjunction/integration-engine": "6.1.0-edge.5",
|
|
35
|
+
"@memberjunction/integration-pk-classifier": "6.1.0-edge.5",
|
|
36
|
+
"@memberjunction/scheduling-engine": "6.1.0-edge.5",
|
|
37
|
+
"@memberjunction/sql-converter": "6.1.0-edge.5",
|
|
38
|
+
"@memberjunction/sql-dialect": "6.1.0-edge.5",
|
|
39
|
+
"@memberjunction/sql-parser": "6.1.0-edge.5",
|
|
40
|
+
"@memberjunction/sqlserver-dataprovider": "6.1.0-edge.5",
|
|
41
|
+
"@memberjunction/tag-engine": "6.1.0-edge.5",
|
|
42
|
+
"@memberjunction/communication-engine": "6.1.0-edge.5",
|
|
43
|
+
"@memberjunction/communication-types": "6.1.0-edge.5",
|
|
44
|
+
"@memberjunction/templates": "6.1.0-edge.5",
|
|
45
45
|
"nunjucks": "3.2.4",
|
|
46
46
|
"rxjs": "~7.8.1",
|
|
47
47
|
"zod": "^3.25.0"
|