@sentry/junior 0.102.1 → 0.102.3
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/cli/upgrade.js +286 -0
- package/migrations/meta/_journal.json +1 -1
- package/package.json +5 -5
package/dist/cli/upgrade.js
CHANGED
|
@@ -1310,6 +1310,291 @@ var agentTurnSessionActorMigration = {
|
|
|
1310
1310
|
run: migrateAgentTurnSessionActor
|
|
1311
1311
|
};
|
|
1312
1312
|
|
|
1313
|
+
// src/cli/upgrade/migrations/conversation-usage.ts
|
|
1314
|
+
var CONVERSATION_USAGE_REPAIR_BATCH_SIZE = 500;
|
|
1315
|
+
var MAX_SAFE_INTEGER = 9007199254740991;
|
|
1316
|
+
var MAX_FINITE_DOUBLE = "1.7976931348623157e308";
|
|
1317
|
+
var REPAIR_LOCK = "junior:upgrade:repair-conversation-usage";
|
|
1318
|
+
var USAGE_REPAIR_BATCH_SQL = `
|
|
1319
|
+
WITH candidates AS MATERIALIZED (
|
|
1320
|
+
SELECT
|
|
1321
|
+
conversation_id,
|
|
1322
|
+
updated_at,
|
|
1323
|
+
execution_updated_at
|
|
1324
|
+
FROM junior_conversations
|
|
1325
|
+
WHERE parent_conversation_id IS NULL
|
|
1326
|
+
AND execution_status = 'idle'
|
|
1327
|
+
AND conversation_id > $1
|
|
1328
|
+
ORDER BY conversation_id
|
|
1329
|
+
LIMIT $2
|
|
1330
|
+
),
|
|
1331
|
+
-- Occurrence numbers preserve intentional duplicates within one epoch while
|
|
1332
|
+
-- collapsing context copies of the same message across rebuilt epochs.
|
|
1333
|
+
message_occurrences AS (
|
|
1334
|
+
SELECT
|
|
1335
|
+
step.conversation_id,
|
|
1336
|
+
step.payload -> 'message' AS message,
|
|
1337
|
+
row_number() OVER (
|
|
1338
|
+
PARTITION BY
|
|
1339
|
+
step.conversation_id,
|
|
1340
|
+
step.context_epoch,
|
|
1341
|
+
step.payload -> 'message'
|
|
1342
|
+
ORDER BY step.seq
|
|
1343
|
+
) AS occurrence
|
|
1344
|
+
FROM junior_agent_steps AS step
|
|
1345
|
+
INNER JOIN candidates AS candidate
|
|
1346
|
+
ON candidate.conversation_id = step.conversation_id
|
|
1347
|
+
WHERE step.type = 'pi_message'
|
|
1348
|
+
AND step.role = 'assistant'
|
|
1349
|
+
AND jsonb_typeof(step.payload -> 'message' -> 'usage') = 'object'
|
|
1350
|
+
),
|
|
1351
|
+
canonical_messages AS (
|
|
1352
|
+
SELECT DISTINCT conversation_id, message, occurrence
|
|
1353
|
+
FROM message_occurrences
|
|
1354
|
+
),
|
|
1355
|
+
usage_values AS (
|
|
1356
|
+
SELECT
|
|
1357
|
+
conversation_id,
|
|
1358
|
+
CASE
|
|
1359
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'input') = 'number'
|
|
1360
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'input')::numeric))
|
|
1361
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'inputTokens') = 'number'
|
|
1362
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'inputTokens')::numeric))
|
|
1363
|
+
END AS input_tokens,
|
|
1364
|
+
CASE
|
|
1365
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'output') = 'number'
|
|
1366
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'output')::numeric))
|
|
1367
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'outputTokens') = 'number'
|
|
1368
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'outputTokens')::numeric))
|
|
1369
|
+
END AS output_tokens,
|
|
1370
|
+
CASE
|
|
1371
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cacheRead') = 'number'
|
|
1372
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cacheRead')::numeric))
|
|
1373
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cachedInputTokens') = 'number'
|
|
1374
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cachedInputTokens')::numeric))
|
|
1375
|
+
END AS cached_input_tokens,
|
|
1376
|
+
CASE
|
|
1377
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cacheWrite') = 'number'
|
|
1378
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cacheWrite')::numeric))
|
|
1379
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cacheCreationTokens') = 'number'
|
|
1380
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cacheCreationTokens')::numeric))
|
|
1381
|
+
END AS cache_creation_tokens,
|
|
1382
|
+
CASE
|
|
1383
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'reasoning') = 'number'
|
|
1384
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'reasoning')::numeric))
|
|
1385
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'reasoningTokens') = 'number'
|
|
1386
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'reasoningTokens')::numeric))
|
|
1387
|
+
END AS reasoning_tokens,
|
|
1388
|
+
CASE
|
|
1389
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'totalTokens') = 'number'
|
|
1390
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'totalTokens')::numeric))
|
|
1391
|
+
END AS total_tokens,
|
|
1392
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'input') = 'number'
|
|
1393
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'input')::numeric)
|
|
1394
|
+
END AS cost_input,
|
|
1395
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'output') = 'number'
|
|
1396
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'output')::numeric)
|
|
1397
|
+
END AS cost_output,
|
|
1398
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'cacheRead') = 'number'
|
|
1399
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'cacheRead')::numeric)
|
|
1400
|
+
END AS cost_cache_read,
|
|
1401
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'cacheWrite') = 'number'
|
|
1402
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'cacheWrite')::numeric)
|
|
1403
|
+
END AS cost_cache_write,
|
|
1404
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'total') = 'number'
|
|
1405
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'total')::numeric)
|
|
1406
|
+
END AS cost_total
|
|
1407
|
+
FROM canonical_messages
|
|
1408
|
+
),
|
|
1409
|
+
rollups AS (
|
|
1410
|
+
SELECT
|
|
1411
|
+
conversation_id,
|
|
1412
|
+
sum(input_tokens) AS input_tokens,
|
|
1413
|
+
sum(output_tokens) AS output_tokens,
|
|
1414
|
+
sum(cached_input_tokens) AS cached_input_tokens,
|
|
1415
|
+
sum(cache_creation_tokens) AS cache_creation_tokens,
|
|
1416
|
+
sum(reasoning_tokens) AS reasoning_tokens,
|
|
1417
|
+
sum(
|
|
1418
|
+
CASE
|
|
1419
|
+
WHEN input_tokens IS NULL
|
|
1420
|
+
AND output_tokens IS NULL
|
|
1421
|
+
AND cached_input_tokens IS NULL
|
|
1422
|
+
AND cache_creation_tokens IS NULL
|
|
1423
|
+
THEN total_tokens
|
|
1424
|
+
END
|
|
1425
|
+
) AS total_only_tokens,
|
|
1426
|
+
round(sum(cost_input), 12) AS cost_input,
|
|
1427
|
+
round(sum(cost_output), 12) AS cost_output,
|
|
1428
|
+
round(sum(cost_cache_read), 12) AS cost_cache_read,
|
|
1429
|
+
round(sum(cost_cache_write), 12) AS cost_cache_write,
|
|
1430
|
+
round(sum(cost_total), 12) AS cost_total
|
|
1431
|
+
FROM usage_values
|
|
1432
|
+
GROUP BY conversation_id
|
|
1433
|
+
HAVING count(input_tokens)
|
|
1434
|
+
+ count(output_tokens)
|
|
1435
|
+
+ count(cached_input_tokens)
|
|
1436
|
+
+ count(cache_creation_tokens)
|
|
1437
|
+
+ count(reasoning_tokens)
|
|
1438
|
+
+ count(total_tokens)
|
|
1439
|
+
+ count(cost_input)
|
|
1440
|
+
+ count(cost_output)
|
|
1441
|
+
+ count(cost_cache_read)
|
|
1442
|
+
+ count(cost_cache_write)
|
|
1443
|
+
+ count(cost_total) > 0
|
|
1444
|
+
),
|
|
1445
|
+
valid_rollups AS (
|
|
1446
|
+
SELECT *
|
|
1447
|
+
FROM rollups
|
|
1448
|
+
WHERE (input_tokens IS NULL OR input_tokens <= ${MAX_SAFE_INTEGER})
|
|
1449
|
+
AND (output_tokens IS NULL OR output_tokens <= ${MAX_SAFE_INTEGER})
|
|
1450
|
+
AND (cached_input_tokens IS NULL OR cached_input_tokens <= ${MAX_SAFE_INTEGER})
|
|
1451
|
+
AND (cache_creation_tokens IS NULL OR cache_creation_tokens <= ${MAX_SAFE_INTEGER})
|
|
1452
|
+
AND (reasoning_tokens IS NULL OR reasoning_tokens <= ${MAX_SAFE_INTEGER})
|
|
1453
|
+
AND (total_only_tokens IS NULL OR total_only_tokens <= ${MAX_SAFE_INTEGER})
|
|
1454
|
+
AND (
|
|
1455
|
+
total_only_tokens IS NULL
|
|
1456
|
+
OR total_only_tokens
|
|
1457
|
+
+ coalesce(input_tokens, 0)
|
|
1458
|
+
+ coalesce(output_tokens, 0)
|
|
1459
|
+
+ coalesce(cached_input_tokens, 0)
|
|
1460
|
+
+ coalesce(cache_creation_tokens, 0) <= ${MAX_SAFE_INTEGER}
|
|
1461
|
+
)
|
|
1462
|
+
AND (cost_input IS NULL OR cost_input <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1463
|
+
AND (cost_output IS NULL OR cost_output <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1464
|
+
AND (cost_cache_read IS NULL OR cost_cache_read <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1465
|
+
AND (cost_cache_write IS NULL OR cost_cache_write <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1466
|
+
AND (cost_total IS NULL OR cost_total <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1467
|
+
),
|
|
1468
|
+
normalized AS (
|
|
1469
|
+
SELECT
|
|
1470
|
+
conversation_id,
|
|
1471
|
+
jsonb_strip_nulls(jsonb_build_object(
|
|
1472
|
+
'inputTokens', CASE WHEN total_only_tokens IS NULL THEN input_tokens END,
|
|
1473
|
+
'outputTokens', CASE WHEN total_only_tokens IS NULL THEN output_tokens END,
|
|
1474
|
+
'cachedInputTokens', CASE
|
|
1475
|
+
WHEN total_only_tokens IS NULL THEN cached_input_tokens
|
|
1476
|
+
END,
|
|
1477
|
+
'cacheCreationTokens', CASE
|
|
1478
|
+
WHEN total_only_tokens IS NULL THEN cache_creation_tokens
|
|
1479
|
+
END,
|
|
1480
|
+
'reasoningTokens', reasoning_tokens,
|
|
1481
|
+
'totalTokens', CASE
|
|
1482
|
+
WHEN total_only_tokens IS NOT NULL
|
|
1483
|
+
THEN total_only_tokens
|
|
1484
|
+
+ coalesce(input_tokens, 0)
|
|
1485
|
+
+ coalesce(output_tokens, 0)
|
|
1486
|
+
+ coalesce(cached_input_tokens, 0)
|
|
1487
|
+
+ coalesce(cache_creation_tokens, 0)
|
|
1488
|
+
END,
|
|
1489
|
+
'cost', CASE
|
|
1490
|
+
WHEN cost_input IS NULL
|
|
1491
|
+
AND cost_output IS NULL
|
|
1492
|
+
AND cost_cache_read IS NULL
|
|
1493
|
+
AND cost_cache_write IS NULL
|
|
1494
|
+
AND cost_total IS NULL
|
|
1495
|
+
THEN NULL
|
|
1496
|
+
ELSE jsonb_strip_nulls(jsonb_build_object(
|
|
1497
|
+
'input', cost_input,
|
|
1498
|
+
'output', cost_output,
|
|
1499
|
+
'cacheRead', cost_cache_read,
|
|
1500
|
+
'cacheWrite', cost_cache_write,
|
|
1501
|
+
'total', cost_total
|
|
1502
|
+
))
|
|
1503
|
+
END
|
|
1504
|
+
)) AS usage
|
|
1505
|
+
FROM valid_rollups
|
|
1506
|
+
),
|
|
1507
|
+
matched AS MATERIALIZED (
|
|
1508
|
+
SELECT conversation.conversation_id
|
|
1509
|
+
FROM junior_conversations AS conversation
|
|
1510
|
+
INNER JOIN candidates AS candidate USING (conversation_id)
|
|
1511
|
+
INNER JOIN normalized USING (conversation_id)
|
|
1512
|
+
WHERE conversation.execution_status = 'idle'
|
|
1513
|
+
AND conversation.updated_at = candidate.updated_at
|
|
1514
|
+
AND conversation.execution_updated_at IS NOT DISTINCT FROM candidate.execution_updated_at
|
|
1515
|
+
FOR UPDATE OF conversation
|
|
1516
|
+
),
|
|
1517
|
+
updated AS (
|
|
1518
|
+
UPDATE junior_conversations AS conversation
|
|
1519
|
+
SET usage_json = normalized.usage
|
|
1520
|
+
FROM normalized
|
|
1521
|
+
INNER JOIN matched USING (conversation_id)
|
|
1522
|
+
WHERE conversation.conversation_id = normalized.conversation_id
|
|
1523
|
+
AND conversation.usage_json IS DISTINCT FROM normalized.usage
|
|
1524
|
+
RETURNING conversation.conversation_id
|
|
1525
|
+
)
|
|
1526
|
+
SELECT
|
|
1527
|
+
candidate.conversation_id AS "conversationId",
|
|
1528
|
+
updated.conversation_id IS NOT NULL AS changed,
|
|
1529
|
+
matched.conversation_id IS NOT NULL AS matched,
|
|
1530
|
+
normalized.conversation_id IS NOT NULL AS repairable
|
|
1531
|
+
FROM candidates AS candidate
|
|
1532
|
+
LEFT JOIN normalized USING (conversation_id)
|
|
1533
|
+
LEFT JOIN matched USING (conversation_id)
|
|
1534
|
+
LEFT JOIN updated USING (conversation_id)
|
|
1535
|
+
ORDER BY candidate.conversation_id
|
|
1536
|
+
`;
|
|
1537
|
+
async function repairConversationUsage(_context, options = {}) {
|
|
1538
|
+
let executor = options.executor;
|
|
1539
|
+
let closeExecutor;
|
|
1540
|
+
if (!executor) {
|
|
1541
|
+
const { sql } = getChatConfig();
|
|
1542
|
+
executor = createJuniorSqlExecutor({
|
|
1543
|
+
connectionString: sql.databaseUrl,
|
|
1544
|
+
driver: sql.driver
|
|
1545
|
+
});
|
|
1546
|
+
closeExecutor = () => executor.close();
|
|
1547
|
+
}
|
|
1548
|
+
const batchSize = Math.max(
|
|
1549
|
+
1,
|
|
1550
|
+
Math.floor(options.batchSize ?? CONVERSATION_USAGE_REPAIR_BATCH_SIZE)
|
|
1551
|
+
);
|
|
1552
|
+
try {
|
|
1553
|
+
let cursor = "";
|
|
1554
|
+
let existing = 0;
|
|
1555
|
+
let migrated = 0;
|
|
1556
|
+
let missing = 0;
|
|
1557
|
+
let scanned = 0;
|
|
1558
|
+
let skipped = 0;
|
|
1559
|
+
while (true) {
|
|
1560
|
+
const sources = await executor.withLock(
|
|
1561
|
+
REPAIR_LOCK,
|
|
1562
|
+
() => executor.query(USAGE_REPAIR_BATCH_SQL, [
|
|
1563
|
+
cursor,
|
|
1564
|
+
batchSize
|
|
1565
|
+
])
|
|
1566
|
+
);
|
|
1567
|
+
if (sources.length === 0) break;
|
|
1568
|
+
scanned += sources.length;
|
|
1569
|
+
for (const source of sources) {
|
|
1570
|
+
if (!source.repairable) {
|
|
1571
|
+
missing += 1;
|
|
1572
|
+
} else if (source.changed) {
|
|
1573
|
+
migrated += 1;
|
|
1574
|
+
} else if (source.matched) {
|
|
1575
|
+
existing += 1;
|
|
1576
|
+
} else {
|
|
1577
|
+
skipped += 1;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
cursor = sources.at(-1).conversationId;
|
|
1581
|
+
}
|
|
1582
|
+
return {
|
|
1583
|
+
existing,
|
|
1584
|
+
migrated,
|
|
1585
|
+
missing,
|
|
1586
|
+
scanned,
|
|
1587
|
+
...skipped > 0 ? { skipped } : {}
|
|
1588
|
+
};
|
|
1589
|
+
} finally {
|
|
1590
|
+
await closeExecutor?.();
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
var conversationUsageRepairMigration = {
|
|
1594
|
+
name: "repair-conversation-usage",
|
|
1595
|
+
run: repairConversationUsage
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1313
1598
|
// src/cli/upgrade.ts
|
|
1314
1599
|
var DEFAULT_IO = {
|
|
1315
1600
|
info: console.log
|
|
@@ -1321,6 +1606,7 @@ var MIGRATIONS = [
|
|
|
1321
1606
|
coreSqlSchemaMigration,
|
|
1322
1607
|
sqlConversationMigration,
|
|
1323
1608
|
sqlConversationHistoryMigration,
|
|
1609
|
+
conversationUsageRepairMigration,
|
|
1324
1610
|
sqlPluginMigration,
|
|
1325
1611
|
pluginStorageMigration
|
|
1326
1612
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior",
|
|
3
|
-
"version": "0.102.
|
|
3
|
+
"version": "0.102.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"pg": "^8.16.3",
|
|
76
76
|
"yaml": "^2.9.0",
|
|
77
77
|
"zod": "^4.4.3",
|
|
78
|
-
"@sentry/junior-plugin-api": "0.102.
|
|
78
|
+
"@sentry/junior-plugin-api": "0.102.3"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@emnapi/core": "^1.10.0",
|
|
@@ -92,10 +92,10 @@
|
|
|
92
92
|
"typescript": "^6.0.3",
|
|
93
93
|
"vercel": "^54.4.0",
|
|
94
94
|
"vitest": "^4.1.7",
|
|
95
|
-
"@sentry/junior-github": "0.102.
|
|
96
|
-
"@sentry/junior-memory": "0.102.
|
|
95
|
+
"@sentry/junior-github": "0.102.3",
|
|
96
|
+
"@sentry/junior-memory": "0.102.3",
|
|
97
97
|
"@sentry/junior-testing": "0.0.0",
|
|
98
|
-
"@sentry/junior-scheduler": "0.102.
|
|
98
|
+
"@sentry/junior-scheduler": "0.102.3"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
101
101
|
"build": "tsup && tsc -p tsconfig.build.json --emitDeclarationOnly",
|