@opengeni/db 3.2.0-canary.0 → 3.4.0-canary.0
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/canonical-human-identities.js +3 -3
- package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
- package/dist/chunk-6DPJA36C.js.map +1 -0
- package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
- package/dist/chunk-C2AFP7SB.js.map +1 -0
- package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
- package/dist/chunk-H7MXYG7R.js.map +1 -0
- package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
- package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
- package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
- package/dist/chunk-PYMY3AJW.js.map +1 -0
- package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
- package/dist/chunk-TRBOWUG3.js.map +1 -0
- package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
- package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation.d.ts +16 -0
- package/dist/index.d.ts +108 -7
- package/dist/index.js +3605 -1417
- package/dist/index.js.map +1 -1
- package/dist/insights-model-bundle.d.ts +30 -0
- package/dist/insights-usage-bundle.d.ts +32 -0
- package/dist/insights.d.ts +10 -2
- package/dist/lossless-json.d.ts +1 -1
- package/dist/managed-user-setup.d.ts +82 -0
- package/dist/memory-domain.d.ts +2 -2
- package/dist/migrate.d.ts +3 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +4 -4
- package/dist/organization-membership-lifecycle.d.ts +60 -1
- package/dist/pr-review.d.ts +44 -3
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +12 -7
- package/dist/schema.d.ts +839 -101
- package/dist/schema.js +9 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-tenancy.d.ts +12 -1
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
- package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
- package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
- package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
- package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
- package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
- package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
- package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
- package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
- package/drizzle/0357_rig_platform_base_only.sql +44 -0
- package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
- package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
- package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
- package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
- package/package.json +6 -6
- package/src/database.ts +12 -8
- package/src/governed-learning-activation.ts +74 -2
- package/src/index.ts +879 -92
- package/src/insights-model-bundle.ts +681 -0
- package/src/insights-usage-bundle.ts +240 -0
- package/src/insights.ts +265 -152
- package/src/lossless-json.ts +2 -1
- package/src/managed-user-setup.ts +316 -0
- package/src/memory-domain.ts +3 -3
- package/src/migrate.ts +38 -14
- package/src/new-session-drafts.ts +22 -15
- package/src/organization-membership-lifecycle.ts +253 -1
- package/src/pr-review.ts +449 -6
- package/src/provision-roles.ts +92 -0
- package/src/runtime-posture.ts +247 -4
- package/src/schema.ts +210 -4
- package/src/session-tenancy.ts +120 -2
- package/dist/chunk-6HMM2R5T.js.map +0 -1
- package/dist/chunk-AZHW7R5V.js.map +0 -1
- package/dist/chunk-KRLPEMLH.js.map +0 -1
- package/dist/chunk-SIBYBA2D.js.map +0 -1
- package/dist/chunk-UZNXG44K.js.map +0 -1
- /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
- /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
- /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
- /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
package/src/insights.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { and, desc, eq, gte, inArray, lt, sql } from "drizzle-orm";
|
|
1
|
+
import { and, desc, eq, gt, gte, inArray, lt, sql } from "drizzle-orm";
|
|
2
2
|
import { alias } from "drizzle-orm/pg-core";
|
|
3
3
|
import type { Database } from "./database";
|
|
4
4
|
import { rlsContextForWorkspace, withRlsContext } from "./database";
|
|
5
5
|
import * as schema from "./schema";
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
export const INSIGHTS_WARM_GROUP_UUID_RE =
|
|
8
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
8
9
|
|
|
9
10
|
export type InsightsTimeWindow = {
|
|
10
11
|
since: Date;
|
|
@@ -119,6 +120,7 @@ export type RecentModelCallRow = {
|
|
|
119
120
|
recordedAt: Date;
|
|
120
121
|
sessionId: string;
|
|
121
122
|
sessionTitle: string | null;
|
|
123
|
+
sessionDepth: number | null;
|
|
122
124
|
turnId: string;
|
|
123
125
|
provider: string;
|
|
124
126
|
providerApi: string;
|
|
@@ -143,6 +145,62 @@ function hourKeyUtc(value: Date): string {
|
|
|
143
145
|
return `${value.toISOString().slice(0, 13)}:00`;
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
function insightsDate(value: unknown, field: string): Date {
|
|
149
|
+
const date = value instanceof Date ? value : new Date(String(value));
|
|
150
|
+
if (!Number.isFinite(date.getTime())) {
|
|
151
|
+
throw new Error(`Workspace Insights returned an invalid ${field}`);
|
|
152
|
+
}
|
|
153
|
+
return date;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function insightsNumber(value: unknown, field: string): number {
|
|
157
|
+
const number = typeof value === "number" ? value : Number(value);
|
|
158
|
+
if (!Number.isFinite(number)) {
|
|
159
|
+
throw new Error(`Workspace Insights returned an invalid ${field}`);
|
|
160
|
+
}
|
|
161
|
+
return number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function insightsNullableNumber(value: unknown, field: string): number | null {
|
|
165
|
+
return value === null ? null : insightsNumber(value, field);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function visibleUsageEventsSource(input: InsightsTimeWindow & { workspaceId: string }) {
|
|
169
|
+
const usageEvents = alias(schema.usageEvents, "insights_visible_usage_events");
|
|
170
|
+
return {
|
|
171
|
+
usageEvents,
|
|
172
|
+
source: sql`opengeni_private.visible_workspace_insights_usage_events(
|
|
173
|
+
${input.workspaceId},
|
|
174
|
+
${input.since.toISOString()}::timestamp with time zone,
|
|
175
|
+
${input.until.toISOString()}::timestamp with time zone
|
|
176
|
+
) "insights_visible_usage_events"`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function visibleUsageEventsSinceSource(input: { workspaceId: string; since: Date }) {
|
|
181
|
+
const usageEvents = alias(schema.usageEvents, "insights_visible_usage_events_since");
|
|
182
|
+
return {
|
|
183
|
+
usageEvents,
|
|
184
|
+
source: sql`opengeni_private.visible_workspace_insights_usage_events(
|
|
185
|
+
${input.workspaceId},
|
|
186
|
+
${input.since.toISOString()}::timestamp with time zone,
|
|
187
|
+
'infinity'::timestamp with time zone
|
|
188
|
+
) "insights_visible_usage_events_since"`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function visibleModelCallFactsSource(input: InsightsTimeWindow & { workspaceId: string }) {
|
|
193
|
+
const modelCallFacts = alias(schema.modelCallFacts, "insights_visible_model_call_facts");
|
|
194
|
+
return {
|
|
195
|
+
modelCallFacts,
|
|
196
|
+
source: sql`opengeni_private.visible_workspace_insights_model_call_facts(
|
|
197
|
+
${input.workspaceId},
|
|
198
|
+
${input.since.toISOString()}::timestamp with time zone,
|
|
199
|
+
${input.until.toISOString()}::timestamp with time zone
|
|
200
|
+
) "insights_visible_model_call_facts"`,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
146
204
|
export async function sumUsageQuantityInRange(
|
|
147
205
|
db: Database,
|
|
148
206
|
input: {
|
|
@@ -154,17 +212,46 @@ export async function sumUsageQuantityInRange(
|
|
|
154
212
|
): Promise<number> {
|
|
155
213
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
156
214
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
215
|
+
const { usageEvents, source } = visibleUsageEventsSource(input);
|
|
157
216
|
const [{ total } = { total: 0 }] = await scopedDb
|
|
158
217
|
.select({
|
|
159
|
-
total: sql<number>`coalesce(sum(${
|
|
218
|
+
total: sql<number>`coalesce(sum(${usageEvents.quantity}), 0)`,
|
|
160
219
|
})
|
|
161
|
-
.from(
|
|
220
|
+
.from(source)
|
|
162
221
|
.where(
|
|
163
222
|
and(
|
|
164
|
-
eq(
|
|
165
|
-
eq(
|
|
166
|
-
gte(
|
|
167
|
-
lt(
|
|
223
|
+
eq(usageEvents.workspaceId, input.workspaceId),
|
|
224
|
+
eq(usageEvents.eventType, input.eventType),
|
|
225
|
+
gte(usageEvents.occurredAt, input.since),
|
|
226
|
+
lt(usageEvents.occurredAt, input.until),
|
|
227
|
+
),
|
|
228
|
+
);
|
|
229
|
+
return Number(total);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Preserve the existing strictly-after boundary used by monthly cap meters. */
|
|
234
|
+
export async function sumUsageQuantitySinceForInsights(
|
|
235
|
+
db: Database,
|
|
236
|
+
input: {
|
|
237
|
+
workspaceId: string;
|
|
238
|
+
eventType: string;
|
|
239
|
+
since: Date;
|
|
240
|
+
},
|
|
241
|
+
): Promise<number> {
|
|
242
|
+
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
243
|
+
return await withRlsContext(db, context, async (scopedDb) => {
|
|
244
|
+
const { usageEvents, source } = visibleUsageEventsSinceSource(input);
|
|
245
|
+
const [{ total } = { total: 0 }] = await scopedDb
|
|
246
|
+
.select({
|
|
247
|
+
total: sql<number>`coalesce(sum(${usageEvents.quantity}), 0)`,
|
|
248
|
+
})
|
|
249
|
+
.from(source)
|
|
250
|
+
.where(
|
|
251
|
+
and(
|
|
252
|
+
eq(usageEvents.workspaceId, input.workspaceId),
|
|
253
|
+
eq(usageEvents.eventType, input.eventType),
|
|
254
|
+
gt(usageEvents.occurredAt, input.since),
|
|
168
255
|
),
|
|
169
256
|
);
|
|
170
257
|
return Number(total);
|
|
@@ -183,26 +270,27 @@ async function sumUsageQuantityByBucket(
|
|
|
183
270
|
): Promise<Map<string, number>> {
|
|
184
271
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
185
272
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
273
|
+
const { usageEvents, source } = visibleUsageEventsSource(input);
|
|
186
274
|
const bucket =
|
|
187
275
|
granularity === "hour"
|
|
188
|
-
? sql<string>`to_char(date_trunc('hour', ${
|
|
189
|
-
: sql<string>`to_char(date_trunc('day', ${
|
|
276
|
+
? sql<string>`to_char(date_trunc('hour', ${usageEvents.occurredAt} at time zone 'UTC'), 'YYYY-MM-DD"T"HH24:00')`
|
|
277
|
+
: sql<string>`to_char(date_trunc('day', ${usageEvents.occurredAt} at time zone 'UTC'), 'YYYY-MM-DD')`;
|
|
190
278
|
const bucketGroup =
|
|
191
279
|
granularity === "hour"
|
|
192
|
-
? sql`date_trunc('hour', ${
|
|
193
|
-
: sql`date_trunc('day', ${
|
|
280
|
+
? sql`date_trunc('hour', ${usageEvents.occurredAt} at time zone 'UTC')`
|
|
281
|
+
: sql`date_trunc('day', ${usageEvents.occurredAt} at time zone 'UTC')`;
|
|
194
282
|
const rows = await scopedDb
|
|
195
283
|
.select({
|
|
196
284
|
bucket,
|
|
197
|
-
total: sql<number>`coalesce(sum(${
|
|
285
|
+
total: sql<number>`coalesce(sum(${usageEvents.quantity}), 0)`,
|
|
198
286
|
})
|
|
199
|
-
.from(
|
|
287
|
+
.from(source)
|
|
200
288
|
.where(
|
|
201
289
|
and(
|
|
202
|
-
eq(
|
|
203
|
-
eq(
|
|
204
|
-
gte(
|
|
205
|
-
lt(
|
|
290
|
+
eq(usageEvents.workspaceId, input.workspaceId),
|
|
291
|
+
eq(usageEvents.eventType, input.eventType),
|
|
292
|
+
gte(usageEvents.occurredAt, input.since),
|
|
293
|
+
lt(usageEvents.occurredAt, input.until),
|
|
206
294
|
),
|
|
207
295
|
)
|
|
208
296
|
.groupBy(bucketGroup);
|
|
@@ -246,39 +334,36 @@ export async function aggregateModelCallFacts(
|
|
|
246
334
|
): Promise<ModelCallFactAggregateRow[]> {
|
|
247
335
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
248
336
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
337
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
249
338
|
const clauses = [
|
|
250
|
-
eq(
|
|
251
|
-
gte(
|
|
252
|
-
lt(
|
|
253
|
-
...(input.provider ? [eq(
|
|
254
|
-
...(input.model ? [eq(
|
|
339
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
340
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
341
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
342
|
+
...(input.provider ? [eq(modelCallFacts.provider, input.provider)] : []),
|
|
343
|
+
...(input.model ? [eq(modelCallFacts.model, input.model)] : []),
|
|
255
344
|
];
|
|
256
345
|
const rows = await scopedDb
|
|
257
346
|
.select({
|
|
258
|
-
provider:
|
|
259
|
-
model:
|
|
260
|
-
billingPath:
|
|
347
|
+
provider: sql<string>`${modelCallFacts.provider}`,
|
|
348
|
+
model: sql<string>`${modelCallFacts.model}`,
|
|
349
|
+
billingPath: sql<string>`${modelCallFacts.billingPath}`,
|
|
261
350
|
calls: sql<number>`count(*)::int`,
|
|
262
|
-
inputTokens: sql<number>`coalesce(sum(${
|
|
263
|
-
outputTokens: sql<number>`coalesce(sum(${
|
|
264
|
-
cachedTokens: sql<number>`coalesce(sum(${
|
|
265
|
-
cacheInputTokens: sql<number>`coalesce(sum(${
|
|
266
|
-
cacheWriteTokens: sql<number>`coalesce(sum(${
|
|
267
|
-
reasoningTokens: sql<number>`coalesce(sum(${
|
|
268
|
-
totalTokens: sql<number>`coalesce(sum(${
|
|
269
|
-
tokenKnownCalls: sql<number>`count(${
|
|
270
|
-
cacheKnownCalls: sql<number>`count(*) filter (where ${
|
|
271
|
-
pricedCostMicros: sql<number>`coalesce(sum(${
|
|
272
|
-
estimatedProviderCostMicros: sql<number>`coalesce(sum(${
|
|
273
|
-
estimatedProviderCostKnownCalls: sql<number>`count(${
|
|
351
|
+
inputTokens: sql<number>`coalesce(sum(${modelCallFacts.inputTokens}), 0)`,
|
|
352
|
+
outputTokens: sql<number>`coalesce(sum(${modelCallFacts.outputTokens}), 0)`,
|
|
353
|
+
cachedTokens: sql<number>`coalesce(sum(${modelCallFacts.cachedTokens}), 0)`,
|
|
354
|
+
cacheInputTokens: sql<number>`coalesce(sum(${modelCallFacts.inputTokens}) filter (where ${modelCallFacts.cachedTokens} is not null and ${modelCallFacts.inputTokens} is not null), 0)`,
|
|
355
|
+
cacheWriteTokens: sql<number>`coalesce(sum(${modelCallFacts.cacheWriteTokens}), 0)`,
|
|
356
|
+
reasoningTokens: sql<number>`coalesce(sum(${modelCallFacts.reasoningTokens}), 0)`,
|
|
357
|
+
totalTokens: sql<number>`coalesce(sum(${modelCallFacts.totalTokens}), 0)`,
|
|
358
|
+
tokenKnownCalls: sql<number>`count(${modelCallFacts.totalTokens})::int`,
|
|
359
|
+
cacheKnownCalls: sql<number>`count(*) filter (where ${modelCallFacts.cachedTokens} is not null and ${modelCallFacts.inputTokens} is not null)::int`,
|
|
360
|
+
pricedCostMicros: sql<number>`coalesce(sum(${modelCallFacts.pricedCostMicros}) filter (where ${modelCallFacts.billingPath} = 'opengeni_credits'), 0)`,
|
|
361
|
+
estimatedProviderCostMicros: sql<number>`coalesce(sum(${modelCallFacts.estimatedProviderCostMicros}), 0)`,
|
|
362
|
+
estimatedProviderCostKnownCalls: sql<number>`count(${modelCallFacts.estimatedProviderCostMicros})::int`,
|
|
274
363
|
})
|
|
275
|
-
.from(
|
|
364
|
+
.from(source)
|
|
276
365
|
.where(and(...clauses))
|
|
277
|
-
.groupBy(
|
|
278
|
-
schema.modelCallFacts.provider,
|
|
279
|
-
schema.modelCallFacts.model,
|
|
280
|
-
schema.modelCallFacts.billingPath,
|
|
281
|
-
);
|
|
366
|
+
.groupBy(modelCallFacts.provider, modelCallFacts.model, modelCallFacts.billingPath);
|
|
282
367
|
return rows.map((row) => ({
|
|
283
368
|
provider: row.provider,
|
|
284
369
|
model: row.model,
|
|
@@ -300,7 +385,7 @@ export async function aggregateModelCallFacts(
|
|
|
300
385
|
});
|
|
301
386
|
}
|
|
302
387
|
|
|
303
|
-
type ModelCallFactSeriesAggregate = {
|
|
388
|
+
export type ModelCallFactSeriesAggregate = {
|
|
304
389
|
costMicros: number;
|
|
305
390
|
estimatedProviderCostMicros: number;
|
|
306
391
|
estimatedProviderCostKnownCalls: number;
|
|
@@ -329,39 +414,40 @@ async function aggregateModelCallFactsByBucket(
|
|
|
329
414
|
): Promise<Map<string, ModelCallFactSeriesAggregate>> {
|
|
330
415
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
331
416
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
417
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
332
418
|
const clauses = [
|
|
333
|
-
eq(
|
|
334
|
-
gte(
|
|
335
|
-
lt(
|
|
336
|
-
...(input.provider ? [eq(
|
|
337
|
-
...(input.model ? [eq(
|
|
419
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
420
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
421
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
422
|
+
...(input.provider ? [eq(modelCallFacts.provider, input.provider)] : []),
|
|
423
|
+
...(input.model ? [eq(modelCallFacts.model, input.model)] : []),
|
|
338
424
|
];
|
|
339
425
|
const bucket =
|
|
340
426
|
granularity === "hour"
|
|
341
|
-
? sql<string>`to_char(date_trunc('hour', ${
|
|
342
|
-
: sql<string>`to_char(date_trunc('day', ${
|
|
427
|
+
? sql<string>`to_char(date_trunc('hour', ${modelCallFacts.occurredAt} at time zone 'UTC'), 'YYYY-MM-DD"T"HH24:00')`
|
|
428
|
+
: sql<string>`to_char(date_trunc('day', ${modelCallFacts.occurredAt} at time zone 'UTC'), 'YYYY-MM-DD')`;
|
|
343
429
|
const bucketGroup =
|
|
344
430
|
granularity === "hour"
|
|
345
|
-
? sql`date_trunc('hour', ${
|
|
346
|
-
: sql`date_trunc('day', ${
|
|
431
|
+
? sql`date_trunc('hour', ${modelCallFacts.occurredAt} at time zone 'UTC')`
|
|
432
|
+
: sql`date_trunc('day', ${modelCallFacts.occurredAt} at time zone 'UTC')`;
|
|
347
433
|
const rows = await scopedDb
|
|
348
434
|
.select({
|
|
349
435
|
bucket,
|
|
350
|
-
costMicros: sql<number>`coalesce(sum(${
|
|
351
|
-
estimatedProviderCostMicros: sql<number>`coalesce(sum(${
|
|
352
|
-
estimatedProviderCostKnownCalls: sql<number>`count(${
|
|
353
|
-
inputTokens: sql<number>`coalesce(sum(${
|
|
354
|
-
outputTokens: sql<number>`coalesce(sum(${
|
|
355
|
-
cachedTokens: sql<number>`coalesce(sum(${
|
|
356
|
-
cacheInputTokens: sql<number>`coalesce(sum(${
|
|
357
|
-
cacheWriteTokens: sql<number>`coalesce(sum(${
|
|
358
|
-
reasoningTokens: sql<number>`coalesce(sum(${
|
|
359
|
-
totalTokens: sql<number>`coalesce(sum(${
|
|
360
|
-
tokenKnownCalls: sql<number>`count(${
|
|
361
|
-
cacheKnownCalls: sql<number>`count(*) filter (where ${
|
|
436
|
+
costMicros: sql<number>`coalesce(sum(${modelCallFacts.pricedCostMicros}) filter (where ${modelCallFacts.billingPath} = 'opengeni_credits'), 0)`,
|
|
437
|
+
estimatedProviderCostMicros: sql<number>`coalesce(sum(${modelCallFacts.estimatedProviderCostMicros}), 0)`,
|
|
438
|
+
estimatedProviderCostKnownCalls: sql<number>`count(${modelCallFacts.estimatedProviderCostMicros})::int`,
|
|
439
|
+
inputTokens: sql<number>`coalesce(sum(${modelCallFacts.inputTokens}), 0)`,
|
|
440
|
+
outputTokens: sql<number>`coalesce(sum(${modelCallFacts.outputTokens}), 0)`,
|
|
441
|
+
cachedTokens: sql<number>`coalesce(sum(${modelCallFacts.cachedTokens}), 0)`,
|
|
442
|
+
cacheInputTokens: sql<number>`coalesce(sum(${modelCallFacts.inputTokens}) filter (where ${modelCallFacts.cachedTokens} is not null and ${modelCallFacts.inputTokens} is not null), 0)`,
|
|
443
|
+
cacheWriteTokens: sql<number>`coalesce(sum(${modelCallFacts.cacheWriteTokens}), 0)`,
|
|
444
|
+
reasoningTokens: sql<number>`coalesce(sum(${modelCallFacts.reasoningTokens}), 0)`,
|
|
445
|
+
totalTokens: sql<number>`coalesce(sum(${modelCallFacts.totalTokens}), 0)`,
|
|
446
|
+
tokenKnownCalls: sql<number>`count(${modelCallFacts.totalTokens})::int`,
|
|
447
|
+
cacheKnownCalls: sql<number>`count(*) filter (where ${modelCallFacts.cachedTokens} is not null and ${modelCallFacts.inputTokens} is not null)::int`,
|
|
362
448
|
calls: sql<number>`count(*)::int`,
|
|
363
449
|
})
|
|
364
|
-
.from(
|
|
450
|
+
.from(source)
|
|
365
451
|
.where(and(...clauses))
|
|
366
452
|
.groupBy(bucketGroup);
|
|
367
453
|
return new Map(
|
|
@@ -420,26 +506,27 @@ export async function aggregateWarmSecondsByGroup(
|
|
|
420
506
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
421
507
|
const limit = input.limit ?? 24;
|
|
422
508
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
509
|
+
const { usageEvents, source } = visibleUsageEventsSource(input);
|
|
423
510
|
const rows = await scopedDb
|
|
424
511
|
.select({
|
|
425
|
-
groupId: sql<string>`split_part(${
|
|
426
|
-
warmSeconds: sql<number>`coalesce(sum(${
|
|
512
|
+
groupId: sql<string>`split_part(${usageEvents.sourceResourceId}, ':', 1)`,
|
|
513
|
+
warmSeconds: sql<number>`coalesce(sum(${usageEvents.quantity}), 0)`,
|
|
427
514
|
})
|
|
428
|
-
.from(
|
|
515
|
+
.from(source)
|
|
429
516
|
.where(
|
|
430
517
|
and(
|
|
431
|
-
eq(
|
|
432
|
-
eq(
|
|
433
|
-
gte(
|
|
434
|
-
lt(
|
|
435
|
-
sql`${
|
|
518
|
+
eq(usageEvents.workspaceId, input.workspaceId),
|
|
519
|
+
eq(usageEvents.eventType, "sandbox.warm_seconds"),
|
|
520
|
+
gte(usageEvents.occurredAt, input.since),
|
|
521
|
+
lt(usageEvents.occurredAt, input.until),
|
|
522
|
+
sql`${usageEvents.sourceResourceId} is not null`,
|
|
436
523
|
),
|
|
437
524
|
)
|
|
438
|
-
.groupBy(sql`split_part(${
|
|
439
|
-
.orderBy(sql`coalesce(sum(${
|
|
525
|
+
.groupBy(sql`split_part(${usageEvents.sourceResourceId}, ':', 1)`)
|
|
526
|
+
.orderBy(sql`coalesce(sum(${usageEvents.quantity}), 0) desc`)
|
|
440
527
|
.limit(Math.max(limit * 4, limit));
|
|
441
528
|
return rows
|
|
442
|
-
.filter((row) =>
|
|
529
|
+
.filter((row) => INSIGHTS_WARM_GROUP_UUID_RE.test(row.groupId))
|
|
443
530
|
.slice(0, limit)
|
|
444
531
|
.map((row) => ({
|
|
445
532
|
groupId: row.groupId,
|
|
@@ -527,31 +614,32 @@ export async function aggregateRootSessionDrivers(
|
|
|
527
614
|
const childSessions = alias(schema.sessions, "insight_child_sessions");
|
|
528
615
|
const rootSessions = alias(schema.sessions, "insight_root_sessions");
|
|
529
616
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
617
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
530
618
|
const clauses = [
|
|
531
|
-
eq(
|
|
532
|
-
gte(
|
|
533
|
-
lt(
|
|
534
|
-
...(input.provider ? [eq(
|
|
535
|
-
...(input.model ? [eq(
|
|
619
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
620
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
621
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
622
|
+
...(input.provider ? [eq(modelCallFacts.provider, input.provider)] : []),
|
|
623
|
+
...(input.model ? [eq(modelCallFacts.model, input.model)] : []),
|
|
536
624
|
...(input.rootSessionIds ? [inArray(childSessions.rootSessionId, input.rootSessionIds)] : []),
|
|
537
625
|
];
|
|
538
626
|
const query = scopedDb
|
|
539
627
|
.select({
|
|
540
628
|
rootSessionId: childSessions.rootSessionId,
|
|
541
629
|
title: rootSessions.title,
|
|
542
|
-
pricedCostMicros: sql<number>`coalesce(sum(${
|
|
543
|
-
estimatedProviderCostMicros: sql<number>`coalesce(sum(${
|
|
544
|
-
estimatedProviderCostKnownCalls: sql<number>`count(${
|
|
545
|
-
totalTokens: sql<number>`coalesce(sum(${
|
|
546
|
-
cachedTokens: sql<number>`coalesce(sum(${
|
|
547
|
-
cacheInputTokens: sql<number>`coalesce(sum(${
|
|
630
|
+
pricedCostMicros: sql<number>`coalesce(sum(${modelCallFacts.pricedCostMicros}) filter (where ${modelCallFacts.billingPath} = 'opengeni_credits'), 0)`,
|
|
631
|
+
estimatedProviderCostMicros: sql<number>`coalesce(sum(${modelCallFacts.estimatedProviderCostMicros}), 0)`,
|
|
632
|
+
estimatedProviderCostKnownCalls: sql<number>`count(${modelCallFacts.estimatedProviderCostMicros})::int`,
|
|
633
|
+
totalTokens: sql<number>`coalesce(sum(${modelCallFacts.totalTokens}), 0)`,
|
|
634
|
+
cachedTokens: sql<number>`coalesce(sum(${modelCallFacts.cachedTokens}), 0)`,
|
|
635
|
+
cacheInputTokens: sql<number>`coalesce(sum(${modelCallFacts.inputTokens}) filter (where ${modelCallFacts.cachedTokens} is not null and ${modelCallFacts.inputTokens} is not null), 0)`,
|
|
548
636
|
})
|
|
549
|
-
.from(
|
|
637
|
+
.from(source)
|
|
550
638
|
.innerJoin(
|
|
551
639
|
childSessions,
|
|
552
640
|
and(
|
|
553
|
-
eq(childSessions.workspaceId,
|
|
554
|
-
eq(childSessions.id,
|
|
641
|
+
eq(childSessions.workspaceId, modelCallFacts.workspaceId),
|
|
642
|
+
eq(childSessions.id, modelCallFacts.sessionId),
|
|
555
643
|
),
|
|
556
644
|
)
|
|
557
645
|
.leftJoin(
|
|
@@ -563,7 +651,7 @@ export async function aggregateRootSessionDrivers(
|
|
|
563
651
|
)
|
|
564
652
|
.where(and(...clauses))
|
|
565
653
|
.groupBy(childSessions.rootSessionId, rootSessions.title)
|
|
566
|
-
.orderBy(sql`coalesce(sum(${
|
|
654
|
+
.orderBy(sql`coalesce(sum(${modelCallFacts.totalTokens}), 0) desc`);
|
|
567
655
|
const rows = input.rootSessionIds ? await query : await query.limit(input.limit ?? 8);
|
|
568
656
|
return rows.map((row) => ({
|
|
569
657
|
rootSessionId: row.rootSessionId,
|
|
@@ -584,20 +672,21 @@ export async function listModelCallFacets(
|
|
|
584
672
|
): Promise<ModelCallFacetRow[]> {
|
|
585
673
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
586
674
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
675
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
587
676
|
const rows = await scopedDb
|
|
588
677
|
.selectDistinct({
|
|
589
|
-
provider:
|
|
590
|
-
model:
|
|
678
|
+
provider: sql<string>`${modelCallFacts.provider}`,
|
|
679
|
+
model: sql<string>`${modelCallFacts.model}`,
|
|
591
680
|
})
|
|
592
|
-
.from(
|
|
681
|
+
.from(source)
|
|
593
682
|
.where(
|
|
594
683
|
and(
|
|
595
|
-
eq(
|
|
596
|
-
gte(
|
|
597
|
-
lt(
|
|
684
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
685
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
686
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
598
687
|
),
|
|
599
688
|
)
|
|
600
|
-
.orderBy(
|
|
689
|
+
.orderBy(modelCallFacts.provider, modelCallFacts.model)
|
|
601
690
|
.limit(500);
|
|
602
691
|
return rows;
|
|
603
692
|
});
|
|
@@ -615,47 +704,66 @@ export async function listRecentModelCalls(
|
|
|
615
704
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
616
705
|
const factSessions = alias(schema.sessions, "insight_recent_fact_sessions");
|
|
617
706
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
707
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
618
708
|
const clauses = [
|
|
619
|
-
eq(
|
|
620
|
-
gte(
|
|
621
|
-
lt(
|
|
622
|
-
...(input.provider ? [eq(
|
|
623
|
-
...(input.model ? [eq(
|
|
709
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
710
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
711
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
712
|
+
...(input.provider ? [eq(modelCallFacts.provider, input.provider)] : []),
|
|
713
|
+
...(input.model ? [eq(modelCallFacts.model, input.model)] : []),
|
|
624
714
|
];
|
|
625
715
|
const rows = await scopedDb
|
|
626
716
|
.select({
|
|
627
|
-
id:
|
|
628
|
-
occurredAt:
|
|
629
|
-
recordedAt:
|
|
630
|
-
sessionId:
|
|
717
|
+
id: sql<string>`${modelCallFacts.id}`,
|
|
718
|
+
occurredAt: sql<Date>`${modelCallFacts.occurredAt}`,
|
|
719
|
+
recordedAt: sql<Date>`${modelCallFacts.recordedAt}`,
|
|
720
|
+
sessionId: sql<string>`${modelCallFacts.sessionId}`,
|
|
631
721
|
sessionTitle: factSessions.title,
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
722
|
+
sessionDepth: factSessions.nestedAgentDepth,
|
|
723
|
+
turnId: sql<string>`${modelCallFacts.turnId}`,
|
|
724
|
+
provider: sql<string>`${modelCallFacts.provider}`,
|
|
725
|
+
providerApi: sql<string>`${modelCallFacts.providerApi}`,
|
|
726
|
+
model: sql<string>`${modelCallFacts.model}`,
|
|
727
|
+
billingPath: sql<string>`${modelCallFacts.billingPath}`,
|
|
728
|
+
inputTokens: sql<number | null>`${modelCallFacts.inputTokens}`,
|
|
729
|
+
outputTokens: sql<number | null>`${modelCallFacts.outputTokens}`,
|
|
730
|
+
cachedTokens: sql<number | null>`${modelCallFacts.cachedTokens}`,
|
|
731
|
+
cacheWriteTokens: sql<number | null>`${modelCallFacts.cacheWriteTokens}`,
|
|
732
|
+
reasoningTokens: sql<number | null>`${modelCallFacts.reasoningTokens}`,
|
|
733
|
+
totalTokens: sql<number | null>`${modelCallFacts.totalTokens}`,
|
|
734
|
+
pricedCostMicros: sql<number>`${modelCallFacts.pricedCostMicros}`,
|
|
735
|
+
estimatedProviderCostMicros: sql<
|
|
736
|
+
number | null
|
|
737
|
+
>`${modelCallFacts.estimatedProviderCostMicros}`,
|
|
738
|
+
pricingSource: sql<string | null>`${modelCallFacts.pricingSource}`,
|
|
646
739
|
})
|
|
647
|
-
.from(
|
|
740
|
+
.from(source)
|
|
648
741
|
.leftJoin(
|
|
649
742
|
factSessions,
|
|
650
743
|
and(
|
|
651
|
-
eq(factSessions.workspaceId,
|
|
652
|
-
eq(factSessions.id,
|
|
744
|
+
eq(factSessions.workspaceId, modelCallFacts.workspaceId),
|
|
745
|
+
eq(factSessions.id, modelCallFacts.sessionId),
|
|
653
746
|
),
|
|
654
747
|
)
|
|
655
748
|
.where(and(...clauses))
|
|
656
|
-
.orderBy(desc(
|
|
749
|
+
.orderBy(desc(modelCallFacts.occurredAt), desc(modelCallFacts.id))
|
|
657
750
|
.limit(Math.max(1, Math.min(input.limit ?? 50, 100)));
|
|
658
|
-
return rows
|
|
751
|
+
return rows.map((row) => ({
|
|
752
|
+
...row,
|
|
753
|
+
occurredAt: insightsDate(row.occurredAt, "model-call occurrence timestamp"),
|
|
754
|
+
recordedAt: insightsDate(row.recordedAt, "model-call recording timestamp"),
|
|
755
|
+
inputTokens: insightsNullableNumber(row.inputTokens, "input token count"),
|
|
756
|
+
outputTokens: insightsNullableNumber(row.outputTokens, "output token count"),
|
|
757
|
+
cachedTokens: insightsNullableNumber(row.cachedTokens, "cached token count"),
|
|
758
|
+
cacheWriteTokens: insightsNullableNumber(row.cacheWriteTokens, "cache-write token count"),
|
|
759
|
+
reasoningTokens: insightsNullableNumber(row.reasoningTokens, "reasoning token count"),
|
|
760
|
+
totalTokens: insightsNullableNumber(row.totalTokens, "total token count"),
|
|
761
|
+
pricedCostMicros: insightsNumber(row.pricedCostMicros, "priced cost"),
|
|
762
|
+
estimatedProviderCostMicros: insightsNullableNumber(
|
|
763
|
+
row.estimatedProviderCostMicros,
|
|
764
|
+
"estimated provider cost",
|
|
765
|
+
),
|
|
766
|
+
}));
|
|
659
767
|
});
|
|
660
768
|
}
|
|
661
769
|
|
|
@@ -669,12 +777,13 @@ export async function aggregateModelContextContributions(
|
|
|
669
777
|
): Promise<ModelContextContributionAggregate> {
|
|
670
778
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
671
779
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
780
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
672
781
|
const clauses = [
|
|
673
|
-
eq(
|
|
674
|
-
gte(
|
|
675
|
-
lt(
|
|
676
|
-
...(input.provider ? [eq(
|
|
677
|
-
...(input.model ? [eq(
|
|
782
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
783
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
784
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
785
|
+
...(input.provider ? [eq(modelCallFacts.provider, input.provider)] : []),
|
|
786
|
+
...(input.model ? [eq(modelCallFacts.model, input.model)] : []),
|
|
678
787
|
];
|
|
679
788
|
type ContributionRow = {
|
|
680
789
|
total_calls: number | string;
|
|
@@ -688,9 +797,9 @@ export async function aggregateModelContextContributions(
|
|
|
688
797
|
const rows = (await scopedDb.execute(sql<ContributionRow>`
|
|
689
798
|
with filtered as (
|
|
690
799
|
select
|
|
691
|
-
${
|
|
692
|
-
${
|
|
693
|
-
from ${
|
|
800
|
+
${modelCallFacts.id} as id,
|
|
801
|
+
${modelCallFacts.contextContributions} as context_contributions
|
|
802
|
+
from ${source}
|
|
694
803
|
where ${and(...clauses)}
|
|
695
804
|
), coverage as (
|
|
696
805
|
select
|
|
@@ -762,33 +871,34 @@ export async function aggregateScheduleFacts(
|
|
|
762
871
|
): Promise<ScheduleFactAggregate[]> {
|
|
763
872
|
const context = await rlsContextForWorkspace(db, input.workspaceId);
|
|
764
873
|
return await withRlsContext(db, context, async (scopedDb) => {
|
|
874
|
+
const { modelCallFacts, source } = visibleModelCallFactsSource(input);
|
|
765
875
|
const clauses = [
|
|
766
|
-
eq(
|
|
767
|
-
gte(
|
|
768
|
-
lt(
|
|
769
|
-
sql`${
|
|
770
|
-
...(input.provider ? [eq(
|
|
771
|
-
...(input.model ? [eq(
|
|
876
|
+
eq(modelCallFacts.workspaceId, input.workspaceId),
|
|
877
|
+
gte(modelCallFacts.occurredAt, input.since),
|
|
878
|
+
lt(modelCallFacts.occurredAt, input.until),
|
|
879
|
+
sql`${modelCallFacts.scheduledTaskId} is not null`,
|
|
880
|
+
...(input.provider ? [eq(modelCallFacts.provider, input.provider)] : []),
|
|
881
|
+
...(input.model ? [eq(modelCallFacts.model, input.model)] : []),
|
|
772
882
|
];
|
|
773
883
|
const rows = await scopedDb
|
|
774
884
|
.select({
|
|
775
|
-
scheduledTaskId:
|
|
776
|
-
pricedCostMicros: sql<number>`coalesce(sum(${
|
|
777
|
-
estimatedProviderCostMicros: sql<number>`coalesce(sum(${
|
|
778
|
-
estimatedProviderCostKnownCalls: sql<number>`count(${
|
|
779
|
-
totalTokens: sql<number>`coalesce(sum(${
|
|
780
|
-
cachedTokens: sql<number>`coalesce(sum(${
|
|
781
|
-
cacheInputTokens: sql<number>`coalesce(sum(${
|
|
885
|
+
scheduledTaskId: sql<string | null>`${modelCallFacts.scheduledTaskId}`,
|
|
886
|
+
pricedCostMicros: sql<number>`coalesce(sum(${modelCallFacts.pricedCostMicros}) filter (where ${modelCallFacts.billingPath} = 'opengeni_credits'), 0)`,
|
|
887
|
+
estimatedProviderCostMicros: sql<number>`coalesce(sum(${modelCallFacts.estimatedProviderCostMicros}), 0)`,
|
|
888
|
+
estimatedProviderCostKnownCalls: sql<number>`count(${modelCallFacts.estimatedProviderCostMicros})::int`,
|
|
889
|
+
totalTokens: sql<number>`coalesce(sum(${modelCallFacts.totalTokens}), 0)`,
|
|
890
|
+
cachedTokens: sql<number>`coalesce(sum(${modelCallFacts.cachedTokens}), 0)`,
|
|
891
|
+
cacheInputTokens: sql<number>`coalesce(sum(${modelCallFacts.inputTokens}) filter (where ${modelCallFacts.cachedTokens} is not null and ${modelCallFacts.inputTokens} is not null), 0)`,
|
|
782
892
|
calls: sql<number>`count(*)::int`,
|
|
783
893
|
billingPath: sql<string>`case
|
|
784
|
-
when bool_or(${
|
|
894
|
+
when bool_or(${modelCallFacts.billingPath} = 'opengeni_credits')
|
|
785
895
|
then 'opengeni_credits'
|
|
786
896
|
else 'external'
|
|
787
897
|
end`,
|
|
788
898
|
})
|
|
789
|
-
.from(
|
|
899
|
+
.from(source)
|
|
790
900
|
.where(and(...clauses))
|
|
791
|
-
.groupBy(
|
|
901
|
+
.groupBy(modelCallFacts.scheduledTaskId);
|
|
792
902
|
return rows
|
|
793
903
|
.filter((row): row is typeof row & { scheduledTaskId: string } => row.scheduledTaskId != null)
|
|
794
904
|
.map((row) => ({
|
|
@@ -839,6 +949,7 @@ export async function aggregateSessionDepth(
|
|
|
839
949
|
sessionsTouched: number;
|
|
840
950
|
rootSessions: number;
|
|
841
951
|
deepestDepth: number;
|
|
952
|
+
deepestSessionId: string | null;
|
|
842
953
|
deepestSessionTitle: string;
|
|
843
954
|
avgDepth: number;
|
|
844
955
|
goalsActive: number;
|
|
@@ -866,6 +977,7 @@ export async function aggregateSessionDepth(
|
|
|
866
977
|
.where(eq(schema.sessions.workspaceId, workspaceId));
|
|
867
978
|
const [deepest] = await scopedDb
|
|
868
979
|
.select({
|
|
980
|
+
id: schema.sessions.id,
|
|
869
981
|
title: schema.sessions.title,
|
|
870
982
|
depth: schema.sessions.nestedAgentDepth,
|
|
871
983
|
})
|
|
@@ -888,6 +1000,7 @@ export async function aggregateSessionDepth(
|
|
|
888
1000
|
sessionsTouched: Number(stats?.sessionsTouched ?? 0),
|
|
889
1001
|
rootSessions: Number(stats?.rootSessions ?? 0),
|
|
890
1002
|
deepestDepth: Number(stats?.deepestDepth ?? 0),
|
|
1003
|
+
deepestSessionId: deepest?.id ?? null,
|
|
891
1004
|
deepestSessionTitle: deepest?.title?.trim() || "",
|
|
892
1005
|
avgDepth: Number(stats?.avgDepth ?? 0),
|
|
893
1006
|
goalsActive: Number(goals?.active ?? 0),
|
package/src/lossless-json.ts
CHANGED
|
@@ -9,7 +9,8 @@ const MAX_JSON_DEPTH = 512;
|
|
|
9
9
|
* column and must never be decoded based on content shape alone.
|
|
10
10
|
*/
|
|
11
11
|
export const LOSSLESS_CONTENT_CODEC_VERSION = 1 as const;
|
|
12
|
-
export const LOSSLESS_CONTENT_WRITER_APPLICATION_NAME =
|
|
12
|
+
export const LOSSLESS_CONTENT_WRITER_APPLICATION_NAME =
|
|
13
|
+
"opengeni-lossless-v1-session-variable-sets-v1";
|
|
13
14
|
|
|
14
15
|
export function withLosslessContentWriteVersion<
|
|
15
16
|
const ContentKey extends string,
|