@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/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 { listKnowledgeEntries } from "@opengeni/db";
1382
- async function searchKnowledgeEntries(db, context, input, embedder) {
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
- let embedding;
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(db, context, { ...retrievalRequest, mode: "keyword" }),
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 HTTPException4 } from "hono/http-exception";
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 HTTPException4(403, {
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 HTTPException4(403, { message: "membership exceeds key authority" });
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 HTTPException4(403, { message: "membership authority changed" });
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 HTTPException4(403, {
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 HTTPException4(409, {
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 HTTPException4(status, {
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 HTTPException4(403, {
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 HTTPException4(422, { message: "Invalid external identity reference" });
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 HTTPException4(422, { message: "Invalid external grant cancellation" });
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 HTTPException5 } from "hono/http-exception";
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 HTTPException5(403, {
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 HTTPException5(422, { message: "invalid external identity transition" });
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 HTTPException6 } from "hono/http-exception";
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 HTTPException6(denied2 ? 403 : 503, {
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 HTTPException7 } from "hono/http-exception";
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 HTTPException7(422, {
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 HTTPException7(503, {
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 HTTPException7(404, { message: "variableSet not found" });
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 HTTPException7(422, { message: "unknown variableSetId" });
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
- function usesCreditLimits(deps) {
4045
- return deps.settings.billingMode === "stripe" || deps.settings.usageLimitsMode === "managed";
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 isCostlyAction(action) {
4048
- return action === "agent_run:create" || action === "tokens:consume" || action === "document:index";
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
- function blocked(code, message) {
4051
- return { allowed: false, code, message };
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
- function startOfUtcMonth() {
4054
- const now = /* @__PURE__ */ new Date();
4055
- return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
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(item, input.probeMcpServer, headers ?? void 0)
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
- headers: Object.fromEntries(
10171
- Object.entries(normalizedSessionMcpCredentialHeaders(update.headers)).map(([name, value]) => [name.toLowerCase(), value]).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
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(({ headers, ...update }) => ({
10194
- ...update,
10195
- headersEncrypted: Object.fromEntries(
10196
- Object.entries(headers).map(([name, value]) => [
10197
- name,
10198
- encryptVariableSetValue3(encryptionKey, value)
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 = pinnedFetch) {
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 pinnedFetch2, readResponseJsonBounded as readResponseJsonBounded2, readResponseTextBounded } from "@opengeni/network";
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 pinnedFetch2(
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 pinnedFetch2(
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 matches = {
17368
- published: await services.search(
17369
- db,
17370
- context,
17371
- { query: request.query, limit: request.limit, view: "published" },
17372
- sharedEmbedder
17373
- ),
17374
- needs_review: await services.search(
17375
- db,
17376
- context,
17377
- { query: request.query, limit: request.limit, view: "needs_review" },
17378
- sharedEmbedder
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,