@talkpilot/core-db 1.3.67 → 1.3.68
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 +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.d.ts +4 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.d.ts.map +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.js +30 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.js.map +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.d.ts +28 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.d.ts.map +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.js +3 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.js.map +1 -0
- package/dist/talkpilot/callTokenUsage/index.d.ts +3 -0
- package/dist/talkpilot/callTokenUsage/index.d.ts.map +1 -0
- package/dist/talkpilot/callTokenUsage/index.js +18 -0
- package/dist/talkpilot/callTokenUsage/index.js.map +1 -0
- package/dist/talkpilot/index.d.ts +1 -0
- package/dist/talkpilot/index.d.ts.map +1 -1
- package/dist/talkpilot/index.js +1 -0
- package/dist/talkpilot/index.js.map +1 -1
- package/package.json +1 -1
- package/src/talkpilot/callTokenUsage/__tests__/callTokenUsage.getters.spec.ts +57 -0
- package/src/talkpilot/callTokenUsage/callTokenUsage.getters.ts +42 -0
- package/src/talkpilot/callTokenUsage/callTokenUsage.types.ts +28 -0
- package/src/talkpilot/callTokenUsage/index.ts +2 -0
- package/src/talkpilot/index.ts +1 -0
package/README.md
CHANGED
|
@@ -181,6 +181,7 @@ Refer to `DEVELOPMENT.md` for the full walkthrough, token instructions, and fact
|
|
|
181
181
|
| 1.3.57 | Phone-number bind getters: list by client, exclusive flow assign, unbind, and `flow_id` match for ObjectId or leftover string. `getClientByClientId`. |
|
|
182
182
|
| 1.3.61 | Optional `activeFlowId` on `WebsiteTalkProduct` (CP-1849). WebsiteTalk updates this flow instead of the flow on a phone number. |
|
|
183
183
|
| 1.3.62 | Pause/Resume support for WebsiteTalk scans (CP-1752): `PAUSED` and `CANCELED` added to `SCAN_STATUSES` (`PAUSED` deliberately excluded from `FINISHED_SCAN_STATUSES` — pausing isn't done, `CANCELED` is). Added `Scan.pausedAt`, tracked across pause/resume so elapsed-time display can freeze correctly instead of counting the paused duration. |
|
|
184
|
+
| 1.3.64 | New `callTokenUsage` collection with `incrementCallTokenUsage` (CP-1810): per-call realtime token usage, one document per `callSid`. |
|
|
184
185
|
|
|
185
186
|
### 1.1.9
|
|
186
187
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CallTokenUsage, CallTokenUsageDoc } from "./callTokenUsage.types";
|
|
2
|
+
export declare const getCallTokenUsageCollection: () => import("mongodb").Collection<CallTokenUsageDoc>;
|
|
3
|
+
export declare const incrementCallTokenUsage: (callSid: string, { provider, model, ...counters }: CallTokenUsage) => Promise<void>;
|
|
4
|
+
//# sourceMappingURL=callTokenUsage.getters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callTokenUsage.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/callTokenUsage/callTokenUsage.getters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,eAAO,MAAM,2BAA2B,uDAEvC,CAAC;AAkBF,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,EACf,kCAAkC,cAAc,KAC/C,OAAO,CAAC,IAAI,CAcd,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.incrementCallTokenUsage = exports.getCallTokenUsageCollection = void 0;
|
|
4
|
+
const index_1 = require("../index");
|
|
5
|
+
const getCallTokenUsageCollection = () => {
|
|
6
|
+
return (0, index_1.getDb)().collection("callTokenUsage");
|
|
7
|
+
};
|
|
8
|
+
exports.getCallTokenUsageCollection = getCallTokenUsageCollection;
|
|
9
|
+
// Unique callSid, so concurrent first reports of a call upsert one document, not several.
|
|
10
|
+
const callSidIndexByDb = new WeakMap();
|
|
11
|
+
const ensureCallSidIndex = () => {
|
|
12
|
+
const db = (0, index_1.getDb)();
|
|
13
|
+
let index = callSidIndexByDb.get(db);
|
|
14
|
+
if (!index) {
|
|
15
|
+
index = (0, exports.getCallTokenUsageCollection)().createIndex({ callSid: 1 }, { unique: true });
|
|
16
|
+
callSidIndexByDb.set(db, index);
|
|
17
|
+
}
|
|
18
|
+
return index;
|
|
19
|
+
};
|
|
20
|
+
const incrementCallTokenUsage = async (callSid, { provider, model, ...counters }) => {
|
|
21
|
+
await ensureCallSidIndex();
|
|
22
|
+
const now = new Date();
|
|
23
|
+
await (0, exports.getCallTokenUsageCollection)().updateOne({ callSid }, {
|
|
24
|
+
$inc: Object.fromEntries(Object.entries(counters).filter(([, value]) => (value ?? 0) > 0)),
|
|
25
|
+
$set: { provider, ...(model && { model }), updatedAt: now },
|
|
26
|
+
$setOnInsert: { createdAt: now },
|
|
27
|
+
}, { upsert: true });
|
|
28
|
+
};
|
|
29
|
+
exports.incrementCallTokenUsage = incrementCallTokenUsage;
|
|
30
|
+
//# sourceMappingURL=callTokenUsage.getters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callTokenUsage.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/callTokenUsage/callTokenUsage.getters.ts"],"names":[],"mappings":";;;AACA,oCAAiC;AAG1B,MAAM,2BAA2B,GAAG,GAAG,EAAE;IAC9C,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAoB,gBAAgB,CAAC,CAAC;AACjE,CAAC,CAAC;AAFW,QAAA,2BAA2B,+BAEtC;AAEF,0FAA0F;AAC1F,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAAuB,CAAC;AAE5D,MAAM,kBAAkB,GAAG,GAAoB,EAAE;IAC/C,MAAM,EAAE,GAAG,IAAA,aAAK,GAAE,CAAC;IACnB,IAAI,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,IAAA,mCAA2B,GAAE,CAAC,WAAW,CAC/C,EAAE,OAAO,EAAE,CAAC,EAAE,EACd,EAAE,MAAM,EAAE,IAAI,EAAE,CACjB,CAAC;QACF,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEK,MAAM,uBAAuB,GAAG,KAAK,EAC1C,OAAe,EACf,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAkB,EACjC,EAAE;IACjB,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,IAAA,mCAA2B,GAAE,CAAC,SAAS,CAC3C,EAAE,OAAO,EAAE,EACX;QACE,IAAI,EAAE,MAAM,CAAC,WAAW,CACtB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CACjE;QACD,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;QAC3D,YAAY,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE;KACE,EACpC,EAAE,MAAM,EAAE,IAAI,EAAE,CACjB,CAAC;AACJ,CAAC,CAAC;AAjBW,QAAA,uBAAuB,2BAiBlC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type CallTokenUsage = {
|
|
2
|
+
provider: string;
|
|
3
|
+
model?: string;
|
|
4
|
+
responsesCount?: number;
|
|
5
|
+
inputTokens?: number;
|
|
6
|
+
outputTokens?: number;
|
|
7
|
+
totalTokens?: number;
|
|
8
|
+
inputTextTokens?: number;
|
|
9
|
+
inputAudioTokens?: number;
|
|
10
|
+
inputImageTokens?: number;
|
|
11
|
+
cachedInputTokens?: number;
|
|
12
|
+
cachedInputTextTokens?: number;
|
|
13
|
+
cachedInputAudioTokens?: number;
|
|
14
|
+
cachedInputImageTokens?: number;
|
|
15
|
+
outputTextTokens?: number;
|
|
16
|
+
outputAudioTokens?: number;
|
|
17
|
+
thoughtsTokens?: number;
|
|
18
|
+
toolUseTokens?: number;
|
|
19
|
+
billableAudioSeconds?: number;
|
|
20
|
+
sessionSeconds?: number;
|
|
21
|
+
textInputsCount?: number;
|
|
22
|
+
};
|
|
23
|
+
export type CallTokenUsageDoc = CallTokenUsage & {
|
|
24
|
+
callSid: string;
|
|
25
|
+
createdAt: Date;
|
|
26
|
+
updatedAt: Date;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=callTokenUsage.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callTokenUsage.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/callTokenUsage/callTokenUsage.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callTokenUsage.types.js","sourceRoot":"","sources":["../../../src/talkpilot/callTokenUsage/callTokenUsage.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/callTokenUsage/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,mBAAmB,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./callTokenUsage.getters"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/talkpilot/callTokenUsage/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2DAAyC"}
|
|
@@ -12,6 +12,7 @@ export * from "./plans";
|
|
|
12
12
|
export * from "./subscriptions";
|
|
13
13
|
export * from "./groups";
|
|
14
14
|
export * from "./calls";
|
|
15
|
+
export * from "./callTokenUsage";
|
|
15
16
|
export * from "./clientAudioBuffers";
|
|
16
17
|
export * from "./clientsConfig";
|
|
17
18
|
export * from "./backgroundToolResults";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAExD,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,KAAK,GAAI,GAAG,EAAE,SAE1B,CAAC;AACF,eAAO,MAAM,KAAK,QAAO,EAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ,sBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAExD,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,KAAK,GAAI,GAAG,EAAE,SAE1B,CAAC;AACF,eAAO,MAAM,KAAK,QAAO,EAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ,sBAAgB,CAAC"}
|
package/dist/talkpilot/index.js
CHANGED
|
@@ -29,6 +29,7 @@ __exportStar(require("./plans"), exports);
|
|
|
29
29
|
__exportStar(require("./subscriptions"), exports);
|
|
30
30
|
__exportStar(require("./groups"), exports);
|
|
31
31
|
__exportStar(require("./calls"), exports);
|
|
32
|
+
__exportStar(require("./callTokenUsage"), exports);
|
|
32
33
|
__exportStar(require("./clientAudioBuffers"), exports);
|
|
33
34
|
__exportStar(require("./clientsConfig"), exports);
|
|
34
35
|
__exportStar(require("./backgroundToolResults"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qCAAwD;AAExD,0CAAwB;AACxB,iDAA+B;AAC/B,6CAA2B;AAC3B,4CAA0B;AAC1B,6CAA2B;AAC3B,kDAAgC;AAChC,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,0CAAwB;AACxB,kDAAgC;AAChC,2CAAyB;AACzB,0CAAwB;AACxB,uDAAqC;AACrC,kDAAgC;AAChC,0DAAwC;AACxC,kDAAgC;AAChC,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AAEtB,IAAI,EAAM,CAAC;AACJ,MAAM,KAAK,GAAG,CAAC,CAAK,EAAE,EAAE;IAC7B,EAAE,GAAG,CAAC,CAAC;AACT,CAAC,CAAC;AAFW,QAAA,KAAK,SAEhB;AACK,MAAM,KAAK,GAAG,GAAO,EAAE;IAC5B,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAHW,QAAA,KAAK,SAGhB;AAEW,QAAA,QAAQ,GAAG,kBAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qCAAwD;AAExD,0CAAwB;AACxB,iDAA+B;AAC/B,6CAA2B;AAC3B,4CAA0B;AAC1B,6CAA2B;AAC3B,kDAAgC;AAChC,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,0CAAwB;AACxB,kDAAgC;AAChC,2CAAyB;AACzB,0CAAwB;AACxB,mDAAiC;AACjC,uDAAqC;AACrC,kDAAgC;AAChC,0DAAwC;AACxC,kDAAgC;AAChC,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AAEtB,IAAI,EAAM,CAAC;AACJ,MAAM,KAAK,GAAG,CAAC,CAAK,EAAE,EAAE;IAC7B,EAAE,GAAG,CAAC,CAAC;AACT,CAAC,CAAC;AAFW,QAAA,KAAK,SAEhB;AACK,MAAM,KAAK,GAAG,GAAO,EAAE;IAC5B,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAHW,QAAA,KAAK,SAGhB;AAEW,QAAA,QAAQ,GAAG,kBAAa,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCallTokenUsageCollection,
|
|
3
|
+
incrementCallTokenUsage,
|
|
4
|
+
} from "../callTokenUsage.getters";
|
|
5
|
+
|
|
6
|
+
describe("callTokenUsage getters", () => {
|
|
7
|
+
it("should add each report to the call totals and keep provider and model", async () => {
|
|
8
|
+
await incrementCallTokenUsage("CA-usage-1", {
|
|
9
|
+
provider: "openai",
|
|
10
|
+
model: "gpt-realtime",
|
|
11
|
+
inputTokens: 10,
|
|
12
|
+
});
|
|
13
|
+
await incrementCallTokenUsage("CA-usage-1", {
|
|
14
|
+
provider: "openai",
|
|
15
|
+
inputTokens: 5,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const usage = await getCallTokenUsageCollection().findOne({
|
|
19
|
+
callSid: "CA-usage-1",
|
|
20
|
+
});
|
|
21
|
+
expect(usage).toMatchObject({
|
|
22
|
+
provider: "openai",
|
|
23
|
+
model: "gpt-realtime",
|
|
24
|
+
inputTokens: 15,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should create a single document when first reports arrive together", async () => {
|
|
29
|
+
await Promise.all(
|
|
30
|
+
Array.from({ length: 10 }, () =>
|
|
31
|
+
incrementCallTokenUsage("CA-usage-2", {
|
|
32
|
+
provider: "xai",
|
|
33
|
+
textInputsCount: 1,
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const docs = await getCallTokenUsageCollection()
|
|
39
|
+
.find({ callSid: "CA-usage-2" })
|
|
40
|
+
.toArray();
|
|
41
|
+
expect(docs).toHaveLength(1);
|
|
42
|
+
expect(docs[0].textInputsCount).toBe(10);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should not write zero counters", async () => {
|
|
46
|
+
await incrementCallTokenUsage("CA-usage-3", {
|
|
47
|
+
provider: "gemini",
|
|
48
|
+
inputTokens: 3,
|
|
49
|
+
outputTokens: 0,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const usage = await getCallTokenUsageCollection().findOne({
|
|
53
|
+
callSid: "CA-usage-3",
|
|
54
|
+
});
|
|
55
|
+
expect(usage).not.toHaveProperty("outputTokens");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Db, UpdateFilter } from "mongodb";
|
|
2
|
+
import { getDb } from "../index";
|
|
3
|
+
import { CallTokenUsage, CallTokenUsageDoc } from "./callTokenUsage.types";
|
|
4
|
+
|
|
5
|
+
export const getCallTokenUsageCollection = () => {
|
|
6
|
+
return getDb().collection<CallTokenUsageDoc>("callTokenUsage");
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// Unique callSid, so concurrent first reports of a call upsert one document, not several.
|
|
10
|
+
const callSidIndexByDb = new WeakMap<Db, Promise<string>>();
|
|
11
|
+
|
|
12
|
+
const ensureCallSidIndex = (): Promise<string> => {
|
|
13
|
+
const db = getDb();
|
|
14
|
+
let index = callSidIndexByDb.get(db);
|
|
15
|
+
if (!index) {
|
|
16
|
+
index = getCallTokenUsageCollection().createIndex(
|
|
17
|
+
{ callSid: 1 },
|
|
18
|
+
{ unique: true },
|
|
19
|
+
);
|
|
20
|
+
callSidIndexByDb.set(db, index);
|
|
21
|
+
}
|
|
22
|
+
return index;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const incrementCallTokenUsage = async (
|
|
26
|
+
callSid: string,
|
|
27
|
+
{ provider, model, ...counters }: CallTokenUsage,
|
|
28
|
+
): Promise<void> => {
|
|
29
|
+
await ensureCallSidIndex();
|
|
30
|
+
const now = new Date();
|
|
31
|
+
await getCallTokenUsageCollection().updateOne(
|
|
32
|
+
{ callSid },
|
|
33
|
+
{
|
|
34
|
+
$inc: Object.fromEntries(
|
|
35
|
+
Object.entries(counters).filter(([, value]) => (value ?? 0) > 0),
|
|
36
|
+
),
|
|
37
|
+
$set: { provider, ...(model && { model }), updatedAt: now },
|
|
38
|
+
$setOnInsert: { createdAt: now },
|
|
39
|
+
} as UpdateFilter<CallTokenUsageDoc>,
|
|
40
|
+
{ upsert: true },
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type CallTokenUsage = {
|
|
2
|
+
provider: string;
|
|
3
|
+
model?: string;
|
|
4
|
+
responsesCount?: number;
|
|
5
|
+
inputTokens?: number;
|
|
6
|
+
outputTokens?: number;
|
|
7
|
+
totalTokens?: number;
|
|
8
|
+
inputTextTokens?: number;
|
|
9
|
+
inputAudioTokens?: number;
|
|
10
|
+
inputImageTokens?: number;
|
|
11
|
+
cachedInputTokens?: number;
|
|
12
|
+
cachedInputTextTokens?: number;
|
|
13
|
+
cachedInputAudioTokens?: number;
|
|
14
|
+
cachedInputImageTokens?: number;
|
|
15
|
+
outputTextTokens?: number;
|
|
16
|
+
outputAudioTokens?: number;
|
|
17
|
+
thoughtsTokens?: number;
|
|
18
|
+
toolUseTokens?: number;
|
|
19
|
+
billableAudioSeconds?: number;
|
|
20
|
+
sessionSeconds?: number;
|
|
21
|
+
textInputsCount?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type CallTokenUsageDoc = CallTokenUsage & {
|
|
25
|
+
callSid: string;
|
|
26
|
+
createdAt: Date;
|
|
27
|
+
updatedAt: Date;
|
|
28
|
+
};
|
package/src/talkpilot/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./plans";
|
|
|
13
13
|
export * from "./subscriptions";
|
|
14
14
|
export * from "./groups";
|
|
15
15
|
export * from "./calls";
|
|
16
|
+
export * from "./callTokenUsage";
|
|
16
17
|
export * from "./clientAudioBuffers";
|
|
17
18
|
export * from "./clientsConfig";
|
|
18
19
|
export * from "./backgroundToolResults";
|