@opengeni/core 4.0.1 → 4.0.3-canary.36079201993001
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/application/new-session-drafts.d.ts +3 -3
- package/dist/billing/limits.d.ts +4 -0
- package/dist/domain/capabilities.d.ts +2 -1
- package/dist/domain/knowledge-messages.d.ts +4 -4
- package/dist/domain/knowledge-preparation.d.ts +2 -1
- package/dist/domain/knowledge-search.d.ts +11 -76
- package/dist/domain/pr-review.d.ts +2 -2
- package/dist/domain/session-native-connection-replacement.d.ts +14 -0
- package/dist/index.js +707 -482
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/application/session-mcp-credential-rotation.ts +57 -15
- package/src/billing/limits.ts +24 -3
- package/src/domain/capabilities.ts +23 -7
- package/src/domain/knowledge-preparation.test.ts +25 -0
- package/src/domain/knowledge-preparation.ts +35 -14
- package/src/domain/knowledge-search.test.ts +331 -5
- package/src/domain/knowledge-search.ts +172 -23
- package/src/domain/session-native-connection-replacement.ts +64 -0
package/dist/index.js
CHANGED
|
@@ -1378,8 +1378,257 @@ async function knowledgeContextForAccess(deps, access, permission) {
|
|
|
1378
1378
|
|
|
1379
1379
|
// src/domain/knowledge-search.ts
|
|
1380
1380
|
import { KnowledgeEntryListRequest } from "@opengeni/contracts";
|
|
1381
|
-
import {
|
|
1382
|
-
|
|
1381
|
+
import {
|
|
1382
|
+
applyCreditDebitAfterUse,
|
|
1383
|
+
getBillingBalance as getBillingBalance2,
|
|
1384
|
+
listKnowledgeEntries,
|
|
1385
|
+
recordUsageEvent as recordUsageEvent2,
|
|
1386
|
+
sumUsageQuantity as sumUsageQuantity2,
|
|
1387
|
+
withKnowledgeQueryAccountLock
|
|
1388
|
+
} from "@opengeni/db";
|
|
1389
|
+
|
|
1390
|
+
// src/billing/limits.ts
|
|
1391
|
+
import {
|
|
1392
|
+
configuredStaticUsageLimits,
|
|
1393
|
+
resolveModelProviderForTurn
|
|
1394
|
+
} from "@opengeni/config";
|
|
1395
|
+
import {
|
|
1396
|
+
countActiveApiKeysForWorkspace,
|
|
1397
|
+
countActiveOrganizationApiKeysForAccount,
|
|
1398
|
+
countScheduledTasksForWorkspace,
|
|
1399
|
+
countWorkspacesForAccount,
|
|
1400
|
+
getBillingBalance,
|
|
1401
|
+
isCodexBilledTurn,
|
|
1402
|
+
recordUsageEvent,
|
|
1403
|
+
sumUsageQuantity
|
|
1404
|
+
} from "@opengeni/db";
|
|
1405
|
+
import { HTTPException as HTTPException4 } from "hono/http-exception";
|
|
1406
|
+
function paidDocumentEmbedding(settings) {
|
|
1407
|
+
return settings.documentEmbeddingBillingMode === "credits" && settings.documentEmbeddingProvider === "openai";
|
|
1408
|
+
}
|
|
1409
|
+
function documentEmbeddingCostMicros(settings, inputBytes) {
|
|
1410
|
+
if (!Number.isSafeInteger(inputBytes) || inputBytes < 0)
|
|
1411
|
+
throw new Error("invalid embedding bytes");
|
|
1412
|
+
const amount = (BigInt(inputBytes) * BigInt(settings.documentEmbeddingRateMicrosPerMillionBytes) + 999999n) / 1000000n;
|
|
1413
|
+
if (amount > BigInt(Number.MAX_SAFE_INTEGER))
|
|
1414
|
+
throw new Error("embedding cost exceeds safe integer");
|
|
1415
|
+
return Number(amount);
|
|
1416
|
+
}
|
|
1417
|
+
function modelFundingForAdmission(settings, model, codexBilled) {
|
|
1418
|
+
const resolvedModel = model ? resolveModelProviderForTurn(settings, model)?.model : null;
|
|
1419
|
+
const codexSubscriptionModel = resolvedModel?.credentialSource.kind === "connected_subscription" && resolvedModel.credentialSource.provider === "codex";
|
|
1420
|
+
return {
|
|
1421
|
+
// A Codex namespace/definition never bypasses credits by itself: the live
|
|
1422
|
+
// workspace credential predicate above remains authoritative. SuperGrok's
|
|
1423
|
+
// static overlay is likewise secret-free; its worker/provider admission
|
|
1424
|
+
// owns live account selection before any upstream request can occur.
|
|
1425
|
+
fundedWithoutCredits: codexBilled || resolvedModel != null && !codexSubscriptionModel && resolvedModel.cost !== "credits",
|
|
1426
|
+
countsTowardTokenCap: !codexBilled && resolvedModel != null && resolvedModel.billing.upstreamPayer === "deployment"
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
async function requireLimit(deps, input) {
|
|
1430
|
+
const decision = await checkLimit(deps, input);
|
|
1431
|
+
if (decision.allowed) {
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
throw new HTTPException4(decision.code === "insufficient_credits" ? 402 : 429, {
|
|
1435
|
+
message: decision.message
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
async function checkLimit(deps, input) {
|
|
1439
|
+
const codexBilled = input.workspaceId ? await isCodexBilledTurn({
|
|
1440
|
+
db: deps.db,
|
|
1441
|
+
settings: deps.settings,
|
|
1442
|
+
workspaceId: input.workspaceId,
|
|
1443
|
+
model: input.model
|
|
1444
|
+
}) : false;
|
|
1445
|
+
const { fundedWithoutCredits, countsTowardTokenCap } = modelFundingForAdmission(
|
|
1446
|
+
deps.settings,
|
|
1447
|
+
input.model,
|
|
1448
|
+
codexBilled
|
|
1449
|
+
);
|
|
1450
|
+
const creditDecision = await checkCreditBalance(deps, input, fundedWithoutCredits);
|
|
1451
|
+
if (!creditDecision.allowed) {
|
|
1452
|
+
return creditDecision;
|
|
1453
|
+
}
|
|
1454
|
+
if (deps.settings.usageLimitsMode !== "static" && deps.settings.usageLimitsMode !== "managed") {
|
|
1455
|
+
return { allowed: true };
|
|
1456
|
+
}
|
|
1457
|
+
return await checkStaticCaps(deps, input, {
|
|
1458
|
+
fundedWithoutCredits,
|
|
1459
|
+
countsTowardTokenCap
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
async function checkCreditBalance(deps, input, externallyBilled) {
|
|
1463
|
+
if (externallyBilled) {
|
|
1464
|
+
return { allowed: true };
|
|
1465
|
+
}
|
|
1466
|
+
if (!usesCreditLimits(deps) || !isCostlyAction(input.action)) {
|
|
1467
|
+
return { allowed: true };
|
|
1468
|
+
}
|
|
1469
|
+
const balance = await getBillingBalance(deps.db, input.accountId);
|
|
1470
|
+
if (balance.balanceMicros > 0) {
|
|
1471
|
+
return { allowed: true };
|
|
1472
|
+
}
|
|
1473
|
+
return { allowed: false, code: "insufficient_credits", message: "insufficient OpenGeni credits" };
|
|
1474
|
+
}
|
|
1475
|
+
async function checkStaticCaps(deps, input, funding) {
|
|
1476
|
+
const limits = configuredStaticUsageLimits(deps.settings);
|
|
1477
|
+
if (limits.maxMonthlyCostMicrosPerAccount && isCostlyAction(input.action) && !funding.fundedWithoutCredits) {
|
|
1478
|
+
const used = await sumUsageQuantity(deps.db, {
|
|
1479
|
+
accountId: input.accountId,
|
|
1480
|
+
eventType: "model.cost",
|
|
1481
|
+
since: startOfUtcMonth()
|
|
1482
|
+
});
|
|
1483
|
+
if (used >= limits.maxMonthlyCostMicrosPerAccount) {
|
|
1484
|
+
return blocked(
|
|
1485
|
+
"max_monthly_cost_micros_per_account",
|
|
1486
|
+
`monthly model cost limit reached (${limits.maxMonthlyCostMicrosPerAccount} micros)`
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
switch (input.action) {
|
|
1491
|
+
case "workspace:create": {
|
|
1492
|
+
if (!limits.maxWorkspacesPerAccount) {
|
|
1493
|
+
return { allowed: true };
|
|
1494
|
+
}
|
|
1495
|
+
const count = await countWorkspacesForAccount(deps.db, input.accountId);
|
|
1496
|
+
return count < limits.maxWorkspacesPerAccount ? { allowed: true } : blocked(
|
|
1497
|
+
"max_workspaces_per_account",
|
|
1498
|
+
`workspace limit reached (${limits.maxWorkspacesPerAccount})`
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
case "api_key:create": {
|
|
1502
|
+
if (!limits.maxApiKeysPerWorkspace) {
|
|
1503
|
+
return { allowed: true };
|
|
1504
|
+
}
|
|
1505
|
+
const count = input.workspaceId ? await countActiveApiKeysForWorkspace(deps.db, input.workspaceId) : await countActiveOrganizationApiKeysForAccount(deps.db, input.accountId);
|
|
1506
|
+
return count < limits.maxApiKeysPerWorkspace ? { allowed: true } : blocked(
|
|
1507
|
+
"max_api_keys_per_workspace",
|
|
1508
|
+
`API key limit reached (${limits.maxApiKeysPerWorkspace})`
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
case "schedule:create": {
|
|
1512
|
+
if (!limits.maxSchedulesPerWorkspace || !input.workspaceId) {
|
|
1513
|
+
return { allowed: true };
|
|
1514
|
+
}
|
|
1515
|
+
const count = await countScheduledTasksForWorkspace(deps.db, input.workspaceId);
|
|
1516
|
+
return count < limits.maxSchedulesPerWorkspace ? { allowed: true } : blocked(
|
|
1517
|
+
"max_schedules_per_workspace",
|
|
1518
|
+
`scheduled task limit reached (${limits.maxSchedulesPerWorkspace})`
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
case "file:upload": {
|
|
1522
|
+
if (!limits.maxFileUploadBytes || !input.quantity) {
|
|
1523
|
+
return { allowed: true };
|
|
1524
|
+
}
|
|
1525
|
+
return input.quantity <= limits.maxFileUploadBytes ? { allowed: true } : blocked(
|
|
1526
|
+
"max_file_upload_bytes",
|
|
1527
|
+
`file upload exceeds static limit of ${limits.maxFileUploadBytes} bytes`
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
case "agent_run:create": {
|
|
1531
|
+
if (!limits.maxMonthlyAgentRunsPerWorkspace || !input.workspaceId) {
|
|
1532
|
+
return { allowed: true };
|
|
1533
|
+
}
|
|
1534
|
+
const used = await sumUsageQuantity(deps.db, {
|
|
1535
|
+
workspaceId: input.workspaceId,
|
|
1536
|
+
eventType: "agent_run.created",
|
|
1537
|
+
since: startOfUtcMonth()
|
|
1538
|
+
});
|
|
1539
|
+
const requested = input.quantity ?? 0;
|
|
1540
|
+
return used + requested <= limits.maxMonthlyAgentRunsPerWorkspace ? { allowed: true } : blocked(
|
|
1541
|
+
"max_monthly_agent_runs_per_workspace",
|
|
1542
|
+
`monthly agent run limit reached (${limits.maxMonthlyAgentRunsPerWorkspace})`
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
1545
|
+
case "tokens:consume": {
|
|
1546
|
+
if (!funding.countsTowardTokenCap || !limits.maxMonthlyTokensPerWorkspace || !input.workspaceId) {
|
|
1547
|
+
return { allowed: true };
|
|
1548
|
+
}
|
|
1549
|
+
const used = await sumUsageQuantity(deps.db, {
|
|
1550
|
+
workspaceId: input.workspaceId,
|
|
1551
|
+
eventType: "model.tokens",
|
|
1552
|
+
since: startOfUtcMonth()
|
|
1553
|
+
});
|
|
1554
|
+
const requested = input.quantity ?? 0;
|
|
1555
|
+
return used + requested <= limits.maxMonthlyTokensPerWorkspace ? { allowed: true } : blocked(
|
|
1556
|
+
"max_monthly_tokens_per_workspace",
|
|
1557
|
+
`monthly token limit reached (${limits.maxMonthlyTokensPerWorkspace})`
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
case "document:index": {
|
|
1561
|
+
if (!limits.maxDocumentIndexedChunksPerWorkspace || !input.workspaceId) {
|
|
1562
|
+
return { allowed: true };
|
|
1563
|
+
}
|
|
1564
|
+
const used = await sumUsageQuantity(deps.db, {
|
|
1565
|
+
workspaceId: input.workspaceId,
|
|
1566
|
+
eventType: "document.indexed",
|
|
1567
|
+
since: startOfUtcMonth()
|
|
1568
|
+
});
|
|
1569
|
+
const requested = input.quantity ?? 0;
|
|
1570
|
+
return used + requested <= limits.maxDocumentIndexedChunksPerWorkspace ? { allowed: true } : blocked(
|
|
1571
|
+
"max_document_indexed_chunks_per_workspace",
|
|
1572
|
+
`monthly document indexing limit reached (${limits.maxDocumentIndexedChunksPerWorkspace} chunks)`
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
async function recordWorkspaceUsage(deps, input) {
|
|
1578
|
+
await recordUsageEvent(deps.db, {
|
|
1579
|
+
accountId: input.accountId,
|
|
1580
|
+
workspaceId: input.workspaceId,
|
|
1581
|
+
subjectId: input.subjectId ?? null,
|
|
1582
|
+
eventType: input.eventType,
|
|
1583
|
+
quantity: input.quantity,
|
|
1584
|
+
unit: input.unit,
|
|
1585
|
+
sourceResourceType: input.sourceResourceType,
|
|
1586
|
+
sourceResourceId: input.sourceResourceId,
|
|
1587
|
+
sessionId: input.sessionId ?? null,
|
|
1588
|
+
turnId: input.turnId ?? null,
|
|
1589
|
+
turnAttemptId: input.turnAttemptId ?? null,
|
|
1590
|
+
initiator: input.initiator ?? (input.subjectId ? { kind: "subject", subjectId: input.subjectId } : null),
|
|
1591
|
+
...input.initiatorContext ? { initiatorContext: input.initiatorContext } : {},
|
|
1592
|
+
origin: input.origin ?? null,
|
|
1593
|
+
idempotencyKey: input.idempotencyKey
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
function usesCreditLimits(deps) {
|
|
1597
|
+
return deps.settings.billingMode === "stripe" || deps.settings.usageLimitsMode === "managed";
|
|
1598
|
+
}
|
|
1599
|
+
function isCostlyAction(action) {
|
|
1600
|
+
return action === "agent_run:create" || action === "tokens:consume";
|
|
1601
|
+
}
|
|
1602
|
+
function blocked(code, message) {
|
|
1603
|
+
return { allowed: false, code, message };
|
|
1604
|
+
}
|
|
1605
|
+
function startOfUtcMonth() {
|
|
1606
|
+
const now = /* @__PURE__ */ new Date();
|
|
1607
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// src/domain/knowledge-search.ts
|
|
1611
|
+
var MAX_PAID_QUERY_BYTES = 4096;
|
|
1612
|
+
var MAX_PAID_QUERY_MICROS = 1e3;
|
|
1613
|
+
var MAX_PAID_QUERY_BYTES_PER_MINUTE = 64 * 1024;
|
|
1614
|
+
var MAX_PAID_QUERY_BYTES_PER_MONTH = 8 * 1024 * 1024;
|
|
1615
|
+
var MAX_PAID_QUERY_MICROS_PER_MINUTE = 1e4;
|
|
1616
|
+
var MAX_PAID_QUERY_MICROS_PER_MONTH = 1e6;
|
|
1617
|
+
var KnowledgeVectorFundingError = class extends Error {
|
|
1618
|
+
code = "knowledge_vector_funding_required";
|
|
1619
|
+
constructor() {
|
|
1620
|
+
super("Knowledge vector search needs OpenGeni credits; keyword search remains available.");
|
|
1621
|
+
this.name = "KnowledgeVectorFundingError";
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
var KnowledgeVectorQueryRejectedError = class extends Error {
|
|
1625
|
+
constructor(code, message) {
|
|
1626
|
+
super(message);
|
|
1627
|
+
this.code = code;
|
|
1628
|
+
this.name = "KnowledgeVectorQueryRejectedError";
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
async function searchKnowledgeEntries(db, context, input, embedder, settings) {
|
|
1383
1632
|
const request = KnowledgeEntryListRequest.parse(input);
|
|
1384
1633
|
if (!request.query || request.mode === "keyword") {
|
|
1385
1634
|
return {
|
|
@@ -1390,25 +1639,119 @@ async function searchKnowledgeEntries(db, context, input, embedder) {
|
|
|
1390
1639
|
const lexicalQuery = /^[\p{L}\p{N}\s]+$/u.test(request.query) && !/\bOR\b/i.test(request.query) ? [...new Set(request.query.trim().split(/\s+/u))].map((term) => `"${term}"`).join(" OR ") : request.query;
|
|
1391
1640
|
const lexicalRequest = KnowledgeEntryListRequest.safeParse({ ...request, query: lexicalQuery });
|
|
1392
1641
|
const retrievalRequest = request.mode === "hybrid" && lexicalRequest.success ? lexicalRequest.data : request;
|
|
1393
|
-
|
|
1394
|
-
try {
|
|
1395
|
-
const provider = embedder();
|
|
1396
|
-
const values = await provider.embedQuery(request.query);
|
|
1397
|
-
if (values.length !== provider.dimensions || values.some((value) => !Number.isFinite(value)) || !values.some((value) => value !== 0)) {
|
|
1398
|
-
throw new Error("Knowledge query embedding is unavailable");
|
|
1399
|
-
}
|
|
1400
|
-
embedding = { model: provider.model, values };
|
|
1401
|
-
} catch (error) {
|
|
1642
|
+
const keywordFallback = async (queryDb, error, fallbackReason) => {
|
|
1402
1643
|
if (request.mode === "vector") throw error;
|
|
1403
1644
|
return {
|
|
1404
|
-
...await listKnowledgeEntries(
|
|
1405
|
-
searchMode: "keyword"
|
|
1645
|
+
...await listKnowledgeEntries(queryDb, context, { ...retrievalRequest, mode: "keyword" }),
|
|
1646
|
+
searchMode: "keyword",
|
|
1647
|
+
fallbackReason
|
|
1406
1648
|
};
|
|
1407
|
-
}
|
|
1408
|
-
return {
|
|
1409
|
-
...await listKnowledgeEntries(db, context, retrievalRequest, embedding),
|
|
1410
|
-
searchMode: request.mode
|
|
1411
1649
|
};
|
|
1650
|
+
const bytes = Buffer.byteLength(request.query, "utf8");
|
|
1651
|
+
const paidSettings = settings && paidDocumentEmbedding(settings) ? settings : void 0;
|
|
1652
|
+
if (paidSettings && request.cursor)
|
|
1653
|
+
throw new KnowledgeVectorQueryRejectedError(
|
|
1654
|
+
"pagination_unavailable",
|
|
1655
|
+
"Paid semantic Knowledge pagination is unavailable; use keyword mode"
|
|
1656
|
+
);
|
|
1657
|
+
const cost = paidSettings ? documentEmbeddingCostMicros(paidSettings, bytes) : 0;
|
|
1658
|
+
if (paidSettings && (bytes > MAX_PAID_QUERY_BYTES || cost > MAX_PAID_QUERY_MICROS))
|
|
1659
|
+
return keywordFallback(
|
|
1660
|
+
db,
|
|
1661
|
+
new KnowledgeVectorQueryRejectedError(
|
|
1662
|
+
"query_limit",
|
|
1663
|
+
"Paid Knowledge query exceeds the per-request limit"
|
|
1664
|
+
),
|
|
1665
|
+
"query_limit"
|
|
1666
|
+
);
|
|
1667
|
+
const retrieveThenSettle = async (queryDb) => {
|
|
1668
|
+
let embedding;
|
|
1669
|
+
try {
|
|
1670
|
+
const provider = embedder();
|
|
1671
|
+
const values = await provider.embedQuery(request.query);
|
|
1672
|
+
if (values.length !== provider.dimensions || values.some((value) => !Number.isFinite(value)) || !values.some((value) => value !== 0))
|
|
1673
|
+
throw new Error("Knowledge query embedding is unavailable");
|
|
1674
|
+
embedding = { model: provider.model, values };
|
|
1675
|
+
} catch (error) {
|
|
1676
|
+
return keywordFallback(queryDb, error, "provider_unavailable");
|
|
1677
|
+
}
|
|
1678
|
+
const found = await listKnowledgeEntries(queryDb, context, retrievalRequest, embedding);
|
|
1679
|
+
if (settings) {
|
|
1680
|
+
const usageId = crypto.randomUUID();
|
|
1681
|
+
await recordUsageEvent2(queryDb, {
|
|
1682
|
+
accountId: context.accountId,
|
|
1683
|
+
workspaceId: context.workspaceId,
|
|
1684
|
+
eventType: "document.query_embedding_bytes",
|
|
1685
|
+
quantity: bytes,
|
|
1686
|
+
unit: "byte",
|
|
1687
|
+
sourceResourceType: "knowledge_query",
|
|
1688
|
+
sourceResourceId: usageId,
|
|
1689
|
+
idempotencyKey: `knowledge.query_bytes:${usageId}`
|
|
1690
|
+
});
|
|
1691
|
+
if (paidSettings && cost > 0)
|
|
1692
|
+
await recordUsageEvent2(queryDb, {
|
|
1693
|
+
accountId: context.accountId,
|
|
1694
|
+
workspaceId: context.workspaceId,
|
|
1695
|
+
eventType: "document.query_embedding_cost",
|
|
1696
|
+
quantity: cost,
|
|
1697
|
+
unit: "micro_usd",
|
|
1698
|
+
sourceResourceType: "knowledge_query",
|
|
1699
|
+
sourceResourceId: usageId,
|
|
1700
|
+
idempotencyKey: `knowledge.query_cost:${usageId}`
|
|
1701
|
+
});
|
|
1702
|
+
if (paidSettings && cost > 0)
|
|
1703
|
+
await applyCreditDebitAfterUse(queryDb, {
|
|
1704
|
+
accountId: context.accountId,
|
|
1705
|
+
workspaceId: context.workspaceId,
|
|
1706
|
+
type: "document_embedding_debit",
|
|
1707
|
+
amountMicros: cost,
|
|
1708
|
+
sourceType: "knowledge_query",
|
|
1709
|
+
sourceId: usageId,
|
|
1710
|
+
idempotencyKey: `knowledge.query_embedding:${usageId}`,
|
|
1711
|
+
metadata: { model: embedding.model, bytes }
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
return { ...found, searchMode: request.mode };
|
|
1715
|
+
};
|
|
1716
|
+
if (!paidSettings) return retrieveThenSettle(db);
|
|
1717
|
+
return withKnowledgeQueryAccountLock(
|
|
1718
|
+
db,
|
|
1719
|
+
context.accountId,
|
|
1720
|
+
context.workspaceId,
|
|
1721
|
+
async (lockedDb) => {
|
|
1722
|
+
const balance = await getBillingBalance2(lockedDb, context.accountId);
|
|
1723
|
+
if (balance.balanceMicros <= 0)
|
|
1724
|
+
return keywordFallback(lockedDb, new KnowledgeVectorFundingError(), "awaiting_funding");
|
|
1725
|
+
const now = /* @__PURE__ */ new Date();
|
|
1726
|
+
const minuteBytes = await sumUsageQuantity2(lockedDb, {
|
|
1727
|
+
accountId: context.accountId,
|
|
1728
|
+
eventType: "document.query_embedding_bytes",
|
|
1729
|
+
since: new Date(now.getTime() - 6e4)
|
|
1730
|
+
});
|
|
1731
|
+
const monthBytes = await sumUsageQuantity2(lockedDb, {
|
|
1732
|
+
accountId: context.accountId,
|
|
1733
|
+
eventType: "document.query_embedding_bytes",
|
|
1734
|
+
since: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))
|
|
1735
|
+
});
|
|
1736
|
+
const minuteMicros = await sumUsageQuantity2(lockedDb, {
|
|
1737
|
+
accountId: context.accountId,
|
|
1738
|
+
eventType: "document.query_embedding_cost",
|
|
1739
|
+
since: new Date(now.getTime() - 6e4)
|
|
1740
|
+
});
|
|
1741
|
+
const monthMicros = await sumUsageQuantity2(lockedDb, {
|
|
1742
|
+
accountId: context.accountId,
|
|
1743
|
+
eventType: "document.query_embedding_cost",
|
|
1744
|
+
since: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))
|
|
1745
|
+
});
|
|
1746
|
+
if (minuteBytes + bytes > MAX_PAID_QUERY_BYTES_PER_MINUTE || monthBytes + bytes > MAX_PAID_QUERY_BYTES_PER_MONTH || minuteMicros + cost > MAX_PAID_QUERY_MICROS_PER_MINUTE || monthMicros + cost > MAX_PAID_QUERY_MICROS_PER_MONTH)
|
|
1747
|
+
return keywordFallback(
|
|
1748
|
+
lockedDb,
|
|
1749
|
+
new KnowledgeVectorQueryRejectedError("quota", "Paid Knowledge query rate limit reached"),
|
|
1750
|
+
"quota"
|
|
1751
|
+
);
|
|
1752
|
+
return retrieveThenSettle(lockedDb);
|
|
1753
|
+
}
|
|
1754
|
+
);
|
|
1412
1755
|
}
|
|
1413
1756
|
|
|
1414
1757
|
// src/workflow-wake-contract.ts
|
|
@@ -3272,7 +3615,7 @@ async function provisionSandbox(services, ctx, input) {
|
|
|
3272
3615
|
}
|
|
3273
3616
|
|
|
3274
3617
|
// src/application/external-workspace-members.ts
|
|
3275
|
-
import { HTTPException as
|
|
3618
|
+
import { HTTPException as HTTPException5 } from "hono/http-exception";
|
|
3276
3619
|
import {
|
|
3277
3620
|
AddExternalWorkspaceMemberRequest,
|
|
3278
3621
|
ExternalIdentityReference,
|
|
@@ -3308,12 +3651,12 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3308
3651
|
const context = await requireAccessContext(c, deps);
|
|
3309
3652
|
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
3310
3653
|
if (!authority)
|
|
3311
|
-
throw new
|
|
3654
|
+
throw new HTTPException5(403, {
|
|
3312
3655
|
message: "external onboarding requires an organization service key"
|
|
3313
3656
|
});
|
|
3314
3657
|
const grant = await requireFreshAccessGrant(c, deps, workspaceId, "members:manage");
|
|
3315
3658
|
if (grant.accountId !== authority.accountId || payload.permissions.some((permission) => !hasPermission(grant.permissions, permission))) {
|
|
3316
|
-
throw new
|
|
3659
|
+
throw new HTTPException5(403, { message: "membership exceeds key authority" });
|
|
3317
3660
|
}
|
|
3318
3661
|
if (payload.operationId) {
|
|
3319
3662
|
try {
|
|
@@ -3339,11 +3682,11 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3339
3682
|
"members:manage"
|
|
3340
3683
|
);
|
|
3341
3684
|
if (live.accountId !== grant.accountId || live.subjectId !== grant.subjectId || payload.permissions.some((permission) => !hasPermission(live.permissions, permission))) {
|
|
3342
|
-
throw new
|
|
3685
|
+
throw new HTTPException5(403, { message: "membership authority changed" });
|
|
3343
3686
|
}
|
|
3344
3687
|
const workspace = await requireWorkspace2(tx, workspaceId);
|
|
3345
3688
|
if (workspace.kind !== "shared" || workspace.accountId !== authority.accountId)
|
|
3346
|
-
throw new
|
|
3689
|
+
throw new HTTPException5(403, {
|
|
3347
3690
|
message: "external onboarding requires a shared organization workspace"
|
|
3348
3691
|
});
|
|
3349
3692
|
const identity = await ensureExternalIdentity2(tx, {
|
|
@@ -3357,7 +3700,7 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3357
3700
|
const permissions = [...new Set(payload.permissions)];
|
|
3358
3701
|
if (existing) {
|
|
3359
3702
|
if (existing.permissions.length !== permissions.length || existing.permissions.some((permission) => !permissions.includes(permission))) {
|
|
3360
|
-
throw new
|
|
3703
|
+
throw new HTTPException5(409, {
|
|
3361
3704
|
message: "existing membership differs; onboarding does not overwrite permissions"
|
|
3362
3705
|
});
|
|
3363
3706
|
}
|
|
@@ -3376,7 +3719,7 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3376
3719
|
function rethrowExternalWorkspaceOperation(error) {
|
|
3377
3720
|
const status = organizationMembershipHttpStatus(nestedPostgresSqlState2(error));
|
|
3378
3721
|
if (status)
|
|
3379
|
-
throw new
|
|
3722
|
+
throw new HTTPException5(status, {
|
|
3380
3723
|
message: status === 409 ? "External membership operation changed or was cancelled" : "External membership operation is not available"
|
|
3381
3724
|
});
|
|
3382
3725
|
throw error;
|
|
@@ -3385,7 +3728,7 @@ async function externalService(c, deps, organizationId) {
|
|
|
3385
3728
|
const context = await requireAccessContext(c, deps);
|
|
3386
3729
|
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
3387
3730
|
if (!authority || authority.accountId !== organizationId || !hasPermission(authority.permissions, "members:manage")) {
|
|
3388
|
-
throw new
|
|
3731
|
+
throw new HTTPException5(403, {
|
|
3389
3732
|
message: "External membership operation requires an organization service key"
|
|
3390
3733
|
});
|
|
3391
3734
|
}
|
|
@@ -3395,7 +3738,7 @@ async function lookupExternalIdentityForRequest(c, deps, organizationId, input)
|
|
|
3395
3738
|
const service = await externalService(c, deps, organizationId);
|
|
3396
3739
|
const identity = ExternalIdentityReference.safeParse(input);
|
|
3397
3740
|
if (!identity.success)
|
|
3398
|
-
throw new
|
|
3741
|
+
throw new HTTPException5(422, { message: "Invalid external identity reference" });
|
|
3399
3742
|
try {
|
|
3400
3743
|
return await lookupExternalIdentity(deps.db, service, identity.data);
|
|
3401
3744
|
} catch (error) {
|
|
@@ -3406,7 +3749,7 @@ async function cancelExternalWorkspaceMemberGrantForRequest(c, deps, organizatio
|
|
|
3406
3749
|
const service = await externalService(c, deps, organizationId);
|
|
3407
3750
|
const request = CancelExternalWorkspaceMemberGrantRequest.safeParse(input);
|
|
3408
3751
|
if (!request.success)
|
|
3409
|
-
throw new
|
|
3752
|
+
throw new HTTPException5(422, { message: "Invalid external grant cancellation" });
|
|
3410
3753
|
try {
|
|
3411
3754
|
return await cancelExternalWorkspaceMemberGrant(
|
|
3412
3755
|
deps.db,
|
|
@@ -3419,7 +3762,7 @@ async function cancelExternalWorkspaceMemberGrantForRequest(c, deps, organizatio
|
|
|
3419
3762
|
}
|
|
3420
3763
|
|
|
3421
3764
|
// src/application/external-identity-lifecycle.ts
|
|
3422
|
-
import { HTTPException as
|
|
3765
|
+
import { HTTPException as HTTPException6 } from "hono/http-exception";
|
|
3423
3766
|
import { UpdateExternalIdentityMembershipRequest } from "@opengeni/contracts/external-identities";
|
|
3424
3767
|
import { updateOrganizationMember } from "@opengeni/db";
|
|
3425
3768
|
async function updateExternalIdentityMembershipForRequest(context, deps, organizationId, membershipId, input) {
|
|
@@ -3429,13 +3772,13 @@ async function updateExternalIdentityMembershipForRequest(context, deps, organiz
|
|
|
3429
3772
|
(grant) => grant.accountId === organizationId && grant.subjectId === access.subjectId
|
|
3430
3773
|
);
|
|
3431
3774
|
if (!service || service.accountId !== organizationId || !account?.permissions.includes("account:admin")) {
|
|
3432
|
-
throw new
|
|
3775
|
+
throw new HTTPException6(403, {
|
|
3433
3776
|
message: "external identity administration requires an organization service key"
|
|
3434
3777
|
});
|
|
3435
3778
|
}
|
|
3436
3779
|
const parsed = UpdateExternalIdentityMembershipRequest.safeParse(input);
|
|
3437
3780
|
if (!parsed.success)
|
|
3438
|
-
throw new
|
|
3781
|
+
throw new HTTPException6(422, { message: "invalid external identity transition" });
|
|
3439
3782
|
return updateOrganizationMember(deps.db, {
|
|
3440
3783
|
organizationId,
|
|
3441
3784
|
membershipId,
|
|
@@ -3457,7 +3800,7 @@ import {
|
|
|
3457
3800
|
nestedPostgresSqlState as nestedPostgresSqlState3,
|
|
3458
3801
|
withWorkspaceSubjectRls as withWorkspaceSubjectRls3
|
|
3459
3802
|
} from "@opengeni/db";
|
|
3460
|
-
import { HTTPException as
|
|
3803
|
+
import { HTTPException as HTTPException7 } from "hono/http-exception";
|
|
3461
3804
|
function externalContinuationCommitAuthorizer(authorization) {
|
|
3462
3805
|
const continuation = authorization ? externalActorContinuationForAuthorization(authorization) : null;
|
|
3463
3806
|
if (!continuation || !authorization) return void 0;
|
|
@@ -3472,7 +3815,7 @@ function externalContinuationCommitAuthorizer(authorization) {
|
|
|
3472
3815
|
await requireExternalContinuationAuthority(tx, continuation, scope, permissions);
|
|
3473
3816
|
} catch (error) {
|
|
3474
3817
|
const denied2 = nestedPostgresSqlState3(error) === "42501" || error instanceof Error && error.message === "External continuation authority unavailable";
|
|
3475
|
-
throw new
|
|
3818
|
+
throw new HTTPException7(denied2 ? 403 : 503, {
|
|
3476
3819
|
message: denied2 ? "external authority changed" : "external authority is unavailable",
|
|
3477
3820
|
cause: error
|
|
3478
3821
|
});
|
|
@@ -3537,12 +3880,12 @@ import {
|
|
|
3537
3880
|
variableSetVariableNameReservation
|
|
3538
3881
|
} from "@opengeni/contracts";
|
|
3539
3882
|
import { getVariableSet, recordAuditEvent } from "@opengeni/db";
|
|
3540
|
-
import { HTTPException as
|
|
3883
|
+
import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
3541
3884
|
var MAX_ENVIRONMENTS_PER_WORKSPACE = 25;
|
|
3542
3885
|
var MAX_VARIABLES_PER_ENVIRONMENT = 100;
|
|
3543
3886
|
function assertAllowedVariableSetVariableName(name) {
|
|
3544
3887
|
if (variableSetVariableNameReservation(name)) {
|
|
3545
|
-
throw new
|
|
3888
|
+
throw new HTTPException8(422, {
|
|
3546
3889
|
message: `reserved variable set variable name / reserved environment variable name: ${name}`
|
|
3547
3890
|
});
|
|
3548
3891
|
}
|
|
@@ -3551,7 +3894,7 @@ var assertAllowedEnvironmentVariableName = assertAllowedVariableSetVariableName;
|
|
|
3551
3894
|
function requireVariableSetEncryption(settings) {
|
|
3552
3895
|
const key = environmentsEncryptionKeyBytes(settings);
|
|
3553
3896
|
if (!key) {
|
|
3554
|
-
throw new
|
|
3897
|
+
throw new HTTPException8(503, {
|
|
3555
3898
|
message: "variable sets require OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY"
|
|
3556
3899
|
});
|
|
3557
3900
|
}
|
|
@@ -3569,7 +3912,7 @@ async function requireVariableSetForApi(db, grant, variableSetId) {
|
|
|
3569
3912
|
variableSetId
|
|
3570
3913
|
);
|
|
3571
3914
|
if (!variableSet) {
|
|
3572
|
-
throw new
|
|
3915
|
+
throw new HTTPException8(404, { message: "variableSet not found" });
|
|
3573
3916
|
}
|
|
3574
3917
|
return variableSet;
|
|
3575
3918
|
}
|
|
@@ -3583,7 +3926,7 @@ async function validateVariableSetAttachment(deps, grant, workspaceId, variableS
|
|
|
3583
3926
|
variableSetId
|
|
3584
3927
|
);
|
|
3585
3928
|
if (!variableSet) {
|
|
3586
|
-
throw new
|
|
3929
|
+
throw new HTTPException8(422, { message: "unknown variableSetId" });
|
|
3587
3930
|
}
|
|
3588
3931
|
return variableSet;
|
|
3589
3932
|
}
|
|
@@ -3643,416 +3986,207 @@ async function fileOwnerContextForAgent(deps, grant, permission) {
|
|
|
3643
3986
|
sessionId,
|
|
3644
3987
|
turnId: attempt.turnId,
|
|
3645
3988
|
attemptId: attempt.attemptId,
|
|
3646
|
-
executionGeneration: attempt.executionGeneration
|
|
3647
|
-
}
|
|
3648
|
-
});
|
|
3649
|
-
const sessionAuthority = await getSessionAuthorityProjection3(
|
|
3650
|
-
deps.db,
|
|
3651
|
-
grant.workspaceId,
|
|
3652
|
-
sessionId
|
|
3653
|
-
);
|
|
3654
|
-
if (!sessionAuthority) throw new Error("File session authority unavailable");
|
|
3655
|
-
return {
|
|
3656
|
-
sessionAttachmentReadAccess: {
|
|
3657
|
-
sessionId,
|
|
3658
|
-
authorityEpoch: sessionAuthority.authorityEpoch,
|
|
3659
|
-
actor: attempt
|
|
3660
|
-
},
|
|
3661
|
-
subjectId: grant.subjectId,
|
|
3662
|
-
initiatingHumanSubjectId: attempt.initiatingHumanSubjectId,
|
|
3663
|
-
privateFileOwnerSubjectId: snapshot.defaultScope === "personal" ? snapshot.subjectId : null
|
|
3664
|
-
};
|
|
3665
|
-
}
|
|
3666
|
-
|
|
3667
|
-
// src/domain/sessions.ts
|
|
3668
|
-
import { CODEX_MODEL_ID_PREFIX, isCodexBilledModel } from "@opengeni/codex";
|
|
3669
|
-
|
|
3670
|
-
// src/site-session-origin.ts
|
|
3671
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
3672
|
-
var origins = new AsyncLocalStorage();
|
|
3673
|
-
function withSiteSessionOrigin(origin, run) {
|
|
3674
|
-
return origins.run(origin, run);
|
|
3675
|
-
}
|
|
3676
|
-
function sessionCreationMetadata(metadata) {
|
|
3677
|
-
const { _opengeniSiteOrigin: _ignored, ...rest } = metadata;
|
|
3678
|
-
const origin = origins.getStore();
|
|
3679
|
-
return origin ? { ...rest, _opengeniSiteOrigin: origin } : rest;
|
|
3680
|
-
}
|
|
3681
|
-
|
|
3682
|
-
// src/domain/sessions.ts
|
|
3683
|
-
import {
|
|
3684
|
-
canonicalizeConfiguredModelId,
|
|
3685
|
-
configuredAllowedModels,
|
|
3686
|
-
withCodexCatalogProvider as withCodexCatalogProvider2,
|
|
3687
|
-
ORGANIZATION_GATEWAY_MODEL_ID_PREFIX as ORGANIZATION_GATEWAY_MODEL_ID_PREFIX2,
|
|
3688
|
-
ORGANIZATION_OPENROUTER_MODEL_ID_PREFIX as ORGANIZATION_OPENROUTER_MODEL_ID_PREFIX2,
|
|
3689
|
-
resolveFirstPartyMcpToolPolicy,
|
|
3690
|
-
policyProviderIdForModel,
|
|
3691
|
-
resolveTurnExecutionPolicyV1,
|
|
3692
|
-
WORKSPACE_GATEWAY_MODEL_ID_PREFIX as WORKSPACE_GATEWAY_MODEL_ID_PREFIX2,
|
|
3693
|
-
WORKSPACE_OPENROUTER_MODEL_ID_PREFIX as WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2,
|
|
3694
|
-
XAI_SUBSCRIPTION_MODEL_ID_PREFIX
|
|
3695
|
-
} from "@opengeni/config";
|
|
3696
|
-
import {
|
|
3697
|
-
AUTOMATIC_SESSION_TITLE_FALLBACK,
|
|
3698
|
-
CreateSessionRequest,
|
|
3699
|
-
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
3700
|
-
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
3701
|
-
currentAgentLearningToolSelection,
|
|
3702
|
-
DraftTimelineAnnotations as DraftTimelineAnnotations2,
|
|
3703
|
-
FIRST_PARTY_MCP_TOOL_NAMES as FIRST_PARTY_MCP_TOOL_NAMES2,
|
|
3704
|
-
OPENGENI_SLACK_BOT_SESSION_METADATA_KEY as OPENGENI_SLACK_BOT_SESSION_METADATA_KEY2,
|
|
3705
|
-
SessionSkills,
|
|
3706
|
-
resolveBundledSkillSelection,
|
|
3707
|
-
SessionSpawnDenial,
|
|
3708
|
-
ServiceTurnInitiator,
|
|
3709
|
-
ServiceTurnInitiatorContext,
|
|
3710
|
-
evaluateWorkspaceModelPolicy as evaluateWorkspaceModelPolicy2,
|
|
3711
|
-
normalizeAutomaticSessionTitle,
|
|
3712
|
-
resolveWorkspaceSessionToolDefaults as resolveWorkspaceSessionToolDefaults2,
|
|
3713
|
-
metadataWithTurnExecutionPolicyV1,
|
|
3714
|
-
readTurnExecutionPolicyV1,
|
|
3715
|
-
stableJson as stableJson3,
|
|
3716
|
-
SessionMcpApprovalPolicy
|
|
3717
|
-
} from "@opengeni/contracts";
|
|
3718
|
-
import {
|
|
3719
|
-
assertExactNewSessionDraftInTransaction,
|
|
3720
|
-
createSession,
|
|
3721
|
-
createSessionWithIdempotencyKeyResult,
|
|
3722
|
-
canonicalSessionCommandHash,
|
|
3723
|
-
encryptVariableSetValue as encryptVariableSetValue2,
|
|
3724
|
-
getAnySessionInGroup,
|
|
3725
|
-
getEnrollment as getEnrollment2,
|
|
3726
|
-
getChannel,
|
|
3727
|
-
getRig as getRig2,
|
|
3728
|
-
getWorkspaceDefaultRigId,
|
|
3729
|
-
listDistinctVariableSetSelectionsInGroup,
|
|
3730
|
-
listDistinctRigVersionIdsInGroup,
|
|
3731
|
-
listInstalledPortableSkills,
|
|
3732
|
-
listEnabledMcpCapabilityServers as listEnabledMcpCapabilityServers2,
|
|
3733
|
-
requireApprovalWithFloor,
|
|
3734
|
-
getSandbox as getSandbox3,
|
|
3735
|
-
getSession as getSession2,
|
|
3736
|
-
getInitializedSessionCreateReplay,
|
|
3737
|
-
getSessionAuthorityProjection as getSessionAuthorityProjection4,
|
|
3738
|
-
SessionIdConflictError,
|
|
3739
|
-
NewSessionDraftConflictError,
|
|
3740
|
-
getWorkspaceControlEvent,
|
|
3741
|
-
getSessionLineage,
|
|
3742
|
-
getSessionTurn,
|
|
3743
|
-
getSessionTurnForAttempt as getSessionTurnForAttempt3,
|
|
3744
|
-
getSessionTurnPersonalConnectionDelegations as getSessionTurnPersonalConnectionDelegations2,
|
|
3745
|
-
getSessionTurnXaiProviderAccountAuthoritySnapshot,
|
|
3746
|
-
getWorkspaceModelPolicy,
|
|
3747
|
-
requireWorkspace as requireWorkspace4,
|
|
3748
|
-
initializeSessionStartAtomically,
|
|
3749
|
-
listSessionTurns,
|
|
3750
|
-
listSessionMcpServersForChildInheritance,
|
|
3751
|
-
requireSession as requireSession2,
|
|
3752
|
-
setActiveSandbox as setActiveSandbox2,
|
|
3753
|
-
setSubjectRlsContext,
|
|
3754
|
-
replaySubmittedHumanPromptFromBoundaryReceipt,
|
|
3755
|
-
submitHumanPromptInTransaction,
|
|
3756
|
-
appendSessionEventsWithLockedSessionUpdate,
|
|
3757
|
-
updateSessionTitleWithEvent,
|
|
3758
|
-
withWorkspaceSubjectSessionActivityRls,
|
|
3759
|
-
QueueCommandConflictError,
|
|
3760
|
-
AgentCommandAuthorityError,
|
|
3761
|
-
runIdempotentPersistenceTransaction,
|
|
3762
|
-
SessionSpawnDeniedDbError,
|
|
3763
|
-
SessionControlConflictError,
|
|
3764
|
-
SessionToolPolicyVersionConflictError,
|
|
3765
|
-
SessionCreateIdempotencyConflictError,
|
|
3766
|
-
PersonalResourceAttachmentAcceptanceError,
|
|
3767
|
-
sessionTenancyProductActivated as sessionTenancyProductActivated2,
|
|
3768
|
-
workspaceControlRequestLockTimeoutMs,
|
|
3769
|
-
WorkspaceControlBusyError
|
|
3770
|
-
} from "@opengeni/db";
|
|
3771
|
-
import {
|
|
3772
|
-
publishDurableSessionEvents as publishDurableSessionEvents2,
|
|
3773
|
-
publishDurableWorkspaceControlEvent
|
|
3774
|
-
} from "@opengeni/events";
|
|
3775
|
-
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
3776
|
-
|
|
3777
|
-
// src/domain/external-creation-attribution.ts
|
|
3778
|
-
import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
3779
|
-
var EXTERNAL_CREATION_ATTRIBUTION_KEY = "opengeniExternalCreationAttribution";
|
|
3780
|
-
function externalCreationMetadata(metadata, authorization, grant) {
|
|
3781
|
-
if (metadata && Object.hasOwn(metadata, EXTERNAL_CREATION_ATTRIBUTION_KEY)) {
|
|
3782
|
-
throw new HTTPException8(422, {
|
|
3783
|
-
message: `${EXTERNAL_CREATION_ATTRIBUTION_KEY} is server-owned`
|
|
3784
|
-
});
|
|
3785
|
-
}
|
|
3786
|
-
const attribution = externalAttributionForAuthorization(authorization, grant);
|
|
3787
|
-
if (!attribution) return metadata;
|
|
3788
|
-
return { ...metadata, [EXTERNAL_CREATION_ATTRIBUTION_KEY]: attribution };
|
|
3789
|
-
}
|
|
3790
|
-
|
|
3791
|
-
// src/application/external-link-work-admission.ts
|
|
3792
|
-
import { ExternalLinkWorkSnapshot } from "@opengeni/contracts/external-identities";
|
|
3793
|
-
import {
|
|
3794
|
-
captureExternalLinkTurnAuthority,
|
|
3795
|
-
captureExternalLinkTaskAuthority,
|
|
3796
|
-
getExternalLinkTurnSnapshot,
|
|
3797
|
-
getSessionTurnForAttempt as getSessionTurnForAttempt2
|
|
3798
|
-
} from "@opengeni/db";
|
|
3799
|
-
function snapshotFor(authorization) {
|
|
3800
|
-
const continuation = authorization ? externalActorContinuationForAuthorization(authorization) : null;
|
|
3801
|
-
return continuation?.actor.actingMode === "linked_native" ? ExternalLinkWorkSnapshot.parse({
|
|
3802
|
-
...continuation,
|
|
3803
|
-
permissions: [...authorization.grant.permissions]
|
|
3804
|
-
}) : null;
|
|
3805
|
-
}
|
|
3806
|
-
function prepareExternalLinkTurnAdmission(authorization) {
|
|
3807
|
-
const snapshot = snapshotFor(authorization);
|
|
3808
|
-
if (!snapshot || !authorization) return void 0;
|
|
3809
|
-
const workspaceId = authorization.grant.workspaceId;
|
|
3810
|
-
const accountId = authorization.grant.accountId;
|
|
3811
|
-
const commit = externalContinuationCommitAuthorizer(authorization);
|
|
3812
|
-
return async (tx, sessionId, turnId) => {
|
|
3813
|
-
await commit(tx);
|
|
3814
|
-
await captureExternalLinkTurnAuthority(tx, {
|
|
3815
|
-
accountId,
|
|
3816
|
-
workspaceId,
|
|
3817
|
-
sessionId,
|
|
3818
|
-
turnId,
|
|
3819
|
-
snapshot
|
|
3820
|
-
});
|
|
3821
|
-
};
|
|
3822
|
-
}
|
|
3823
|
-
function prepareExternalLinkTaskAdmission(authorization, actor) {
|
|
3824
|
-
const snapshot = snapshotFor(authorization);
|
|
3825
|
-
const commit = externalContinuationCommitAuthorizer(authorization);
|
|
3826
|
-
if (snapshot)
|
|
3827
|
-
return async (tx, task) => {
|
|
3828
|
-
await commit?.(tx);
|
|
3829
|
-
await captureExternalLinkTaskAuthority(tx, task, snapshot);
|
|
3830
|
-
};
|
|
3831
|
-
if (!actor) {
|
|
3832
|
-
return authorization && hasVerifiedOwningUserAuthorization(authorization) ? async () => {
|
|
3833
|
-
} : void 0;
|
|
3834
|
-
}
|
|
3835
|
-
return async (tx, task) => {
|
|
3836
|
-
const turn = await getSessionTurnForAttempt2(
|
|
3837
|
-
tx,
|
|
3838
|
-
task.workspaceId,
|
|
3839
|
-
actor.sessionId,
|
|
3840
|
-
actor.attemptId
|
|
3841
|
-
);
|
|
3842
|
-
if (!turn || turn.id !== actor.turnId || turn.executionGeneration !== actor.executionGeneration)
|
|
3843
|
-
throw new Error("Linked task creator attempt is no longer active");
|
|
3844
|
-
const inherited = await getExternalLinkTurnSnapshot(tx, task, actor.turnId);
|
|
3845
|
-
if (inherited) await captureExternalLinkTaskAuthority(tx, task, inherited);
|
|
3846
|
-
};
|
|
3847
|
-
}
|
|
3848
|
-
|
|
3849
|
-
// src/billing/limits.ts
|
|
3850
|
-
import {
|
|
3851
|
-
configuredStaticUsageLimits,
|
|
3852
|
-
resolveModelProviderForTurn
|
|
3853
|
-
} from "@opengeni/config";
|
|
3854
|
-
import {
|
|
3855
|
-
countActiveApiKeysForWorkspace,
|
|
3856
|
-
countActiveOrganizationApiKeysForAccount,
|
|
3857
|
-
countScheduledTasksForWorkspace,
|
|
3858
|
-
countWorkspacesForAccount,
|
|
3859
|
-
getBillingBalance,
|
|
3860
|
-
isCodexBilledTurn,
|
|
3861
|
-
recordUsageEvent,
|
|
3862
|
-
sumUsageQuantity
|
|
3863
|
-
} from "@opengeni/db";
|
|
3864
|
-
import { HTTPException as HTTPException9 } from "hono/http-exception";
|
|
3865
|
-
function modelFundingForAdmission(settings, model, codexBilled) {
|
|
3866
|
-
const resolvedModel = model ? resolveModelProviderForTurn(settings, model)?.model : null;
|
|
3867
|
-
const codexSubscriptionModel = resolvedModel?.credentialSource.kind === "connected_subscription" && resolvedModel.credentialSource.provider === "codex";
|
|
3868
|
-
return {
|
|
3869
|
-
// A Codex namespace/definition never bypasses credits by itself: the live
|
|
3870
|
-
// workspace credential predicate above remains authoritative. SuperGrok's
|
|
3871
|
-
// static overlay is likewise secret-free; its worker/provider admission
|
|
3872
|
-
// owns live account selection before any upstream request can occur.
|
|
3873
|
-
fundedWithoutCredits: codexBilled || resolvedModel != null && !codexSubscriptionModel && resolvedModel.cost !== "credits",
|
|
3874
|
-
countsTowardTokenCap: !codexBilled && resolvedModel != null && resolvedModel.billing.upstreamPayer === "deployment"
|
|
3875
|
-
};
|
|
3876
|
-
}
|
|
3877
|
-
async function requireLimit(deps, input) {
|
|
3878
|
-
const decision = await checkLimit(deps, input);
|
|
3879
|
-
if (decision.allowed) {
|
|
3880
|
-
return;
|
|
3881
|
-
}
|
|
3882
|
-
throw new HTTPException9(decision.code === "insufficient_credits" ? 402 : 429, {
|
|
3883
|
-
message: decision.message
|
|
3884
|
-
});
|
|
3885
|
-
}
|
|
3886
|
-
async function checkLimit(deps, input) {
|
|
3887
|
-
const codexBilled = input.workspaceId ? await isCodexBilledTurn({
|
|
3888
|
-
db: deps.db,
|
|
3889
|
-
settings: deps.settings,
|
|
3890
|
-
workspaceId: input.workspaceId,
|
|
3891
|
-
model: input.model
|
|
3892
|
-
}) : false;
|
|
3893
|
-
const { fundedWithoutCredits, countsTowardTokenCap } = modelFundingForAdmission(
|
|
3894
|
-
deps.settings,
|
|
3895
|
-
input.model,
|
|
3896
|
-
codexBilled
|
|
3897
|
-
);
|
|
3898
|
-
const creditDecision = await checkCreditBalance(deps, input, fundedWithoutCredits);
|
|
3899
|
-
if (!creditDecision.allowed) {
|
|
3900
|
-
return creditDecision;
|
|
3901
|
-
}
|
|
3902
|
-
if (deps.settings.usageLimitsMode !== "static" && deps.settings.usageLimitsMode !== "managed") {
|
|
3903
|
-
return { allowed: true };
|
|
3904
|
-
}
|
|
3905
|
-
return await checkStaticCaps(deps, input, {
|
|
3906
|
-
fundedWithoutCredits,
|
|
3907
|
-
countsTowardTokenCap
|
|
3908
|
-
});
|
|
3909
|
-
}
|
|
3910
|
-
async function checkCreditBalance(deps, input, externallyBilled) {
|
|
3911
|
-
if (externallyBilled) {
|
|
3912
|
-
return { allowed: true };
|
|
3913
|
-
}
|
|
3914
|
-
if (!usesCreditLimits(deps) || !isCostlyAction(input.action)) {
|
|
3915
|
-
return { allowed: true };
|
|
3916
|
-
}
|
|
3917
|
-
const balance = await getBillingBalance(deps.db, input.accountId);
|
|
3918
|
-
if (balance.balanceMicros > 0) {
|
|
3919
|
-
return { allowed: true };
|
|
3920
|
-
}
|
|
3921
|
-
return { allowed: false, code: "insufficient_credits", message: "insufficient OpenGeni credits" };
|
|
3922
|
-
}
|
|
3923
|
-
async function checkStaticCaps(deps, input, funding) {
|
|
3924
|
-
const limits = configuredStaticUsageLimits(deps.settings);
|
|
3925
|
-
if (limits.maxMonthlyCostMicrosPerAccount && isCostlyAction(input.action) && !funding.fundedWithoutCredits) {
|
|
3926
|
-
const used = await sumUsageQuantity(deps.db, {
|
|
3927
|
-
accountId: input.accountId,
|
|
3928
|
-
eventType: "model.cost",
|
|
3929
|
-
since: startOfUtcMonth()
|
|
3930
|
-
});
|
|
3931
|
-
if (used >= limits.maxMonthlyCostMicrosPerAccount) {
|
|
3932
|
-
return blocked(
|
|
3933
|
-
"max_monthly_cost_micros_per_account",
|
|
3934
|
-
`monthly model cost limit reached (${limits.maxMonthlyCostMicrosPerAccount} micros)`
|
|
3935
|
-
);
|
|
3936
|
-
}
|
|
3937
|
-
}
|
|
3938
|
-
switch (input.action) {
|
|
3939
|
-
case "workspace:create": {
|
|
3940
|
-
if (!limits.maxWorkspacesPerAccount) {
|
|
3941
|
-
return { allowed: true };
|
|
3942
|
-
}
|
|
3943
|
-
const count = await countWorkspacesForAccount(deps.db, input.accountId);
|
|
3944
|
-
return count < limits.maxWorkspacesPerAccount ? { allowed: true } : blocked(
|
|
3945
|
-
"max_workspaces_per_account",
|
|
3946
|
-
`workspace limit reached (${limits.maxWorkspacesPerAccount})`
|
|
3947
|
-
);
|
|
3948
|
-
}
|
|
3949
|
-
case "api_key:create": {
|
|
3950
|
-
if (!limits.maxApiKeysPerWorkspace) {
|
|
3951
|
-
return { allowed: true };
|
|
3952
|
-
}
|
|
3953
|
-
const count = input.workspaceId ? await countActiveApiKeysForWorkspace(deps.db, input.workspaceId) : await countActiveOrganizationApiKeysForAccount(deps.db, input.accountId);
|
|
3954
|
-
return count < limits.maxApiKeysPerWorkspace ? { allowed: true } : blocked(
|
|
3955
|
-
"max_api_keys_per_workspace",
|
|
3956
|
-
`API key limit reached (${limits.maxApiKeysPerWorkspace})`
|
|
3957
|
-
);
|
|
3958
|
-
}
|
|
3959
|
-
case "schedule:create": {
|
|
3960
|
-
if (!limits.maxSchedulesPerWorkspace || !input.workspaceId) {
|
|
3961
|
-
return { allowed: true };
|
|
3962
|
-
}
|
|
3963
|
-
const count = await countScheduledTasksForWorkspace(deps.db, input.workspaceId);
|
|
3964
|
-
return count < limits.maxSchedulesPerWorkspace ? { allowed: true } : blocked(
|
|
3965
|
-
"max_schedules_per_workspace",
|
|
3966
|
-
`scheduled task limit reached (${limits.maxSchedulesPerWorkspace})`
|
|
3967
|
-
);
|
|
3968
|
-
}
|
|
3969
|
-
case "file:upload": {
|
|
3970
|
-
if (!limits.maxFileUploadBytes || !input.quantity) {
|
|
3971
|
-
return { allowed: true };
|
|
3972
|
-
}
|
|
3973
|
-
return input.quantity <= limits.maxFileUploadBytes ? { allowed: true } : blocked(
|
|
3974
|
-
"max_file_upload_bytes",
|
|
3975
|
-
`file upload exceeds static limit of ${limits.maxFileUploadBytes} bytes`
|
|
3976
|
-
);
|
|
3977
|
-
}
|
|
3978
|
-
case "agent_run:create": {
|
|
3979
|
-
if (!limits.maxMonthlyAgentRunsPerWorkspace || !input.workspaceId) {
|
|
3980
|
-
return { allowed: true };
|
|
3981
|
-
}
|
|
3982
|
-
const used = await sumUsageQuantity(deps.db, {
|
|
3983
|
-
workspaceId: input.workspaceId,
|
|
3984
|
-
eventType: "agent_run.created",
|
|
3985
|
-
since: startOfUtcMonth()
|
|
3986
|
-
});
|
|
3987
|
-
const requested = input.quantity ?? 0;
|
|
3988
|
-
return used + requested <= limits.maxMonthlyAgentRunsPerWorkspace ? { allowed: true } : blocked(
|
|
3989
|
-
"max_monthly_agent_runs_per_workspace",
|
|
3990
|
-
`monthly agent run limit reached (${limits.maxMonthlyAgentRunsPerWorkspace})`
|
|
3991
|
-
);
|
|
3992
|
-
}
|
|
3993
|
-
case "tokens:consume": {
|
|
3994
|
-
if (!funding.countsTowardTokenCap || !limits.maxMonthlyTokensPerWorkspace || !input.workspaceId) {
|
|
3995
|
-
return { allowed: true };
|
|
3996
|
-
}
|
|
3997
|
-
const used = await sumUsageQuantity(deps.db, {
|
|
3998
|
-
workspaceId: input.workspaceId,
|
|
3999
|
-
eventType: "model.tokens",
|
|
4000
|
-
since: startOfUtcMonth()
|
|
4001
|
-
});
|
|
4002
|
-
const requested = input.quantity ?? 0;
|
|
4003
|
-
return used + requested <= limits.maxMonthlyTokensPerWorkspace ? { allowed: true } : blocked(
|
|
4004
|
-
"max_monthly_tokens_per_workspace",
|
|
4005
|
-
`monthly token limit reached (${limits.maxMonthlyTokensPerWorkspace})`
|
|
4006
|
-
);
|
|
4007
|
-
}
|
|
4008
|
-
case "document:index": {
|
|
4009
|
-
if (!limits.maxDocumentIndexedChunksPerWorkspace || !input.workspaceId) {
|
|
4010
|
-
return { allowed: true };
|
|
4011
|
-
}
|
|
4012
|
-
const used = await sumUsageQuantity(deps.db, {
|
|
4013
|
-
workspaceId: input.workspaceId,
|
|
4014
|
-
eventType: "document.indexed",
|
|
4015
|
-
since: startOfUtcMonth()
|
|
4016
|
-
});
|
|
4017
|
-
const requested = input.quantity ?? 0;
|
|
4018
|
-
return used + requested <= limits.maxDocumentIndexedChunksPerWorkspace ? { allowed: true } : blocked(
|
|
4019
|
-
"max_document_indexed_chunks_per_workspace",
|
|
4020
|
-
`monthly document indexing limit reached (${limits.maxDocumentIndexedChunksPerWorkspace} chunks)`
|
|
4021
|
-
);
|
|
4022
|
-
}
|
|
4023
|
-
}
|
|
4024
|
-
}
|
|
4025
|
-
async function recordWorkspaceUsage(deps, input) {
|
|
4026
|
-
await recordUsageEvent(deps.db, {
|
|
4027
|
-
accountId: input.accountId,
|
|
4028
|
-
workspaceId: input.workspaceId,
|
|
4029
|
-
subjectId: input.subjectId ?? null,
|
|
4030
|
-
eventType: input.eventType,
|
|
4031
|
-
quantity: input.quantity,
|
|
4032
|
-
unit: input.unit,
|
|
4033
|
-
sourceResourceType: input.sourceResourceType,
|
|
4034
|
-
sourceResourceId: input.sourceResourceId,
|
|
4035
|
-
sessionId: input.sessionId ?? null,
|
|
4036
|
-
turnId: input.turnId ?? null,
|
|
4037
|
-
turnAttemptId: input.turnAttemptId ?? null,
|
|
4038
|
-
initiator: input.initiator ?? (input.subjectId ? { kind: "subject", subjectId: input.subjectId } : null),
|
|
4039
|
-
...input.initiatorContext ? { initiatorContext: input.initiatorContext } : {},
|
|
4040
|
-
origin: input.origin ?? null,
|
|
4041
|
-
idempotencyKey: input.idempotencyKey
|
|
3989
|
+
executionGeneration: attempt.executionGeneration
|
|
3990
|
+
}
|
|
4042
3991
|
});
|
|
3992
|
+
const sessionAuthority = await getSessionAuthorityProjection3(
|
|
3993
|
+
deps.db,
|
|
3994
|
+
grant.workspaceId,
|
|
3995
|
+
sessionId
|
|
3996
|
+
);
|
|
3997
|
+
if (!sessionAuthority) throw new Error("File session authority unavailable");
|
|
3998
|
+
return {
|
|
3999
|
+
sessionAttachmentReadAccess: {
|
|
4000
|
+
sessionId,
|
|
4001
|
+
authorityEpoch: sessionAuthority.authorityEpoch,
|
|
4002
|
+
actor: attempt
|
|
4003
|
+
},
|
|
4004
|
+
subjectId: grant.subjectId,
|
|
4005
|
+
initiatingHumanSubjectId: attempt.initiatingHumanSubjectId,
|
|
4006
|
+
privateFileOwnerSubjectId: snapshot.defaultScope === "personal" ? snapshot.subjectId : null
|
|
4007
|
+
};
|
|
4043
4008
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4009
|
+
|
|
4010
|
+
// src/domain/sessions.ts
|
|
4011
|
+
import { CODEX_MODEL_ID_PREFIX, isCodexBilledModel } from "@opengeni/codex";
|
|
4012
|
+
|
|
4013
|
+
// src/site-session-origin.ts
|
|
4014
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
4015
|
+
var origins = new AsyncLocalStorage();
|
|
4016
|
+
function withSiteSessionOrigin(origin, run) {
|
|
4017
|
+
return origins.run(origin, run);
|
|
4046
4018
|
}
|
|
4047
|
-
function
|
|
4048
|
-
|
|
4019
|
+
function sessionCreationMetadata(metadata) {
|
|
4020
|
+
const { _opengeniSiteOrigin: _ignored, ...rest } = metadata;
|
|
4021
|
+
const origin = origins.getStore();
|
|
4022
|
+
return origin ? { ...rest, _opengeniSiteOrigin: origin } : rest;
|
|
4049
4023
|
}
|
|
4050
|
-
|
|
4051
|
-
|
|
4024
|
+
|
|
4025
|
+
// src/domain/sessions.ts
|
|
4026
|
+
import {
|
|
4027
|
+
canonicalizeConfiguredModelId,
|
|
4028
|
+
configuredAllowedModels,
|
|
4029
|
+
withCodexCatalogProvider as withCodexCatalogProvider2,
|
|
4030
|
+
ORGANIZATION_GATEWAY_MODEL_ID_PREFIX as ORGANIZATION_GATEWAY_MODEL_ID_PREFIX2,
|
|
4031
|
+
ORGANIZATION_OPENROUTER_MODEL_ID_PREFIX as ORGANIZATION_OPENROUTER_MODEL_ID_PREFIX2,
|
|
4032
|
+
resolveFirstPartyMcpToolPolicy,
|
|
4033
|
+
policyProviderIdForModel,
|
|
4034
|
+
resolveTurnExecutionPolicyV1,
|
|
4035
|
+
WORKSPACE_GATEWAY_MODEL_ID_PREFIX as WORKSPACE_GATEWAY_MODEL_ID_PREFIX2,
|
|
4036
|
+
WORKSPACE_OPENROUTER_MODEL_ID_PREFIX as WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2,
|
|
4037
|
+
XAI_SUBSCRIPTION_MODEL_ID_PREFIX
|
|
4038
|
+
} from "@opengeni/config";
|
|
4039
|
+
import {
|
|
4040
|
+
AUTOMATIC_SESSION_TITLE_FALLBACK,
|
|
4041
|
+
CreateSessionRequest,
|
|
4042
|
+
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
4043
|
+
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
4044
|
+
currentAgentLearningToolSelection,
|
|
4045
|
+
DraftTimelineAnnotations as DraftTimelineAnnotations2,
|
|
4046
|
+
FIRST_PARTY_MCP_TOOL_NAMES as FIRST_PARTY_MCP_TOOL_NAMES2,
|
|
4047
|
+
OPENGENI_SLACK_BOT_SESSION_METADATA_KEY as OPENGENI_SLACK_BOT_SESSION_METADATA_KEY2,
|
|
4048
|
+
SessionSkills,
|
|
4049
|
+
resolveBundledSkillSelection,
|
|
4050
|
+
SessionSpawnDenial,
|
|
4051
|
+
ServiceTurnInitiator,
|
|
4052
|
+
ServiceTurnInitiatorContext,
|
|
4053
|
+
evaluateWorkspaceModelPolicy as evaluateWorkspaceModelPolicy2,
|
|
4054
|
+
normalizeAutomaticSessionTitle,
|
|
4055
|
+
resolveWorkspaceSessionToolDefaults as resolveWorkspaceSessionToolDefaults2,
|
|
4056
|
+
metadataWithTurnExecutionPolicyV1,
|
|
4057
|
+
readTurnExecutionPolicyV1,
|
|
4058
|
+
stableJson as stableJson3,
|
|
4059
|
+
SessionMcpApprovalPolicy
|
|
4060
|
+
} from "@opengeni/contracts";
|
|
4061
|
+
import {
|
|
4062
|
+
assertExactNewSessionDraftInTransaction,
|
|
4063
|
+
createSession,
|
|
4064
|
+
createSessionWithIdempotencyKeyResult,
|
|
4065
|
+
canonicalSessionCommandHash,
|
|
4066
|
+
encryptVariableSetValue as encryptVariableSetValue2,
|
|
4067
|
+
getAnySessionInGroup,
|
|
4068
|
+
getEnrollment as getEnrollment2,
|
|
4069
|
+
getChannel,
|
|
4070
|
+
getRig as getRig2,
|
|
4071
|
+
getWorkspaceDefaultRigId,
|
|
4072
|
+
listDistinctVariableSetSelectionsInGroup,
|
|
4073
|
+
listDistinctRigVersionIdsInGroup,
|
|
4074
|
+
listInstalledPortableSkills,
|
|
4075
|
+
listEnabledMcpCapabilityServers as listEnabledMcpCapabilityServers2,
|
|
4076
|
+
requireApprovalWithFloor,
|
|
4077
|
+
getSandbox as getSandbox3,
|
|
4078
|
+
getSession as getSession2,
|
|
4079
|
+
getInitializedSessionCreateReplay,
|
|
4080
|
+
getSessionAuthorityProjection as getSessionAuthorityProjection4,
|
|
4081
|
+
SessionIdConflictError,
|
|
4082
|
+
NewSessionDraftConflictError,
|
|
4083
|
+
getWorkspaceControlEvent,
|
|
4084
|
+
getSessionLineage,
|
|
4085
|
+
getSessionTurn,
|
|
4086
|
+
getSessionTurnForAttempt as getSessionTurnForAttempt3,
|
|
4087
|
+
getSessionTurnPersonalConnectionDelegations as getSessionTurnPersonalConnectionDelegations2,
|
|
4088
|
+
getSessionTurnXaiProviderAccountAuthoritySnapshot,
|
|
4089
|
+
getWorkspaceModelPolicy,
|
|
4090
|
+
requireWorkspace as requireWorkspace4,
|
|
4091
|
+
initializeSessionStartAtomically,
|
|
4092
|
+
listSessionTurns,
|
|
4093
|
+
listSessionMcpServersForChildInheritance,
|
|
4094
|
+
requireSession as requireSession2,
|
|
4095
|
+
setActiveSandbox as setActiveSandbox2,
|
|
4096
|
+
setSubjectRlsContext,
|
|
4097
|
+
replaySubmittedHumanPromptFromBoundaryReceipt,
|
|
4098
|
+
submitHumanPromptInTransaction,
|
|
4099
|
+
appendSessionEventsWithLockedSessionUpdate,
|
|
4100
|
+
updateSessionTitleWithEvent,
|
|
4101
|
+
withWorkspaceSubjectSessionActivityRls,
|
|
4102
|
+
QueueCommandConflictError,
|
|
4103
|
+
AgentCommandAuthorityError,
|
|
4104
|
+
runIdempotentPersistenceTransaction,
|
|
4105
|
+
SessionSpawnDeniedDbError,
|
|
4106
|
+
SessionControlConflictError,
|
|
4107
|
+
SessionToolPolicyVersionConflictError,
|
|
4108
|
+
SessionCreateIdempotencyConflictError,
|
|
4109
|
+
PersonalResourceAttachmentAcceptanceError,
|
|
4110
|
+
sessionTenancyProductActivated as sessionTenancyProductActivated2,
|
|
4111
|
+
workspaceControlRequestLockTimeoutMs,
|
|
4112
|
+
WorkspaceControlBusyError
|
|
4113
|
+
} from "@opengeni/db";
|
|
4114
|
+
import {
|
|
4115
|
+
publishDurableSessionEvents as publishDurableSessionEvents2,
|
|
4116
|
+
publishDurableWorkspaceControlEvent
|
|
4117
|
+
} from "@opengeni/events";
|
|
4118
|
+
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
4119
|
+
|
|
4120
|
+
// src/domain/external-creation-attribution.ts
|
|
4121
|
+
import { HTTPException as HTTPException9 } from "hono/http-exception";
|
|
4122
|
+
var EXTERNAL_CREATION_ATTRIBUTION_KEY = "opengeniExternalCreationAttribution";
|
|
4123
|
+
function externalCreationMetadata(metadata, authorization, grant) {
|
|
4124
|
+
if (metadata && Object.hasOwn(metadata, EXTERNAL_CREATION_ATTRIBUTION_KEY)) {
|
|
4125
|
+
throw new HTTPException9(422, {
|
|
4126
|
+
message: `${EXTERNAL_CREATION_ATTRIBUTION_KEY} is server-owned`
|
|
4127
|
+
});
|
|
4128
|
+
}
|
|
4129
|
+
const attribution = externalAttributionForAuthorization(authorization, grant);
|
|
4130
|
+
if (!attribution) return metadata;
|
|
4131
|
+
return { ...metadata, [EXTERNAL_CREATION_ATTRIBUTION_KEY]: attribution };
|
|
4052
4132
|
}
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4133
|
+
|
|
4134
|
+
// src/application/external-link-work-admission.ts
|
|
4135
|
+
import { ExternalLinkWorkSnapshot } from "@opengeni/contracts/external-identities";
|
|
4136
|
+
import {
|
|
4137
|
+
captureExternalLinkTurnAuthority,
|
|
4138
|
+
captureExternalLinkTaskAuthority,
|
|
4139
|
+
getExternalLinkTurnSnapshot,
|
|
4140
|
+
getSessionTurnForAttempt as getSessionTurnForAttempt2
|
|
4141
|
+
} from "@opengeni/db";
|
|
4142
|
+
function snapshotFor(authorization) {
|
|
4143
|
+
const continuation = authorization ? externalActorContinuationForAuthorization(authorization) : null;
|
|
4144
|
+
return continuation?.actor.actingMode === "linked_native" ? ExternalLinkWorkSnapshot.parse({
|
|
4145
|
+
...continuation,
|
|
4146
|
+
permissions: [...authorization.grant.permissions]
|
|
4147
|
+
}) : null;
|
|
4148
|
+
}
|
|
4149
|
+
function prepareExternalLinkTurnAdmission(authorization) {
|
|
4150
|
+
const snapshot = snapshotFor(authorization);
|
|
4151
|
+
if (!snapshot || !authorization) return void 0;
|
|
4152
|
+
const workspaceId = authorization.grant.workspaceId;
|
|
4153
|
+
const accountId = authorization.grant.accountId;
|
|
4154
|
+
const commit = externalContinuationCommitAuthorizer(authorization);
|
|
4155
|
+
return async (tx, sessionId, turnId) => {
|
|
4156
|
+
await commit(tx);
|
|
4157
|
+
await captureExternalLinkTurnAuthority(tx, {
|
|
4158
|
+
accountId,
|
|
4159
|
+
workspaceId,
|
|
4160
|
+
sessionId,
|
|
4161
|
+
turnId,
|
|
4162
|
+
snapshot
|
|
4163
|
+
});
|
|
4164
|
+
};
|
|
4165
|
+
}
|
|
4166
|
+
function prepareExternalLinkTaskAdmission(authorization, actor) {
|
|
4167
|
+
const snapshot = snapshotFor(authorization);
|
|
4168
|
+
const commit = externalContinuationCommitAuthorizer(authorization);
|
|
4169
|
+
if (snapshot)
|
|
4170
|
+
return async (tx, task) => {
|
|
4171
|
+
await commit?.(tx);
|
|
4172
|
+
await captureExternalLinkTaskAuthority(tx, task, snapshot);
|
|
4173
|
+
};
|
|
4174
|
+
if (!actor) {
|
|
4175
|
+
return authorization && hasVerifiedOwningUserAuthorization(authorization) ? async () => {
|
|
4176
|
+
} : void 0;
|
|
4177
|
+
}
|
|
4178
|
+
return async (tx, task) => {
|
|
4179
|
+
const turn = await getSessionTurnForAttempt2(
|
|
4180
|
+
tx,
|
|
4181
|
+
task.workspaceId,
|
|
4182
|
+
actor.sessionId,
|
|
4183
|
+
actor.attemptId
|
|
4184
|
+
);
|
|
4185
|
+
if (!turn || turn.id !== actor.turnId || turn.executionGeneration !== actor.executionGeneration)
|
|
4186
|
+
throw new Error("Linked task creator attempt is no longer active");
|
|
4187
|
+
const inherited = await getExternalLinkTurnSnapshot(tx, task, actor.turnId);
|
|
4188
|
+
if (inherited) await captureExternalLinkTaskAuthority(tx, task, inherited);
|
|
4189
|
+
};
|
|
4056
4190
|
}
|
|
4057
4191
|
|
|
4058
4192
|
// src/domain/native-mcp-connection-admission.ts
|
|
@@ -4071,6 +4205,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|
|
4071
4205
|
import { isDeepStrictEqual } from "util";
|
|
4072
4206
|
import { withLockedCapabilityInstallation } from "@opengeni/db/capability-reconciliation";
|
|
4073
4207
|
import { environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2 } from "@opengeni/config";
|
|
4208
|
+
import { pinnedFetch } from "@opengeni/network";
|
|
4074
4209
|
import {
|
|
4075
4210
|
CapabilityCatalogItem,
|
|
4076
4211
|
capabilityCatalogItemIsTrustedForExposure,
|
|
@@ -4344,7 +4479,12 @@ async function prepareCapabilityEnable(input) {
|
|
|
4344
4479
|
assertRequiredMcpCredentialHeaders(item, headers, connectionRef);
|
|
4345
4480
|
installationMetadata = {
|
|
4346
4481
|
...installationMetadata,
|
|
4347
|
-
...connectionRef && !headers ? authDeferredMcpConnectivity() : await validateMcpCapabilityConnection(
|
|
4482
|
+
...connectionRef && !headers ? authDeferredMcpConnectivity() : await validateMcpCapabilityConnection(
|
|
4483
|
+
item,
|
|
4484
|
+
input.probeMcpServer,
|
|
4485
|
+
headers ?? void 0,
|
|
4486
|
+
input.settings
|
|
4487
|
+
)
|
|
4348
4488
|
};
|
|
4349
4489
|
if (connectionRef) {
|
|
4350
4490
|
installationConfig.connectionRef = connectionRef;
|
|
@@ -4591,7 +4731,7 @@ function requireCapabilityHeaderEncryption(settings) {
|
|
|
4591
4731
|
}
|
|
4592
4732
|
return key;
|
|
4593
4733
|
}
|
|
4594
|
-
async function validateMcpCapabilityConnection(item, probe = probeStreamableHttpMcpServer, headers) {
|
|
4734
|
+
async function validateMcpCapabilityConnection(item, probe = probeStreamableHttpMcpServer, headers, settings) {
|
|
4595
4735
|
if (item.kind !== "mcp") {
|
|
4596
4736
|
return {};
|
|
4597
4737
|
}
|
|
@@ -4606,7 +4746,8 @@ async function validateMcpCapabilityConnection(item, probe = probeStreamableHttp
|
|
|
4606
4746
|
name: item.name,
|
|
4607
4747
|
url: item.endpointUrl,
|
|
4608
4748
|
timeoutMs: mcpCapabilityProbeTimeoutMs,
|
|
4609
|
-
...headers ? { headers } : {}
|
|
4749
|
+
...headers ? { headers } : {},
|
|
4750
|
+
...settings ? { settings } : {}
|
|
4610
4751
|
});
|
|
4611
4752
|
return {
|
|
4612
4753
|
mcpConnectivity: {
|
|
@@ -4622,6 +4763,8 @@ async function validateMcpCapabilityConnection(item, probe = probeStreamableHttp
|
|
|
4622
4763
|
}
|
|
4623
4764
|
}
|
|
4624
4765
|
async function probeStreamableHttpMcpServer(input) {
|
|
4766
|
+
const settings = input.settings;
|
|
4767
|
+
if (!settings) throw new Error("Network policy is unavailable for MCP validation");
|
|
4625
4768
|
const controller = new AbortController();
|
|
4626
4769
|
const timeout = setTimeout(() => controller.abort(), input.timeoutMs);
|
|
4627
4770
|
const client = new Client(
|
|
@@ -4633,7 +4776,11 @@ async function probeStreamableHttpMcpServer(input) {
|
|
|
4633
4776
|
requestInit: {
|
|
4634
4777
|
signal: controller.signal,
|
|
4635
4778
|
...input.headers ? { headers: input.headers } : {}
|
|
4636
|
-
}
|
|
4779
|
+
},
|
|
4780
|
+
fetch: (url, init) => pinnedFetch(url, init, settings, {
|
|
4781
|
+
label: "MCP capability probe",
|
|
4782
|
+
requireHttpsOutsideLocalTest: true
|
|
4783
|
+
})
|
|
4637
4784
|
});
|
|
4638
4785
|
await client.connect(transport, {
|
|
4639
4786
|
timeout: input.timeoutMs,
|
|
@@ -5048,6 +5195,7 @@ function fikenCatalogItem(fikenConnections) {
|
|
|
5048
5195
|
metadata: {
|
|
5049
5196
|
connectorMode: "first_party_fiken",
|
|
5050
5197
|
ownership: "workspace",
|
|
5198
|
+
connectionStatus: fikenConnection?.status ?? null,
|
|
5051
5199
|
// Derived from the contracts catalog so a new fiken_* tool cannot be
|
|
5052
5200
|
// registered without also appearing on the capability tile.
|
|
5053
5201
|
firstPartyMcpTools: FIRST_PARTY_MCP_TOOL_NAMES.filter((name) => name.startsWith("fiken_"))
|
|
@@ -5249,15 +5397,15 @@ function socialProviderConnectionCounts(item) {
|
|
|
5249
5397
|
};
|
|
5250
5398
|
}
|
|
5251
5399
|
function applyCapabilityEnablement(item, installation) {
|
|
5400
|
+
if (item.surfaceType === "first_party_fiken") {
|
|
5401
|
+
return { ...item, connectionRef: null };
|
|
5402
|
+
}
|
|
5252
5403
|
if (item.kind === "skill" || item.kind === "api" || item.kind === "plugin") {
|
|
5253
5404
|
return { ...item, enabled: false, enabledReason: null, connectionRef: null };
|
|
5254
5405
|
}
|
|
5255
5406
|
if (isSocialProviderIntegration(item)) {
|
|
5256
5407
|
return { ...item, connectionRef: null };
|
|
5257
5408
|
}
|
|
5258
|
-
if (item.surfaceType === "first_party_fiken") {
|
|
5259
|
-
return { ...item, connectionRef: null };
|
|
5260
|
-
}
|
|
5261
5409
|
if (item.surfaceType === "codex_apps") {
|
|
5262
5410
|
return { ...item, connectionRef: null };
|
|
5263
5411
|
}
|
|
@@ -10136,6 +10284,39 @@ async function acceptSessionUserMessageWithOutcome(...args) {
|
|
|
10136
10284
|
return withSessionRlsActorContext4(actor, () => acceptSessionUserMessageInFileScope(...args));
|
|
10137
10285
|
}
|
|
10138
10286
|
|
|
10287
|
+
// src/domain/session-native-connection-replacement.ts
|
|
10288
|
+
import { connectionMetadataMatchesBinding } from "@opengeni/db/session-mcp-credential-rotation";
|
|
10289
|
+
function nativeSessionConnectionReplacement(input) {
|
|
10290
|
+
const connection = input.connections.find(
|
|
10291
|
+
(candidate) => candidate.id === input.nativeConnectionId
|
|
10292
|
+
);
|
|
10293
|
+
if (!connection || connection.accountId !== input.accountId || connection.status !== "active" || (connection.subjectId === null ? connection.workspaceId !== input.workspaceId : !input.subjectId || connection.subjectId !== input.subjectId || !connection.authorityId)) {
|
|
10294
|
+
throw new Error("native connection unavailable");
|
|
10295
|
+
}
|
|
10296
|
+
const {
|
|
10297
|
+
authoritySource: _authoritySource,
|
|
10298
|
+
hostBinding: _hostBinding,
|
|
10299
|
+
accountSelection: _accountSelection,
|
|
10300
|
+
...retained
|
|
10301
|
+
} = input.currentRef ?? {};
|
|
10302
|
+
if (input.currentRef && input.currentRef.providerDomain.toLowerCase() !== connection.providerDomain.toLowerCase())
|
|
10303
|
+
throw new Error("native connection provider mismatch");
|
|
10304
|
+
const ref = {
|
|
10305
|
+
...retained,
|
|
10306
|
+
...!input.currentRef?.resource && typeof connection.metadata.resource === "string" ? { resource: connection.metadata.resource } : {},
|
|
10307
|
+
connectionId: connection.id,
|
|
10308
|
+
providerDomain: connection.providerDomain,
|
|
10309
|
+
kind: connection.kind,
|
|
10310
|
+
subjectScope: connection.subjectId === null ? "workspace" : "subject"
|
|
10311
|
+
};
|
|
10312
|
+
const destination = input.replacementServerUrl ?? input.serverUrl;
|
|
10313
|
+
if (input.replacementServerUrl && (typeof connection.metadata.mcpUrl !== "string" || !connection.metadata.mcpUrl.trim()))
|
|
10314
|
+
throw new Error("native connection destination unavailable");
|
|
10315
|
+
if (!connectionMetadataMatchesBinding(connection, ref, destination))
|
|
10316
|
+
throw new Error("native connection binding mismatch");
|
|
10317
|
+
return ref;
|
|
10318
|
+
}
|
|
10319
|
+
|
|
10139
10320
|
// src/application/session-mcp-credential-rotation.ts
|
|
10140
10321
|
function sessionMcpRotationFingerprint(key, scope, request) {
|
|
10141
10322
|
return {
|
|
@@ -10167,9 +10348,14 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10167
10348
|
id: update.id,
|
|
10168
10349
|
expectedCredentialVersion: update.expectedCredentialVersion,
|
|
10169
10350
|
expectedServerUrl: update.expectedServerUrl,
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10351
|
+
..."nativeConnectionId" in update ? {
|
|
10352
|
+
nativeConnectionId: update.nativeConnectionId,
|
|
10353
|
+
...update.replacementServerUrl ? { replacementServerUrl: update.replacementServerUrl } : {}
|
|
10354
|
+
} : {
|
|
10355
|
+
headers: Object.fromEntries(
|
|
10356
|
+
Object.entries(normalizedSessionMcpCredentialHeaders(update.headers)).map(([name, value]) => [name.toLowerCase(), value]).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
10357
|
+
)
|
|
10358
|
+
}
|
|
10173
10359
|
})).sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0)
|
|
10174
10360
|
};
|
|
10175
10361
|
if (new Set(request.updates.map((update) => update.id)).size !== request.updates.length)
|
|
@@ -10185,20 +10371,43 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10185
10371
|
actorType: grant.principalKind === "service" ? "service" : "human"
|
|
10186
10372
|
};
|
|
10187
10373
|
const externalAuthorize = externalContinuationCommitAuthorizer(authorization);
|
|
10374
|
+
let authorizedGrant = grant;
|
|
10188
10375
|
try {
|
|
10189
10376
|
return await rotateSessionMcpCredentialsAtomically(deps.db, {
|
|
10190
10377
|
...scope,
|
|
10191
10378
|
operationKey: request.operationKey,
|
|
10192
10379
|
...sessionMcpRotationFingerprint(encryptionKey, scope, request),
|
|
10193
|
-
updates: request.updates.map(
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10380
|
+
updates: request.updates.map(
|
|
10381
|
+
(update) => "nativeConnectionId" in update ? update : {
|
|
10382
|
+
id: update.id,
|
|
10383
|
+
expectedCredentialVersion: update.expectedCredentialVersion,
|
|
10384
|
+
expectedServerUrl: update.expectedServerUrl,
|
|
10385
|
+
headersEncrypted: Object.fromEntries(
|
|
10386
|
+
Object.entries(update.headers).map(([name, value]) => [
|
|
10387
|
+
name,
|
|
10388
|
+
encryptVariableSetValue3(encryptionKey, value)
|
|
10389
|
+
])
|
|
10390
|
+
)
|
|
10391
|
+
}
|
|
10392
|
+
),
|
|
10393
|
+
resolveNativeConnection: async (tx, server, nativeConnectionId, replacementServerUrl) => {
|
|
10394
|
+
const connections = await listOwnConnectionAccountsForGrant(tx, authorizedGrant);
|
|
10395
|
+
const source = personalConnectionDelegationSourceForGrant(authorizedGrant);
|
|
10396
|
+
try {
|
|
10397
|
+
return nativeSessionConnectionReplacement({
|
|
10398
|
+
accountId: grant.accountId,
|
|
10399
|
+
workspaceId: grant.workspaceId,
|
|
10400
|
+
subjectId: source.kind === "subject" ? source.subjectId : null,
|
|
10401
|
+
serverUrl: server.url,
|
|
10402
|
+
...replacementServerUrl ? { replacementServerUrl } : {},
|
|
10403
|
+
currentRef: server.connectionRef,
|
|
10404
|
+
nativeConnectionId,
|
|
10405
|
+
connections
|
|
10406
|
+
});
|
|
10407
|
+
} catch {
|
|
10408
|
+
throw new SessionMcpCredentialRotationError("connection_unavailable");
|
|
10409
|
+
}
|
|
10410
|
+
},
|
|
10202
10411
|
authorize: async (tx) => {
|
|
10203
10412
|
await externalAuthorize?.(tx);
|
|
10204
10413
|
const fresh = await reauthorize(tx);
|
|
@@ -10221,6 +10430,7 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10221
10430
|
operation: "session.mcp.credentials.rotate",
|
|
10222
10431
|
surface: "http"
|
|
10223
10432
|
});
|
|
10433
|
+
authorizedGrant = fresh;
|
|
10224
10434
|
}
|
|
10225
10435
|
});
|
|
10226
10436
|
} catch (error) {
|
|
@@ -10231,7 +10441,7 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10231
10441
|
if (error instanceof SessionAuthorizationUnavailableError)
|
|
10232
10442
|
throw new HTTPException16(503, { message: "credential rotation authorization unavailable" });
|
|
10233
10443
|
if (error instanceof SessionMcpCredentialRotationError) {
|
|
10234
|
-
const status = error.code === "receipt_key_unavailable" ? 503 : error.code === "authority_revoked" ? 403 : error.code === "not_found" ? 404 : error.code === "invalid_request" || error.code === "brokered_server" ? 422 : 409;
|
|
10444
|
+
const status = error.code === "receipt_key_unavailable" ? 503 : error.code === "authority_revoked" ? 403 : error.code === "not_found" ? 404 : error.code === "invalid_request" || error.code === "brokered_server" || error.code === "connection_unavailable" ? 422 : 409;
|
|
10235
10445
|
throw new HTTPException16(status, { message: `credential_rotation_${error.code}` });
|
|
10236
10446
|
}
|
|
10237
10447
|
throw new HTTPException16(503, { message: "credential rotation unavailable" });
|
|
@@ -10672,7 +10882,7 @@ function sha256Hex2(bytes) {
|
|
|
10672
10882
|
}
|
|
10673
10883
|
|
|
10674
10884
|
// src/domain/skill-search.ts
|
|
10675
|
-
import { pinnedFetch, readResponseJsonBounded } from "@opengeni/network";
|
|
10885
|
+
import { pinnedFetch as pinnedFetch2, readResponseJsonBounded } from "@opengeni/network";
|
|
10676
10886
|
var PublicSkillSearchError = class extends Error {
|
|
10677
10887
|
constructor(code, message, retryAfterSeconds = null) {
|
|
10678
10888
|
super(message);
|
|
@@ -10687,7 +10897,7 @@ var maxResponseBytes = 256 * 1024;
|
|
|
10687
10897
|
var maxResults = 20;
|
|
10688
10898
|
var ownerPattern = /^[a-z0-9](?:[a-z0-9-]{0,38})$/iu;
|
|
10689
10899
|
var segmentPattern = /^[a-z0-9](?:[a-z0-9._-]{0,98}[a-z0-9])?$/iu;
|
|
10690
|
-
function createPublicSkillSearchClient(settings, fetcher =
|
|
10900
|
+
function createPublicSkillSearchClient(settings, fetcher = pinnedFetch2) {
|
|
10691
10901
|
return {
|
|
10692
10902
|
async search(input) {
|
|
10693
10903
|
const query = input.query.trim();
|
|
@@ -10814,7 +11024,7 @@ function parseRetryAfter(value) {
|
|
|
10814
11024
|
|
|
10815
11025
|
// src/domain/github-skill-source.ts
|
|
10816
11026
|
import { HTTPException as HTTPException19 } from "hono/http-exception";
|
|
10817
|
-
import { pinnedFetch as
|
|
11027
|
+
import { pinnedFetch as pinnedFetch3, readResponseJsonBounded as readResponseJsonBounded2, readResponseTextBounded } from "@opengeni/network";
|
|
10818
11028
|
import {
|
|
10819
11029
|
PORTABLE_SKILL_MAX_FILES as PORTABLE_SKILL_MAX_FILES2,
|
|
10820
11030
|
PORTABLE_SKILL_MAX_FILE_BYTES as PORTABLE_SKILL_MAX_FILE_BYTES2,
|
|
@@ -10915,7 +11125,7 @@ function createGitHubSkillSourceClient(settings, requestJson = (path, maxBytes,
|
|
|
10915
11125
|
}
|
|
10916
11126
|
async function downloadSkillSnapshot(settings, owner, repository, slug) {
|
|
10917
11127
|
const signal = AbortSignal.timeout(githubRequestTimeoutMs);
|
|
10918
|
-
const response = await
|
|
11128
|
+
const response = await pinnedFetch3(
|
|
10919
11129
|
`https://skills.sh/api/download/${[owner, repository, slug].map(encodeURIComponent).join("/")}`,
|
|
10920
11130
|
{ headers: { accept: "application/json" }, credentials: "omit", redirect: "manual", signal },
|
|
10921
11131
|
settings,
|
|
@@ -10950,7 +11160,7 @@ async function githubJson(settings, path, maxBytes, label) {
|
|
|
10950
11160
|
const controller = new AbortController();
|
|
10951
11161
|
const timeout = setTimeout(() => controller.abort(), githubRequestTimeoutMs);
|
|
10952
11162
|
try {
|
|
10953
|
-
const response = await
|
|
11163
|
+
const response = await pinnedFetch3(
|
|
10954
11164
|
`${githubApiBase}${path}`,
|
|
10955
11165
|
{
|
|
10956
11166
|
method: "GET",
|
|
@@ -17339,7 +17549,7 @@ var CATALOG_PAGE_SIZE = 25;
|
|
|
17339
17549
|
var CATALOG_PAGE_BUDGET = 40;
|
|
17340
17550
|
var DESCRIPTION_CHARS = 2e3;
|
|
17341
17551
|
var CATALOG_BYTES = 256 * 1024;
|
|
17342
|
-
async function prepareKnowledgeSave(db, context, input, embedder, services = defaults) {
|
|
17552
|
+
async function prepareKnowledgeSave(db, context, input, embedder, services = defaults, settings) {
|
|
17343
17553
|
const request = KnowledgeSavePreparationRequest.parse(input);
|
|
17344
17554
|
if (context.actor.kind !== "agent" && !(context.actor.kind === "human" && context.actor.review)) {
|
|
17345
17555
|
throw Object.assign(
|
|
@@ -17364,20 +17574,31 @@ async function prepareKnowledgeSave(db, context, input, embedder, services = def
|
|
|
17364
17574
|
complete: true,
|
|
17365
17575
|
nextCursors: { published: null, needs_review: null }
|
|
17366
17576
|
};
|
|
17367
|
-
const
|
|
17368
|
-
|
|
17369
|
-
|
|
17370
|
-
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
|
|
17379
|
-
|
|
17380
|
-
|
|
17577
|
+
const paid = settings != null && paidDocumentEmbedding(settings);
|
|
17578
|
+
const published = await services.search(
|
|
17579
|
+
db,
|
|
17580
|
+
context,
|
|
17581
|
+
{
|
|
17582
|
+
query: request.query,
|
|
17583
|
+
limit: request.limit,
|
|
17584
|
+
view: "published",
|
|
17585
|
+
...paid ? { mode: "keyword" } : {}
|
|
17586
|
+
},
|
|
17587
|
+
sharedEmbedder,
|
|
17588
|
+
paid ? void 0 : settings
|
|
17589
|
+
);
|
|
17590
|
+
const needsReview = await services.search(
|
|
17591
|
+
db,
|
|
17592
|
+
context,
|
|
17593
|
+
{
|
|
17594
|
+
query: request.query,
|
|
17595
|
+
limit: request.limit,
|
|
17596
|
+
view: "needs_review",
|
|
17597
|
+
...published.searchMode === "keyword" ? { mode: "keyword" } : {}
|
|
17598
|
+
},
|
|
17599
|
+
sharedEmbedder
|
|
17600
|
+
);
|
|
17601
|
+
const matches = { published, needs_review: needsReview };
|
|
17381
17602
|
for (const view of ["published", "needs_review"]) {
|
|
17382
17603
|
if (request.collectionCursors && request.collectionCursors[view] === null) continue;
|
|
17383
17604
|
let cursor = request.collectionCursors?.[view] ?? void 0;
|
|
@@ -17786,6 +18007,8 @@ export {
|
|
|
17786
18007
|
InMemoryEditableArtifactLiveTicketStore,
|
|
17787
18008
|
InMemoryEditableArtifactStableIdFactory,
|
|
17788
18009
|
InMemoryEditableArtifactStore,
|
|
18010
|
+
KnowledgeVectorFundingError,
|
|
18011
|
+
KnowledgeVectorQueryRejectedError,
|
|
17789
18012
|
MAX_CHECKS_PER_RIG,
|
|
17790
18013
|
MAX_CREDENTIAL_HOOKS_PER_RIG,
|
|
17791
18014
|
MAX_DEFAULT_VARIABLE_SETS_PER_RIG,
|
|
@@ -17934,6 +18157,7 @@ export {
|
|
|
17934
18157
|
directRetainedProcessMatchesBackend,
|
|
17935
18158
|
disableCapability,
|
|
17936
18159
|
discoverMcpRegistryCapabilities,
|
|
18160
|
+
documentEmbeddingCostMicros,
|
|
17937
18161
|
editHumanQueuePrompt,
|
|
17938
18162
|
editableArtifactActorKey,
|
|
17939
18163
|
editableArtifactAuthorizationRevisionPortFromPostgres,
|
|
@@ -18076,6 +18300,7 @@ export {
|
|
|
18076
18300
|
openGeniSlackBotMetadata,
|
|
18077
18301
|
organizationIntegrationCatalog,
|
|
18078
18302
|
organizationMembershipHttpStatus,
|
|
18303
|
+
paidDocumentEmbedding,
|
|
18079
18304
|
parseGitHubRepositoryCoordinates,
|
|
18080
18305
|
parseSkillSource,
|
|
18081
18306
|
personalAtlassianDelegationsFromVisibleConnections,
|