@opengeni/core 4.0.1 → 4.0.3-canary.36199476632001
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 +21 -5
- package/dist/billing/limits.d.ts +4 -0
- package/dist/default-session-model.d.ts +110 -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/domain/sessions.d.ts +9 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +929 -384
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/application/new-session-drafts.ts +101 -22
- package/src/application/session-mcp-credential-rotation.ts +57 -15
- package/src/billing/limits.ts +24 -3
- package/src/default-session-model.ts +467 -0
- 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/src/domain/sessions.ts +42 -7
- package/src/index.ts +1 -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
|
|
@@ -1980,6 +2323,270 @@ function resolveWorkspaceModelSelection(input) {
|
|
|
1980
2323
|
});
|
|
1981
2324
|
}
|
|
1982
2325
|
|
|
2326
|
+
// src/default-session-model.ts
|
|
2327
|
+
import {
|
|
2328
|
+
canonicalizeConfiguredModelId
|
|
2329
|
+
} from "@opengeni/config";
|
|
2330
|
+
import {
|
|
2331
|
+
resolveWorkspaceSessionDefaults
|
|
2332
|
+
} from "@opengeni/contracts";
|
|
2333
|
+
import {
|
|
2334
|
+
getScheduledTaskXaiProviderAccountAuthoritySnapshot,
|
|
2335
|
+
getSession as getSession2,
|
|
2336
|
+
getWorkspace,
|
|
2337
|
+
getWorkspaceConnectionModelRestrictions,
|
|
2338
|
+
getWorkspaceModelPolicy,
|
|
2339
|
+
listOrganizationModelProviderCustomModelsForWorkspace as listOrganizationModelProviderCustomModelsForWorkspace2,
|
|
2340
|
+
listWorkspaceGatewayCustomModels as listWorkspaceGatewayCustomModels2,
|
|
2341
|
+
listWorkspaceOpenRouterCustomModels as listWorkspaceOpenRouterCustomModels2,
|
|
2342
|
+
organizationModelProviderConnectionActiveForWorkspace,
|
|
2343
|
+
workspaceCodexSubscriptionActive,
|
|
2344
|
+
workspaceOpenRouterConnectionActive,
|
|
2345
|
+
workspaceVercelAiGatewayConnectionActive,
|
|
2346
|
+
organizationHoldsCredits,
|
|
2347
|
+
workspaceXaiSubscriptionActive,
|
|
2348
|
+
workspaceXaiSubscriptionActiveForAuthority,
|
|
2349
|
+
XaiAuthorityPoolInactiveError
|
|
2350
|
+
} from "@opengeni/db";
|
|
2351
|
+
var REASONING_EFFORT_ORDER = [
|
|
2352
|
+
"none",
|
|
2353
|
+
"minimal",
|
|
2354
|
+
"low",
|
|
2355
|
+
"medium",
|
|
2356
|
+
"high",
|
|
2357
|
+
"xhigh",
|
|
2358
|
+
"max"
|
|
2359
|
+
];
|
|
2360
|
+
function supportedReasoningEfforts(model) {
|
|
2361
|
+
const efforts = model.capabilities.reasoning.efforts;
|
|
2362
|
+
return REASONING_EFFORT_ORDER.filter((effort) => efforts.includes(effort));
|
|
2363
|
+
}
|
|
2364
|
+
function defaultReasoningEffortForConfiguredModel(model, fallback) {
|
|
2365
|
+
const options = supportedReasoningEfforts(model);
|
|
2366
|
+
if (options.length === 0) return fallback;
|
|
2367
|
+
const configured = model.capabilities.reasoning.defaultEffort;
|
|
2368
|
+
if (configured && options.includes(configured)) return configured;
|
|
2369
|
+
return options[0];
|
|
2370
|
+
}
|
|
2371
|
+
function clampReasoningEffortForConfiguredModel(model, preferred, fallback) {
|
|
2372
|
+
const options = supportedReasoningEfforts(model);
|
|
2373
|
+
if (options.length === 0) return fallback;
|
|
2374
|
+
if (options.includes(preferred)) return preferred;
|
|
2375
|
+
const ceiling = REASONING_EFFORT_ORDER.indexOf(preferred);
|
|
2376
|
+
const below = options.filter((effort) => REASONING_EFFORT_ORDER.indexOf(effort) <= ceiling);
|
|
2377
|
+
return below.at(-1) ?? defaultReasoningEffortForConfiguredModel(model, fallback);
|
|
2378
|
+
}
|
|
2379
|
+
function findSelection(selections, modelId) {
|
|
2380
|
+
return selections.find((selection) => selection.model.id === modelId) ?? selections.find((selection) => selection.model.aliases.includes(modelId));
|
|
2381
|
+
}
|
|
2382
|
+
function creditsCandidate(input) {
|
|
2383
|
+
const fallbackEffort = input.settings.openaiReasoningEffort;
|
|
2384
|
+
const deployment = findSelection(input.selections, input.settings.openaiModel);
|
|
2385
|
+
if (deployment?.availability.selectable && deployment.model.cost === "credits") return null;
|
|
2386
|
+
const configured = findSelection(input.selections, input.settings.creditsDefaultModel);
|
|
2387
|
+
if (configured?.availability.selectable && configured.model.cost === "credits") {
|
|
2388
|
+
return {
|
|
2389
|
+
model: configured.model.id,
|
|
2390
|
+
reasoningEffort: clampReasoningEffortForConfiguredModel(
|
|
2391
|
+
configured.model,
|
|
2392
|
+
input.settings.creditsDefaultReasoningEffort,
|
|
2393
|
+
fallbackEffort
|
|
2394
|
+
),
|
|
2395
|
+
source: "credits"
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2398
|
+
const first = input.selections.find(
|
|
2399
|
+
(selection) => selection.availability.selectable && selection.model.cost === "credits"
|
|
2400
|
+
);
|
|
2401
|
+
return first ? {
|
|
2402
|
+
model: first.model.id,
|
|
2403
|
+
reasoningEffort: defaultReasoningEffortForConfiguredModel(first.model, fallbackEffort),
|
|
2404
|
+
source: "credits"
|
|
2405
|
+
} : null;
|
|
2406
|
+
}
|
|
2407
|
+
function selectDefaultSessionModel(input) {
|
|
2408
|
+
const fallbackEffort = input.settings.openaiReasoningEffort;
|
|
2409
|
+
if (input.workspaceDefaults) {
|
|
2410
|
+
const saved = findSelection(input.selections, input.workspaceDefaults.model);
|
|
2411
|
+
if (saved?.availability.selectable) {
|
|
2412
|
+
return {
|
|
2413
|
+
model: saved.model.id,
|
|
2414
|
+
reasoningEffort: clampReasoningEffortForConfiguredModel(
|
|
2415
|
+
saved.model,
|
|
2416
|
+
input.workspaceDefaults.reasoningEffort,
|
|
2417
|
+
fallbackEffort
|
|
2418
|
+
),
|
|
2419
|
+
source: "workspace"
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
const deployment = findSelection(input.selections, input.settings.openaiModel);
|
|
2424
|
+
const subscription = deployment?.availability.selectable && deployment.model.cost === "subscription" ? deployment : input.selections.find(
|
|
2425
|
+
(selection) => selection.availability.selectable && selection.model.cost === "subscription"
|
|
2426
|
+
);
|
|
2427
|
+
if (subscription) {
|
|
2428
|
+
return {
|
|
2429
|
+
model: subscription.model.id,
|
|
2430
|
+
reasoningEffort: defaultReasoningEffortForConfiguredModel(subscription.model, fallbackEffort),
|
|
2431
|
+
source: "subscription"
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
if (input.creditsAvailable) {
|
|
2435
|
+
const credits = creditsCandidate(input);
|
|
2436
|
+
if (credits) return credits;
|
|
2437
|
+
}
|
|
2438
|
+
return {
|
|
2439
|
+
model: deployment?.model.id ?? canonicalizeConfiguredModelId(input.settings, input.settings.openaiModel),
|
|
2440
|
+
reasoningEffort: fallbackEffort,
|
|
2441
|
+
source: "deployment"
|
|
2442
|
+
};
|
|
2443
|
+
}
|
|
2444
|
+
function creditsDefaultSessionModel(input) {
|
|
2445
|
+
if (input.settings.billingMode !== "stripe") return null;
|
|
2446
|
+
return selectDefaultSessionModel({
|
|
2447
|
+
settings: input.settings,
|
|
2448
|
+
selections: input.selections,
|
|
2449
|
+
workspaceDefaults: resolveWorkspaceSessionDefaults(input.workspaceSettings),
|
|
2450
|
+
creditsAvailable: true
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
async function resolveDefaultSessionModelForSelections(db, input) {
|
|
2454
|
+
const decision = {
|
|
2455
|
+
settings: input.settings,
|
|
2456
|
+
selections: input.selections,
|
|
2457
|
+
workspaceDefaults: resolveWorkspaceSessionDefaults(input.workspaceSettings)
|
|
2458
|
+
};
|
|
2459
|
+
const withoutCredits = selectDefaultSessionModel({ ...decision, creditsAvailable: false });
|
|
2460
|
+
if (withoutCredits.source !== "deployment" || input.settings.billingMode !== "stripe" || creditsCandidate(decision) === null) {
|
|
2461
|
+
return withoutCredits;
|
|
2462
|
+
}
|
|
2463
|
+
return await organizationHoldsCredits(db, input.accountId) ? selectDefaultSessionModel({ ...decision, creditsAvailable: true }) : withoutCredits;
|
|
2464
|
+
}
|
|
2465
|
+
async function connectionRestrictionsAndXaiReadiness(db, settings, context) {
|
|
2466
|
+
const { workspaceId, subjectId, xaiAuthoritySnapshot } = context;
|
|
2467
|
+
if (!xaiAuthoritySnapshot) {
|
|
2468
|
+
const [restrictions2, xaiSubscriptionActive] = await Promise.all([
|
|
2469
|
+
getWorkspaceConnectionModelRestrictions(db, workspaceId, subjectId),
|
|
2470
|
+
workspaceXaiSubscriptionActive(db, settings, workspaceId, subjectId)
|
|
2471
|
+
]);
|
|
2472
|
+
return { restrictions: restrictions2, xaiSubscriptionActive };
|
|
2473
|
+
}
|
|
2474
|
+
const frozen = await Promise.allSettled([
|
|
2475
|
+
getWorkspaceConnectionModelRestrictions(db, workspaceId, subjectId, xaiAuthoritySnapshot),
|
|
2476
|
+
workspaceXaiSubscriptionActiveForAuthority(db, settings, {
|
|
2477
|
+
workspaceId,
|
|
2478
|
+
subjectId,
|
|
2479
|
+
authoritySnapshot: xaiAuthoritySnapshot
|
|
2480
|
+
})
|
|
2481
|
+
]);
|
|
2482
|
+
const [restrictions, readiness] = frozen;
|
|
2483
|
+
if (restrictions.status === "fulfilled" && readiness.status === "fulfilled") {
|
|
2484
|
+
return { restrictions: restrictions.value, xaiSubscriptionActive: readiness.value };
|
|
2485
|
+
}
|
|
2486
|
+
for (const result of frozen) {
|
|
2487
|
+
if (result.status === "rejected" && !(result.reason instanceof XaiAuthorityPoolInactiveError)) {
|
|
2488
|
+
throw result.reason;
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
const current = await getWorkspaceConnectionModelRestrictions(db, workspaceId, subjectId);
|
|
2492
|
+
return {
|
|
2493
|
+
restrictions: { ...current, "supergrok/": [] },
|
|
2494
|
+
xaiSubscriptionActive: false
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
async function loadWorkspaceModelSelectionInput(db, settings, context) {
|
|
2498
|
+
const { accountId, workspaceId } = context;
|
|
2499
|
+
const [
|
|
2500
|
+
{ restrictions: connectionModelRestrictions, xaiSubscriptionActive },
|
|
2501
|
+
policy,
|
|
2502
|
+
codexSubscriptionActive,
|
|
2503
|
+
workspaceGatewayConnectionActive,
|
|
2504
|
+
workspaceGatewayCustomModels,
|
|
2505
|
+
openRouterConnectionActive,
|
|
2506
|
+
workspaceOpenRouterCustomModels,
|
|
2507
|
+
organizationGatewayConnectionActive,
|
|
2508
|
+
organizationOpenRouterConnectionActive,
|
|
2509
|
+
organizationGatewayCustomModels,
|
|
2510
|
+
organizationOpenRouterCustomModels
|
|
2511
|
+
] = await Promise.all([
|
|
2512
|
+
connectionRestrictionsAndXaiReadiness(db, settings, context),
|
|
2513
|
+
getWorkspaceModelPolicy(db, workspaceId),
|
|
2514
|
+
workspaceCodexSubscriptionActive(db, settings, workspaceId),
|
|
2515
|
+
workspaceVercelAiGatewayConnectionActive(db, workspaceId),
|
|
2516
|
+
listWorkspaceGatewayCustomModels2(db, { accountId, workspaceId }),
|
|
2517
|
+
workspaceOpenRouterConnectionActive(db, workspaceId),
|
|
2518
|
+
listWorkspaceOpenRouterCustomModels2(db, { accountId, workspaceId }),
|
|
2519
|
+
organizationModelProviderConnectionActiveForWorkspace(db, {
|
|
2520
|
+
accountId,
|
|
2521
|
+
workspaceId,
|
|
2522
|
+
providerKind: "vercel_gateway"
|
|
2523
|
+
}),
|
|
2524
|
+
organizationModelProviderConnectionActiveForWorkspace(db, {
|
|
2525
|
+
accountId,
|
|
2526
|
+
workspaceId,
|
|
2527
|
+
providerKind: "openrouter"
|
|
2528
|
+
}),
|
|
2529
|
+
listOrganizationModelProviderCustomModelsForWorkspace2(db, {
|
|
2530
|
+
accountId,
|
|
2531
|
+
workspaceId,
|
|
2532
|
+
providerKind: "vercel_gateway"
|
|
2533
|
+
}),
|
|
2534
|
+
listOrganizationModelProviderCustomModelsForWorkspace2(db, {
|
|
2535
|
+
accountId,
|
|
2536
|
+
workspaceId,
|
|
2537
|
+
providerKind: "openrouter"
|
|
2538
|
+
})
|
|
2539
|
+
]);
|
|
2540
|
+
return {
|
|
2541
|
+
connectionModelRestrictions,
|
|
2542
|
+
settings,
|
|
2543
|
+
policy,
|
|
2544
|
+
codexSubscriptionActive,
|
|
2545
|
+
xaiSubscriptionActive,
|
|
2546
|
+
workspaceGatewayConnectionActive,
|
|
2547
|
+
workspaceGatewayCustomModels,
|
|
2548
|
+
workspaceOpenRouterConnectionActive: openRouterConnectionActive,
|
|
2549
|
+
workspaceOpenRouterCustomModels,
|
|
2550
|
+
organizationGatewayConnectionActive,
|
|
2551
|
+
organizationOpenRouterConnectionActive,
|
|
2552
|
+
organizationGatewayCustomModels,
|
|
2553
|
+
organizationOpenRouterCustomModels
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
async function resolveDefaultSessionModel(db, settings, context) {
|
|
2557
|
+
const [selectionInput, workspaceSettings] = await Promise.all([
|
|
2558
|
+
loadWorkspaceModelSelectionInput(db, settings, context),
|
|
2559
|
+
context.workspaceSettings !== void 0 ? Promise.resolve(context.workspaceSettings) : getWorkspace(db, context.workspaceId).then((workspace) => workspace?.settings ?? {})
|
|
2560
|
+
]);
|
|
2561
|
+
return await resolveDefaultSessionModelForSelections(db, {
|
|
2562
|
+
settings,
|
|
2563
|
+
accountId: context.accountId,
|
|
2564
|
+
workspaceSettings,
|
|
2565
|
+
selections: resolveWorkspaceModelSelection(selectionInput)
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
async function resolveScheduledTaskDefaultModel(db, settings, task) {
|
|
2569
|
+
return await resolveDefaultSessionModel(db, settings, {
|
|
2570
|
+
accountId: task.accountId,
|
|
2571
|
+
workspaceId: task.workspaceId,
|
|
2572
|
+
subjectId: task.ownerSubjectId ?? task.createdBy.subjectId,
|
|
2573
|
+
xaiAuthoritySnapshot: await getScheduledTaskXaiProviderAccountAuthoritySnapshot(
|
|
2574
|
+
db,
|
|
2575
|
+
task.workspaceId,
|
|
2576
|
+
task.id
|
|
2577
|
+
)
|
|
2578
|
+
});
|
|
2579
|
+
}
|
|
2580
|
+
async function resolveScheduledTaskPreflightModel(db, settings, task) {
|
|
2581
|
+
if (task.agentConfig.model) return task.agentConfig.model;
|
|
2582
|
+
const targetSessionId = task.runMode === "existing_session" ? task.targetSessionId : task.runMode === "reusable_session" ? task.reusableSessionId : null;
|
|
2583
|
+
if (targetSessionId) {
|
|
2584
|
+
const session = await getSession2(db, task.workspaceId, targetSessionId);
|
|
2585
|
+
if (session) return session.model;
|
|
2586
|
+
}
|
|
2587
|
+
return (await resolveScheduledTaskDefaultModel(db, settings, task)).model;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
1983
2590
|
// src/sandbox/fleet.ts
|
|
1984
2591
|
import {
|
|
1985
2592
|
authorizePersonalMachineForAttempt,
|
|
@@ -3272,7 +3879,7 @@ async function provisionSandbox(services, ctx, input) {
|
|
|
3272
3879
|
}
|
|
3273
3880
|
|
|
3274
3881
|
// src/application/external-workspace-members.ts
|
|
3275
|
-
import { HTTPException as
|
|
3882
|
+
import { HTTPException as HTTPException5 } from "hono/http-exception";
|
|
3276
3883
|
import {
|
|
3277
3884
|
AddExternalWorkspaceMemberRequest,
|
|
3278
3885
|
ExternalIdentityReference,
|
|
@@ -3308,12 +3915,12 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3308
3915
|
const context = await requireAccessContext(c, deps);
|
|
3309
3916
|
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
3310
3917
|
if (!authority)
|
|
3311
|
-
throw new
|
|
3918
|
+
throw new HTTPException5(403, {
|
|
3312
3919
|
message: "external onboarding requires an organization service key"
|
|
3313
3920
|
});
|
|
3314
3921
|
const grant = await requireFreshAccessGrant(c, deps, workspaceId, "members:manage");
|
|
3315
3922
|
if (grant.accountId !== authority.accountId || payload.permissions.some((permission) => !hasPermission(grant.permissions, permission))) {
|
|
3316
|
-
throw new
|
|
3923
|
+
throw new HTTPException5(403, { message: "membership exceeds key authority" });
|
|
3317
3924
|
}
|
|
3318
3925
|
if (payload.operationId) {
|
|
3319
3926
|
try {
|
|
@@ -3339,11 +3946,11 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3339
3946
|
"members:manage"
|
|
3340
3947
|
);
|
|
3341
3948
|
if (live.accountId !== grant.accountId || live.subjectId !== grant.subjectId || payload.permissions.some((permission) => !hasPermission(live.permissions, permission))) {
|
|
3342
|
-
throw new
|
|
3949
|
+
throw new HTTPException5(403, { message: "membership authority changed" });
|
|
3343
3950
|
}
|
|
3344
3951
|
const workspace = await requireWorkspace2(tx, workspaceId);
|
|
3345
3952
|
if (workspace.kind !== "shared" || workspace.accountId !== authority.accountId)
|
|
3346
|
-
throw new
|
|
3953
|
+
throw new HTTPException5(403, {
|
|
3347
3954
|
message: "external onboarding requires a shared organization workspace"
|
|
3348
3955
|
});
|
|
3349
3956
|
const identity = await ensureExternalIdentity2(tx, {
|
|
@@ -3357,7 +3964,7 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3357
3964
|
const permissions = [...new Set(payload.permissions)];
|
|
3358
3965
|
if (existing) {
|
|
3359
3966
|
if (existing.permissions.length !== permissions.length || existing.permissions.some((permission) => !permissions.includes(permission))) {
|
|
3360
|
-
throw new
|
|
3967
|
+
throw new HTTPException5(409, {
|
|
3361
3968
|
message: "existing membership differs; onboarding does not overwrite permissions"
|
|
3362
3969
|
});
|
|
3363
3970
|
}
|
|
@@ -3376,7 +3983,7 @@ async function addExternalWorkspaceMemberForRequest(c, deps, workspaceId, input)
|
|
|
3376
3983
|
function rethrowExternalWorkspaceOperation(error) {
|
|
3377
3984
|
const status = organizationMembershipHttpStatus(nestedPostgresSqlState2(error));
|
|
3378
3985
|
if (status)
|
|
3379
|
-
throw new
|
|
3986
|
+
throw new HTTPException5(status, {
|
|
3380
3987
|
message: status === 409 ? "External membership operation changed or was cancelled" : "External membership operation is not available"
|
|
3381
3988
|
});
|
|
3382
3989
|
throw error;
|
|
@@ -3385,7 +3992,7 @@ async function externalService(c, deps, organizationId) {
|
|
|
3385
3992
|
const context = await requireAccessContext(c, deps);
|
|
3386
3993
|
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
3387
3994
|
if (!authority || authority.accountId !== organizationId || !hasPermission(authority.permissions, "members:manage")) {
|
|
3388
|
-
throw new
|
|
3995
|
+
throw new HTTPException5(403, {
|
|
3389
3996
|
message: "External membership operation requires an organization service key"
|
|
3390
3997
|
});
|
|
3391
3998
|
}
|
|
@@ -3395,7 +4002,7 @@ async function lookupExternalIdentityForRequest(c, deps, organizationId, input)
|
|
|
3395
4002
|
const service = await externalService(c, deps, organizationId);
|
|
3396
4003
|
const identity = ExternalIdentityReference.safeParse(input);
|
|
3397
4004
|
if (!identity.success)
|
|
3398
|
-
throw new
|
|
4005
|
+
throw new HTTPException5(422, { message: "Invalid external identity reference" });
|
|
3399
4006
|
try {
|
|
3400
4007
|
return await lookupExternalIdentity(deps.db, service, identity.data);
|
|
3401
4008
|
} catch (error) {
|
|
@@ -3406,7 +4013,7 @@ async function cancelExternalWorkspaceMemberGrantForRequest(c, deps, organizatio
|
|
|
3406
4013
|
const service = await externalService(c, deps, organizationId);
|
|
3407
4014
|
const request = CancelExternalWorkspaceMemberGrantRequest.safeParse(input);
|
|
3408
4015
|
if (!request.success)
|
|
3409
|
-
throw new
|
|
4016
|
+
throw new HTTPException5(422, { message: "Invalid external grant cancellation" });
|
|
3410
4017
|
try {
|
|
3411
4018
|
return await cancelExternalWorkspaceMemberGrant(
|
|
3412
4019
|
deps.db,
|
|
@@ -3419,7 +4026,7 @@ async function cancelExternalWorkspaceMemberGrantForRequest(c, deps, organizatio
|
|
|
3419
4026
|
}
|
|
3420
4027
|
|
|
3421
4028
|
// src/application/external-identity-lifecycle.ts
|
|
3422
|
-
import { HTTPException as
|
|
4029
|
+
import { HTTPException as HTTPException6 } from "hono/http-exception";
|
|
3423
4030
|
import { UpdateExternalIdentityMembershipRequest } from "@opengeni/contracts/external-identities";
|
|
3424
4031
|
import { updateOrganizationMember } from "@opengeni/db";
|
|
3425
4032
|
async function updateExternalIdentityMembershipForRequest(context, deps, organizationId, membershipId, input) {
|
|
@@ -3429,13 +4036,13 @@ async function updateExternalIdentityMembershipForRequest(context, deps, organiz
|
|
|
3429
4036
|
(grant) => grant.accountId === organizationId && grant.subjectId === access.subjectId
|
|
3430
4037
|
);
|
|
3431
4038
|
if (!service || service.accountId !== organizationId || !account?.permissions.includes("account:admin")) {
|
|
3432
|
-
throw new
|
|
4039
|
+
throw new HTTPException6(403, {
|
|
3433
4040
|
message: "external identity administration requires an organization service key"
|
|
3434
4041
|
});
|
|
3435
4042
|
}
|
|
3436
4043
|
const parsed = UpdateExternalIdentityMembershipRequest.safeParse(input);
|
|
3437
4044
|
if (!parsed.success)
|
|
3438
|
-
throw new
|
|
4045
|
+
throw new HTTPException6(422, { message: "invalid external identity transition" });
|
|
3439
4046
|
return updateOrganizationMember(deps.db, {
|
|
3440
4047
|
organizationId,
|
|
3441
4048
|
membershipId,
|
|
@@ -3457,7 +4064,7 @@ import {
|
|
|
3457
4064
|
nestedPostgresSqlState as nestedPostgresSqlState3,
|
|
3458
4065
|
withWorkspaceSubjectRls as withWorkspaceSubjectRls3
|
|
3459
4066
|
} from "@opengeni/db";
|
|
3460
|
-
import { HTTPException as
|
|
4067
|
+
import { HTTPException as HTTPException7 } from "hono/http-exception";
|
|
3461
4068
|
function externalContinuationCommitAuthorizer(authorization) {
|
|
3462
4069
|
const continuation = authorization ? externalActorContinuationForAuthorization(authorization) : null;
|
|
3463
4070
|
if (!continuation || !authorization) return void 0;
|
|
@@ -3472,7 +4079,7 @@ function externalContinuationCommitAuthorizer(authorization) {
|
|
|
3472
4079
|
await requireExternalContinuationAuthority(tx, continuation, scope, permissions);
|
|
3473
4080
|
} catch (error) {
|
|
3474
4081
|
const denied2 = nestedPostgresSqlState3(error) === "42501" || error instanceof Error && error.message === "External continuation authority unavailable";
|
|
3475
|
-
throw new
|
|
4082
|
+
throw new HTTPException7(denied2 ? 403 : 503, {
|
|
3476
4083
|
message: denied2 ? "external authority changed" : "external authority is unavailable",
|
|
3477
4084
|
cause: error
|
|
3478
4085
|
});
|
|
@@ -3537,12 +4144,12 @@ import {
|
|
|
3537
4144
|
variableSetVariableNameReservation
|
|
3538
4145
|
} from "@opengeni/contracts";
|
|
3539
4146
|
import { getVariableSet, recordAuditEvent } from "@opengeni/db";
|
|
3540
|
-
import { HTTPException as
|
|
4147
|
+
import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
3541
4148
|
var MAX_ENVIRONMENTS_PER_WORKSPACE = 25;
|
|
3542
4149
|
var MAX_VARIABLES_PER_ENVIRONMENT = 100;
|
|
3543
4150
|
function assertAllowedVariableSetVariableName(name) {
|
|
3544
4151
|
if (variableSetVariableNameReservation(name)) {
|
|
3545
|
-
throw new
|
|
4152
|
+
throw new HTTPException8(422, {
|
|
3546
4153
|
message: `reserved variable set variable name / reserved environment variable name: ${name}`
|
|
3547
4154
|
});
|
|
3548
4155
|
}
|
|
@@ -3551,7 +4158,7 @@ var assertAllowedEnvironmentVariableName = assertAllowedVariableSetVariableName;
|
|
|
3551
4158
|
function requireVariableSetEncryption(settings) {
|
|
3552
4159
|
const key = environmentsEncryptionKeyBytes(settings);
|
|
3553
4160
|
if (!key) {
|
|
3554
|
-
throw new
|
|
4161
|
+
throw new HTTPException8(503, {
|
|
3555
4162
|
message: "variable sets require OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY"
|
|
3556
4163
|
});
|
|
3557
4164
|
}
|
|
@@ -3569,7 +4176,7 @@ async function requireVariableSetForApi(db, grant, variableSetId) {
|
|
|
3569
4176
|
variableSetId
|
|
3570
4177
|
);
|
|
3571
4178
|
if (!variableSet) {
|
|
3572
|
-
throw new
|
|
4179
|
+
throw new HTTPException8(404, { message: "variableSet not found" });
|
|
3573
4180
|
}
|
|
3574
4181
|
return variableSet;
|
|
3575
4182
|
}
|
|
@@ -3583,7 +4190,7 @@ async function validateVariableSetAttachment(deps, grant, workspaceId, variableS
|
|
|
3583
4190
|
variableSetId
|
|
3584
4191
|
);
|
|
3585
4192
|
if (!variableSet) {
|
|
3586
|
-
throw new
|
|
4193
|
+
throw new HTTPException8(422, { message: "unknown variableSetId" });
|
|
3587
4194
|
}
|
|
3588
4195
|
return variableSet;
|
|
3589
4196
|
}
|
|
@@ -3681,7 +4288,7 @@ function sessionCreationMetadata(metadata) {
|
|
|
3681
4288
|
|
|
3682
4289
|
// src/domain/sessions.ts
|
|
3683
4290
|
import {
|
|
3684
|
-
canonicalizeConfiguredModelId,
|
|
4291
|
+
canonicalizeConfiguredModelId as canonicalizeConfiguredModelId2,
|
|
3685
4292
|
configuredAllowedModels,
|
|
3686
4293
|
withCodexCatalogProvider as withCodexCatalogProvider2,
|
|
3687
4294
|
ORGANIZATION_GATEWAY_MODEL_ID_PREFIX as ORGANIZATION_GATEWAY_MODEL_ID_PREFIX2,
|
|
@@ -3691,7 +4298,8 @@ import {
|
|
|
3691
4298
|
resolveTurnExecutionPolicyV1,
|
|
3692
4299
|
WORKSPACE_GATEWAY_MODEL_ID_PREFIX as WORKSPACE_GATEWAY_MODEL_ID_PREFIX2,
|
|
3693
4300
|
WORKSPACE_OPENROUTER_MODEL_ID_PREFIX as WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2,
|
|
3694
|
-
XAI_SUBSCRIPTION_MODEL_ID_PREFIX
|
|
4301
|
+
XAI_SUBSCRIPTION_MODEL_ID_PREFIX,
|
|
4302
|
+
codeSearchDeploymentPolicy
|
|
3695
4303
|
} from "@opengeni/config";
|
|
3696
4304
|
import {
|
|
3697
4305
|
AUTOMATIC_SESSION_TITLE_FALLBACK,
|
|
@@ -3732,7 +4340,7 @@ import {
|
|
|
3732
4340
|
listEnabledMcpCapabilityServers as listEnabledMcpCapabilityServers2,
|
|
3733
4341
|
requireApprovalWithFloor,
|
|
3734
4342
|
getSandbox as getSandbox3,
|
|
3735
|
-
getSession as
|
|
4343
|
+
getSession as getSession3,
|
|
3736
4344
|
getInitializedSessionCreateReplay,
|
|
3737
4345
|
getSessionAuthorityProjection as getSessionAuthorityProjection4,
|
|
3738
4346
|
SessionIdConflictError,
|
|
@@ -3743,7 +4351,7 @@ import {
|
|
|
3743
4351
|
getSessionTurnForAttempt as getSessionTurnForAttempt3,
|
|
3744
4352
|
getSessionTurnPersonalConnectionDelegations as getSessionTurnPersonalConnectionDelegations2,
|
|
3745
4353
|
getSessionTurnXaiProviderAccountAuthoritySnapshot,
|
|
3746
|
-
getWorkspaceModelPolicy,
|
|
4354
|
+
getWorkspaceModelPolicy as getWorkspaceModelPolicy2,
|
|
3747
4355
|
requireWorkspace as requireWorkspace4,
|
|
3748
4356
|
initializeSessionStartAtomically,
|
|
3749
4357
|
listSessionTurns,
|
|
@@ -3772,287 +4380,78 @@ import {
|
|
|
3772
4380
|
publishDurableSessionEvents as publishDurableSessionEvents2,
|
|
3773
4381
|
publishDurableWorkspaceControlEvent
|
|
3774
4382
|
} from "@opengeni/events";
|
|
3775
|
-
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
3776
|
-
|
|
3777
|
-
// src/domain/external-creation-attribution.ts
|
|
3778
|
-
import { HTTPException as
|
|
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
|
|
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()
|
|
4383
|
+
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
4384
|
+
|
|
4385
|
+
// src/domain/external-creation-attribution.ts
|
|
4386
|
+
import { HTTPException as HTTPException9 } from "hono/http-exception";
|
|
4387
|
+
var EXTERNAL_CREATION_ATTRIBUTION_KEY = "opengeniExternalCreationAttribution";
|
|
4388
|
+
function externalCreationMetadata(metadata, authorization, grant) {
|
|
4389
|
+
if (metadata && Object.hasOwn(metadata, EXTERNAL_CREATION_ATTRIBUTION_KEY)) {
|
|
4390
|
+
throw new HTTPException9(422, {
|
|
4391
|
+
message: `${EXTERNAL_CREATION_ATTRIBUTION_KEY} is server-owned`
|
|
3930
4392
|
});
|
|
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
4393
|
}
|
|
4394
|
+
const attribution = externalAttributionForAuthorization(authorization, grant);
|
|
4395
|
+
if (!attribution) return metadata;
|
|
4396
|
+
return { ...metadata, [EXTERNAL_CREATION_ATTRIBUTION_KEY]: attribution };
|
|
4024
4397
|
}
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
origin: input.origin ?? null,
|
|
4041
|
-
idempotencyKey: input.idempotencyKey
|
|
4042
|
-
});
|
|
4043
|
-
}
|
|
4044
|
-
function usesCreditLimits(deps) {
|
|
4045
|
-
return deps.settings.billingMode === "stripe" || deps.settings.usageLimitsMode === "managed";
|
|
4046
|
-
}
|
|
4047
|
-
function isCostlyAction(action) {
|
|
4048
|
-
return action === "agent_run:create" || action === "tokens:consume" || action === "document:index";
|
|
4398
|
+
|
|
4399
|
+
// src/application/external-link-work-admission.ts
|
|
4400
|
+
import { ExternalLinkWorkSnapshot } from "@opengeni/contracts/external-identities";
|
|
4401
|
+
import {
|
|
4402
|
+
captureExternalLinkTurnAuthority,
|
|
4403
|
+
captureExternalLinkTaskAuthority,
|
|
4404
|
+
getExternalLinkTurnSnapshot,
|
|
4405
|
+
getSessionTurnForAttempt as getSessionTurnForAttempt2
|
|
4406
|
+
} from "@opengeni/db";
|
|
4407
|
+
function snapshotFor(authorization) {
|
|
4408
|
+
const continuation = authorization ? externalActorContinuationForAuthorization(authorization) : null;
|
|
4409
|
+
return continuation?.actor.actingMode === "linked_native" ? ExternalLinkWorkSnapshot.parse({
|
|
4410
|
+
...continuation,
|
|
4411
|
+
permissions: [...authorization.grant.permissions]
|
|
4412
|
+
}) : null;
|
|
4049
4413
|
}
|
|
4050
|
-
function
|
|
4051
|
-
|
|
4414
|
+
function prepareExternalLinkTurnAdmission(authorization) {
|
|
4415
|
+
const snapshot = snapshotFor(authorization);
|
|
4416
|
+
if (!snapshot || !authorization) return void 0;
|
|
4417
|
+
const workspaceId = authorization.grant.workspaceId;
|
|
4418
|
+
const accountId = authorization.grant.accountId;
|
|
4419
|
+
const commit = externalContinuationCommitAuthorizer(authorization);
|
|
4420
|
+
return async (tx, sessionId, turnId) => {
|
|
4421
|
+
await commit(tx);
|
|
4422
|
+
await captureExternalLinkTurnAuthority(tx, {
|
|
4423
|
+
accountId,
|
|
4424
|
+
workspaceId,
|
|
4425
|
+
sessionId,
|
|
4426
|
+
turnId,
|
|
4427
|
+
snapshot
|
|
4428
|
+
});
|
|
4429
|
+
};
|
|
4052
4430
|
}
|
|
4053
|
-
function
|
|
4054
|
-
const
|
|
4055
|
-
|
|
4431
|
+
function prepareExternalLinkTaskAdmission(authorization, actor) {
|
|
4432
|
+
const snapshot = snapshotFor(authorization);
|
|
4433
|
+
const commit = externalContinuationCommitAuthorizer(authorization);
|
|
4434
|
+
if (snapshot)
|
|
4435
|
+
return async (tx, task) => {
|
|
4436
|
+
await commit?.(tx);
|
|
4437
|
+
await captureExternalLinkTaskAuthority(tx, task, snapshot);
|
|
4438
|
+
};
|
|
4439
|
+
if (!actor) {
|
|
4440
|
+
return authorization && hasVerifiedOwningUserAuthorization(authorization) ? async () => {
|
|
4441
|
+
} : void 0;
|
|
4442
|
+
}
|
|
4443
|
+
return async (tx, task) => {
|
|
4444
|
+
const turn = await getSessionTurnForAttempt2(
|
|
4445
|
+
tx,
|
|
4446
|
+
task.workspaceId,
|
|
4447
|
+
actor.sessionId,
|
|
4448
|
+
actor.attemptId
|
|
4449
|
+
);
|
|
4450
|
+
if (!turn || turn.id !== actor.turnId || turn.executionGeneration !== actor.executionGeneration)
|
|
4451
|
+
throw new Error("Linked task creator attempt is no longer active");
|
|
4452
|
+
const inherited = await getExternalLinkTurnSnapshot(tx, task, actor.turnId);
|
|
4453
|
+
if (inherited) await captureExternalLinkTaskAuthority(tx, task, inherited);
|
|
4454
|
+
};
|
|
4056
4455
|
}
|
|
4057
4456
|
|
|
4058
4457
|
// src/domain/native-mcp-connection-admission.ts
|
|
@@ -4071,6 +4470,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|
|
4071
4470
|
import { isDeepStrictEqual } from "util";
|
|
4072
4471
|
import { withLockedCapabilityInstallation } from "@opengeni/db/capability-reconciliation";
|
|
4073
4472
|
import { environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2 } from "@opengeni/config";
|
|
4473
|
+
import { pinnedFetch } from "@opengeni/network";
|
|
4074
4474
|
import {
|
|
4075
4475
|
CapabilityCatalogItem,
|
|
4076
4476
|
capabilityCatalogItemIsTrustedForExposure,
|
|
@@ -4344,7 +4744,12 @@ async function prepareCapabilityEnable(input) {
|
|
|
4344
4744
|
assertRequiredMcpCredentialHeaders(item, headers, connectionRef);
|
|
4345
4745
|
installationMetadata = {
|
|
4346
4746
|
...installationMetadata,
|
|
4347
|
-
...connectionRef && !headers ? authDeferredMcpConnectivity() : await validateMcpCapabilityConnection(
|
|
4747
|
+
...connectionRef && !headers ? authDeferredMcpConnectivity() : await validateMcpCapabilityConnection(
|
|
4748
|
+
item,
|
|
4749
|
+
input.probeMcpServer,
|
|
4750
|
+
headers ?? void 0,
|
|
4751
|
+
input.settings
|
|
4752
|
+
)
|
|
4348
4753
|
};
|
|
4349
4754
|
if (connectionRef) {
|
|
4350
4755
|
installationConfig.connectionRef = connectionRef;
|
|
@@ -4591,7 +4996,7 @@ function requireCapabilityHeaderEncryption(settings) {
|
|
|
4591
4996
|
}
|
|
4592
4997
|
return key;
|
|
4593
4998
|
}
|
|
4594
|
-
async function validateMcpCapabilityConnection(item, probe = probeStreamableHttpMcpServer, headers) {
|
|
4999
|
+
async function validateMcpCapabilityConnection(item, probe = probeStreamableHttpMcpServer, headers, settings) {
|
|
4595
5000
|
if (item.kind !== "mcp") {
|
|
4596
5001
|
return {};
|
|
4597
5002
|
}
|
|
@@ -4606,7 +5011,8 @@ async function validateMcpCapabilityConnection(item, probe = probeStreamableHttp
|
|
|
4606
5011
|
name: item.name,
|
|
4607
5012
|
url: item.endpointUrl,
|
|
4608
5013
|
timeoutMs: mcpCapabilityProbeTimeoutMs,
|
|
4609
|
-
...headers ? { headers } : {}
|
|
5014
|
+
...headers ? { headers } : {},
|
|
5015
|
+
...settings ? { settings } : {}
|
|
4610
5016
|
});
|
|
4611
5017
|
return {
|
|
4612
5018
|
mcpConnectivity: {
|
|
@@ -4622,6 +5028,8 @@ async function validateMcpCapabilityConnection(item, probe = probeStreamableHttp
|
|
|
4622
5028
|
}
|
|
4623
5029
|
}
|
|
4624
5030
|
async function probeStreamableHttpMcpServer(input) {
|
|
5031
|
+
const settings = input.settings;
|
|
5032
|
+
if (!settings) throw new Error("Network policy is unavailable for MCP validation");
|
|
4625
5033
|
const controller = new AbortController();
|
|
4626
5034
|
const timeout = setTimeout(() => controller.abort(), input.timeoutMs);
|
|
4627
5035
|
const client = new Client(
|
|
@@ -4633,7 +5041,11 @@ async function probeStreamableHttpMcpServer(input) {
|
|
|
4633
5041
|
requestInit: {
|
|
4634
5042
|
signal: controller.signal,
|
|
4635
5043
|
...input.headers ? { headers: input.headers } : {}
|
|
4636
|
-
}
|
|
5044
|
+
},
|
|
5045
|
+
fetch: (url, init) => pinnedFetch(url, init, settings, {
|
|
5046
|
+
label: "MCP capability probe",
|
|
5047
|
+
requireHttpsOutsideLocalTest: true
|
|
5048
|
+
})
|
|
4637
5049
|
});
|
|
4638
5050
|
await client.connect(transport, {
|
|
4639
5051
|
timeout: input.timeoutMs,
|
|
@@ -5048,6 +5460,7 @@ function fikenCatalogItem(fikenConnections) {
|
|
|
5048
5460
|
metadata: {
|
|
5049
5461
|
connectorMode: "first_party_fiken",
|
|
5050
5462
|
ownership: "workspace",
|
|
5463
|
+
connectionStatus: fikenConnection?.status ?? null,
|
|
5051
5464
|
// Derived from the contracts catalog so a new fiken_* tool cannot be
|
|
5052
5465
|
// registered without also appearing on the capability tile.
|
|
5053
5466
|
firstPartyMcpTools: FIRST_PARTY_MCP_TOOL_NAMES.filter((name) => name.startsWith("fiken_"))
|
|
@@ -5249,15 +5662,15 @@ function socialProviderConnectionCounts(item) {
|
|
|
5249
5662
|
};
|
|
5250
5663
|
}
|
|
5251
5664
|
function applyCapabilityEnablement(item, installation) {
|
|
5665
|
+
if (item.surfaceType === "first_party_fiken") {
|
|
5666
|
+
return { ...item, connectionRef: null };
|
|
5667
|
+
}
|
|
5252
5668
|
if (item.kind === "skill" || item.kind === "api" || item.kind === "plugin") {
|
|
5253
5669
|
return { ...item, enabled: false, enabledReason: null, connectionRef: null };
|
|
5254
5670
|
}
|
|
5255
5671
|
if (isSocialProviderIntegration(item)) {
|
|
5256
5672
|
return { ...item, connectionRef: null };
|
|
5257
5673
|
}
|
|
5258
|
-
if (item.surfaceType === "first_party_fiken") {
|
|
5259
|
-
return { ...item, connectionRef: null };
|
|
5260
|
-
}
|
|
5261
5674
|
if (item.surfaceType === "codex_apps") {
|
|
5262
5675
|
return { ...item, connectionRef: null };
|
|
5263
5676
|
}
|
|
@@ -7895,6 +8308,7 @@ async function createAndStartSessionWithOutcome(input) {
|
|
|
7895
8308
|
...input.scopeSubjectId !== void 0 ? { scopeSubjectId: input.scopeSubjectId } : {},
|
|
7896
8309
|
...input.memoryScope ? { memoryScope: input.memoryScope } : {},
|
|
7897
8310
|
parentSessionId: input.parentSessionId ?? null,
|
|
8311
|
+
...input.codeSearchDeploymentPolicy ? { codeSearchDeploymentPolicy: input.codeSearchDeploymentPolicy } : {},
|
|
7898
8312
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
7899
8313
|
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
|
|
7900
8314
|
mcpServers: input.mcpServers ?? [],
|
|
@@ -8019,7 +8433,7 @@ function canonicalConfiguredModel(settings, model) {
|
|
|
8019
8433
|
if (model === null || model === void 0) {
|
|
8020
8434
|
return model;
|
|
8021
8435
|
}
|
|
8022
|
-
const canonicalModel =
|
|
8436
|
+
const canonicalModel = canonicalizeConfiguredModelId2(settings, model);
|
|
8023
8437
|
if (canonicalModel.startsWith(CODEX_MODEL_ID_PREFIX) && settings.resolvedCodexModelsJson !== void 0) {
|
|
8024
8438
|
if (settings.codexSubscriptionEnabled && configuredAllowedModels(withCodexCatalogProvider2(settings)).includes(canonicalModel)) {
|
|
8025
8439
|
return canonicalModel;
|
|
@@ -8066,7 +8480,7 @@ async function assertWorkspaceModelPolicyAllows(db, settings, workspaceId, model
|
|
|
8066
8480
|
if (canonicalModel === null || canonicalModel === void 0) {
|
|
8067
8481
|
return;
|
|
8068
8482
|
}
|
|
8069
|
-
const policy = await
|
|
8483
|
+
const policy = await getWorkspaceModelPolicy2(db, workspaceId);
|
|
8070
8484
|
if (!policy) {
|
|
8071
8485
|
return;
|
|
8072
8486
|
}
|
|
@@ -8548,7 +8962,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
8548
8962
|
throw error;
|
|
8549
8963
|
}
|
|
8550
8964
|
}
|
|
8551
|
-
const parentSession = parentSessionId ? await
|
|
8965
|
+
const parentSession = parentSessionId ? await getSession3(db, workspaceId, parentSessionId) : null;
|
|
8552
8966
|
if (parentSessionId && !parentSession) {
|
|
8553
8967
|
throw new HTTPException15(404, {
|
|
8554
8968
|
message: `parent session not found in workspace: ${parentSessionId}`
|
|
@@ -8615,6 +9029,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
8615
9029
|
}
|
|
8616
9030
|
const replayManagedHumanSubjectId = creationInitiator.actor ? parentCallingTurn?.initiatingHumanSubjectId ?? (parentCallingTurn?.initiator.kind === "subject" ? parentCallingTurn.initiator.subjectId : null) : authorization?.canonicalManagedHumanSession || grant.principalKind === "human_session" ? grant.subjectId : null;
|
|
8617
9031
|
let retainedKeyedShellModel = null;
|
|
9032
|
+
let retainedKeyedShellReasoningEffort = null;
|
|
8618
9033
|
if (payload.idempotencyKey && (effectiveVisibility !== "user_private" || replayManagedHumanSubjectId !== null)) {
|
|
8619
9034
|
try {
|
|
8620
9035
|
const initializedReplay = await getInitializedSessionCreateReplay(db, {
|
|
@@ -8639,6 +9054,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
8639
9054
|
}
|
|
8640
9055
|
if (initializedReplay.outcome === "pending") {
|
|
8641
9056
|
retainedKeyedShellModel = initializedReplay.session.model;
|
|
9057
|
+
retainedKeyedShellReasoningEffort = initializedReplay.session.reasoningEffort;
|
|
8642
9058
|
} else {
|
|
8643
9059
|
if (initializedReplay.workflowWakeRevision !== null) {
|
|
8644
9060
|
await unresolvedDeps.workflowClient.wakeSessionWorkflow({
|
|
@@ -8696,7 +9112,13 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
8696
9112
|
payload.personalResourceAttachment,
|
|
8697
9113
|
false
|
|
8698
9114
|
);
|
|
8699
|
-
const
|
|
9115
|
+
const resolvedDefault = parentSession || payload.model !== void 0 ? null : retainedKeyedShellModel !== null && retainedKeyedShellReasoningEffort !== null ? { model: retainedKeyedShellModel, reasoningEffort: retainedKeyedShellReasoningEffort } : await resolveDefaultSessionModel(db, settings, {
|
|
9116
|
+
accountId: grant.accountId,
|
|
9117
|
+
workspaceId,
|
|
9118
|
+
subjectId: grant.subjectId,
|
|
9119
|
+
workspaceSettings: workspace.settings
|
|
9120
|
+
});
|
|
9121
|
+
const inheritedModel = parentCallingTurn?.model ?? parentSession?.model ?? resolvedDefault?.model ?? settings.openaiModel;
|
|
8700
9122
|
const effectiveModelId = payload.model ?? inheritedModel;
|
|
8701
9123
|
const effectiveCatalogSettings = await resolveWorkspaceModelBoundarySettings(
|
|
8702
9124
|
deps,
|
|
@@ -8950,7 +9372,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
8950
9372
|
throw new Error("effective session model unexpectedly resolved to null");
|
|
8951
9373
|
}
|
|
8952
9374
|
await assertWorkspaceModelPolicyAllows(db, settings, workspaceId, model);
|
|
8953
|
-
const inheritedReasoningEffort = parentCallingTurn?.reasoningEffort ?? parentSession?.reasoningEffort ?? settings.openaiReasoningEffort;
|
|
9375
|
+
const inheritedReasoningEffort = parentCallingTurn?.reasoningEffort ?? parentSession?.reasoningEffort ?? resolvedDefault?.reasoningEffort ?? settings.openaiReasoningEffort;
|
|
8954
9376
|
const inheritedLatencyMode = parentCallingTurn?.latencyMode ?? parentSession?.latencyMode ?? "standard";
|
|
8955
9377
|
const reasoningEffort = payload.reasoningEffort ?? inheritedReasoningEffort;
|
|
8956
9378
|
const latencyMode = payload.latencyMode ?? inheritedLatencyMode;
|
|
@@ -9238,6 +9660,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
|
|
|
9238
9660
|
db,
|
|
9239
9661
|
bus,
|
|
9240
9662
|
workflowClient,
|
|
9663
|
+
codeSearchDeploymentPolicy: codeSearchDeploymentPolicy(deps.settings),
|
|
9241
9664
|
accountId: grant.accountId,
|
|
9242
9665
|
workspaceId,
|
|
9243
9666
|
visibility: effectiveVisibility,
|
|
@@ -10094,7 +10517,7 @@ async function readSessionLineage(deps, grant, sessionId) {
|
|
|
10094
10517
|
surface: "core"
|
|
10095
10518
|
});
|
|
10096
10519
|
if (authorization?.relatedSessionAccess === "target") {
|
|
10097
|
-
const session = await
|
|
10520
|
+
const session = await getSession3(deps.db, grant.workspaceId, sessionId);
|
|
10098
10521
|
if (!session) {
|
|
10099
10522
|
throw new HTTPException15(404, { message: "session not found" });
|
|
10100
10523
|
}
|
|
@@ -10136,6 +10559,39 @@ async function acceptSessionUserMessageWithOutcome(...args) {
|
|
|
10136
10559
|
return withSessionRlsActorContext4(actor, () => acceptSessionUserMessageInFileScope(...args));
|
|
10137
10560
|
}
|
|
10138
10561
|
|
|
10562
|
+
// src/domain/session-native-connection-replacement.ts
|
|
10563
|
+
import { connectionMetadataMatchesBinding } from "@opengeni/db/session-mcp-credential-rotation";
|
|
10564
|
+
function nativeSessionConnectionReplacement(input) {
|
|
10565
|
+
const connection = input.connections.find(
|
|
10566
|
+
(candidate) => candidate.id === input.nativeConnectionId
|
|
10567
|
+
);
|
|
10568
|
+
if (!connection || connection.accountId !== input.accountId || connection.status !== "active" || (connection.subjectId === null ? connection.workspaceId !== input.workspaceId : !input.subjectId || connection.subjectId !== input.subjectId || !connection.authorityId)) {
|
|
10569
|
+
throw new Error("native connection unavailable");
|
|
10570
|
+
}
|
|
10571
|
+
const {
|
|
10572
|
+
authoritySource: _authoritySource,
|
|
10573
|
+
hostBinding: _hostBinding,
|
|
10574
|
+
accountSelection: _accountSelection,
|
|
10575
|
+
...retained
|
|
10576
|
+
} = input.currentRef ?? {};
|
|
10577
|
+
if (input.currentRef && input.currentRef.providerDomain.toLowerCase() !== connection.providerDomain.toLowerCase())
|
|
10578
|
+
throw new Error("native connection provider mismatch");
|
|
10579
|
+
const ref = {
|
|
10580
|
+
...retained,
|
|
10581
|
+
...!input.currentRef?.resource && typeof connection.metadata.resource === "string" ? { resource: connection.metadata.resource } : {},
|
|
10582
|
+
connectionId: connection.id,
|
|
10583
|
+
providerDomain: connection.providerDomain,
|
|
10584
|
+
kind: connection.kind,
|
|
10585
|
+
subjectScope: connection.subjectId === null ? "workspace" : "subject"
|
|
10586
|
+
};
|
|
10587
|
+
const destination = input.replacementServerUrl ?? input.serverUrl;
|
|
10588
|
+
if (input.replacementServerUrl && (typeof connection.metadata.mcpUrl !== "string" || !connection.metadata.mcpUrl.trim()))
|
|
10589
|
+
throw new Error("native connection destination unavailable");
|
|
10590
|
+
if (!connectionMetadataMatchesBinding(connection, ref, destination))
|
|
10591
|
+
throw new Error("native connection binding mismatch");
|
|
10592
|
+
return ref;
|
|
10593
|
+
}
|
|
10594
|
+
|
|
10139
10595
|
// src/application/session-mcp-credential-rotation.ts
|
|
10140
10596
|
function sessionMcpRotationFingerprint(key, scope, request) {
|
|
10141
10597
|
return {
|
|
@@ -10167,9 +10623,14 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10167
10623
|
id: update.id,
|
|
10168
10624
|
expectedCredentialVersion: update.expectedCredentialVersion,
|
|
10169
10625
|
expectedServerUrl: update.expectedServerUrl,
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10626
|
+
..."nativeConnectionId" in update ? {
|
|
10627
|
+
nativeConnectionId: update.nativeConnectionId,
|
|
10628
|
+
...update.replacementServerUrl ? { replacementServerUrl: update.replacementServerUrl } : {}
|
|
10629
|
+
} : {
|
|
10630
|
+
headers: Object.fromEntries(
|
|
10631
|
+
Object.entries(normalizedSessionMcpCredentialHeaders(update.headers)).map(([name, value]) => [name.toLowerCase(), value]).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
10632
|
+
)
|
|
10633
|
+
}
|
|
10173
10634
|
})).sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0)
|
|
10174
10635
|
};
|
|
10175
10636
|
if (new Set(request.updates.map((update) => update.id)).size !== request.updates.length)
|
|
@@ -10185,20 +10646,43 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10185
10646
|
actorType: grant.principalKind === "service" ? "service" : "human"
|
|
10186
10647
|
};
|
|
10187
10648
|
const externalAuthorize = externalContinuationCommitAuthorizer(authorization);
|
|
10649
|
+
let authorizedGrant = grant;
|
|
10188
10650
|
try {
|
|
10189
10651
|
return await rotateSessionMcpCredentialsAtomically(deps.db, {
|
|
10190
10652
|
...scope,
|
|
10191
10653
|
operationKey: request.operationKey,
|
|
10192
10654
|
...sessionMcpRotationFingerprint(encryptionKey, scope, request),
|
|
10193
|
-
updates: request.updates.map(
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10655
|
+
updates: request.updates.map(
|
|
10656
|
+
(update) => "nativeConnectionId" in update ? update : {
|
|
10657
|
+
id: update.id,
|
|
10658
|
+
expectedCredentialVersion: update.expectedCredentialVersion,
|
|
10659
|
+
expectedServerUrl: update.expectedServerUrl,
|
|
10660
|
+
headersEncrypted: Object.fromEntries(
|
|
10661
|
+
Object.entries(update.headers).map(([name, value]) => [
|
|
10662
|
+
name,
|
|
10663
|
+
encryptVariableSetValue3(encryptionKey, value)
|
|
10664
|
+
])
|
|
10665
|
+
)
|
|
10666
|
+
}
|
|
10667
|
+
),
|
|
10668
|
+
resolveNativeConnection: async (tx, server, nativeConnectionId, replacementServerUrl) => {
|
|
10669
|
+
const connections = await listOwnConnectionAccountsForGrant(tx, authorizedGrant);
|
|
10670
|
+
const source = personalConnectionDelegationSourceForGrant(authorizedGrant);
|
|
10671
|
+
try {
|
|
10672
|
+
return nativeSessionConnectionReplacement({
|
|
10673
|
+
accountId: grant.accountId,
|
|
10674
|
+
workspaceId: grant.workspaceId,
|
|
10675
|
+
subjectId: source.kind === "subject" ? source.subjectId : null,
|
|
10676
|
+
serverUrl: server.url,
|
|
10677
|
+
...replacementServerUrl ? { replacementServerUrl } : {},
|
|
10678
|
+
currentRef: server.connectionRef,
|
|
10679
|
+
nativeConnectionId,
|
|
10680
|
+
connections
|
|
10681
|
+
});
|
|
10682
|
+
} catch {
|
|
10683
|
+
throw new SessionMcpCredentialRotationError("connection_unavailable");
|
|
10684
|
+
}
|
|
10685
|
+
},
|
|
10202
10686
|
authorize: async (tx) => {
|
|
10203
10687
|
await externalAuthorize?.(tx);
|
|
10204
10688
|
const fresh = await reauthorize(tx);
|
|
@@ -10221,6 +10705,7 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10221
10705
|
operation: "session.mcp.credentials.rotate",
|
|
10222
10706
|
surface: "http"
|
|
10223
10707
|
});
|
|
10708
|
+
authorizedGrant = fresh;
|
|
10224
10709
|
}
|
|
10225
10710
|
});
|
|
10226
10711
|
} catch (error) {
|
|
@@ -10231,7 +10716,7 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
|
|
|
10231
10716
|
if (error instanceof SessionAuthorizationUnavailableError)
|
|
10232
10717
|
throw new HTTPException16(503, { message: "credential rotation authorization unavailable" });
|
|
10233
10718
|
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;
|
|
10719
|
+
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
10720
|
throw new HTTPException16(status, { message: `credential_rotation_${error.code}` });
|
|
10236
10721
|
}
|
|
10237
10722
|
throw new HTTPException16(503, { message: "credential rotation unavailable" });
|
|
@@ -10672,7 +11157,7 @@ function sha256Hex2(bytes) {
|
|
|
10672
11157
|
}
|
|
10673
11158
|
|
|
10674
11159
|
// src/domain/skill-search.ts
|
|
10675
|
-
import { pinnedFetch, readResponseJsonBounded } from "@opengeni/network";
|
|
11160
|
+
import { pinnedFetch as pinnedFetch2, readResponseJsonBounded } from "@opengeni/network";
|
|
10676
11161
|
var PublicSkillSearchError = class extends Error {
|
|
10677
11162
|
constructor(code, message, retryAfterSeconds = null) {
|
|
10678
11163
|
super(message);
|
|
@@ -10687,7 +11172,7 @@ var maxResponseBytes = 256 * 1024;
|
|
|
10687
11172
|
var maxResults = 20;
|
|
10688
11173
|
var ownerPattern = /^[a-z0-9](?:[a-z0-9-]{0,38})$/iu;
|
|
10689
11174
|
var segmentPattern = /^[a-z0-9](?:[a-z0-9._-]{0,98}[a-z0-9])?$/iu;
|
|
10690
|
-
function createPublicSkillSearchClient(settings, fetcher =
|
|
11175
|
+
function createPublicSkillSearchClient(settings, fetcher = pinnedFetch2) {
|
|
10691
11176
|
return {
|
|
10692
11177
|
async search(input) {
|
|
10693
11178
|
const query = input.query.trim();
|
|
@@ -10814,7 +11299,7 @@ function parseRetryAfter(value) {
|
|
|
10814
11299
|
|
|
10815
11300
|
// src/domain/github-skill-source.ts
|
|
10816
11301
|
import { HTTPException as HTTPException19 } from "hono/http-exception";
|
|
10817
|
-
import { pinnedFetch as
|
|
11302
|
+
import { pinnedFetch as pinnedFetch3, readResponseJsonBounded as readResponseJsonBounded2, readResponseTextBounded } from "@opengeni/network";
|
|
10818
11303
|
import {
|
|
10819
11304
|
PORTABLE_SKILL_MAX_FILES as PORTABLE_SKILL_MAX_FILES2,
|
|
10820
11305
|
PORTABLE_SKILL_MAX_FILE_BYTES as PORTABLE_SKILL_MAX_FILE_BYTES2,
|
|
@@ -10915,7 +11400,7 @@ function createGitHubSkillSourceClient(settings, requestJson = (path, maxBytes,
|
|
|
10915
11400
|
}
|
|
10916
11401
|
async function downloadSkillSnapshot(settings, owner, repository, slug) {
|
|
10917
11402
|
const signal = AbortSignal.timeout(githubRequestTimeoutMs);
|
|
10918
|
-
const response = await
|
|
11403
|
+
const response = await pinnedFetch3(
|
|
10919
11404
|
`https://skills.sh/api/download/${[owner, repository, slug].map(encodeURIComponent).join("/")}`,
|
|
10920
11405
|
{ headers: { accept: "application/json" }, credentials: "omit", redirect: "manual", signal },
|
|
10921
11406
|
settings,
|
|
@@ -10950,7 +11435,7 @@ async function githubJson(settings, path, maxBytes, label) {
|
|
|
10950
11435
|
const controller = new AbortController();
|
|
10951
11436
|
const timeout = setTimeout(() => controller.abort(), githubRequestTimeoutMs);
|
|
10952
11437
|
try {
|
|
10953
|
-
const response = await
|
|
11438
|
+
const response = await pinnedFetch3(
|
|
10954
11439
|
`${githubApiBase}${path}`,
|
|
10955
11440
|
{
|
|
10956
11441
|
method: "GET",
|
|
@@ -12409,10 +12894,10 @@ import {
|
|
|
12409
12894
|
getRig as getRig4,
|
|
12410
12895
|
getScheduledTask,
|
|
12411
12896
|
getScheduledTaskIncludingDeletedForUpdate,
|
|
12412
|
-
getScheduledTaskXaiProviderAccountAuthoritySnapshot,
|
|
12897
|
+
getScheduledTaskXaiProviderAccountAuthoritySnapshot as getScheduledTaskXaiProviderAccountAuthoritySnapshot2,
|
|
12413
12898
|
getSandbox as getSandbox4,
|
|
12414
12899
|
getSessionTurnXaiProviderAccountAuthoritySnapshot as getSessionTurnXaiProviderAccountAuthoritySnapshot2,
|
|
12415
|
-
getSession as
|
|
12900
|
+
getSession as getSession4,
|
|
12416
12901
|
getSessionAuthorityProjection as getSessionAuthorityProjection5,
|
|
12417
12902
|
withSessionRlsActorContext as withSessionRlsActorContext5,
|
|
12418
12903
|
nestedPostgresSqlState as nestedPostgresSqlState6,
|
|
@@ -12669,7 +13154,7 @@ async function createValidatedScheduledTask(input) {
|
|
|
12669
13154
|
);
|
|
12670
13155
|
}
|
|
12671
13156
|
async function frozenScheduledTaskCreatorPolicy(input) {
|
|
12672
|
-
const session = await
|
|
13157
|
+
const session = await getSession4(input.db, input.grant.workspaceId, input.sessionId);
|
|
12673
13158
|
if (!session) {
|
|
12674
13159
|
throw new HTTPException21(403, {
|
|
12675
13160
|
message: "the calling agent session is not available in this workspace"
|
|
@@ -12867,7 +13352,7 @@ async function validateScheduledTaskTarget(input) {
|
|
|
12867
13352
|
}
|
|
12868
13353
|
throw error;
|
|
12869
13354
|
}
|
|
12870
|
-
const session = await
|
|
13355
|
+
const session = await getSession4(input.db, input.grant.workspaceId, input.targetSessionId);
|
|
12871
13356
|
if (!session || session.accountId !== input.grant.accountId) {
|
|
12872
13357
|
throw new HTTPException21(404, { message: "target session not found" });
|
|
12873
13358
|
}
|
|
@@ -13139,7 +13624,7 @@ async function validatedScheduledTaskUpdate(input) {
|
|
|
13139
13624
|
});
|
|
13140
13625
|
if (beforeUpdateCommit) update.beforeUpdateCommit = beforeUpdateCommit;
|
|
13141
13626
|
}
|
|
13142
|
-
const existingXaiAuthority = await
|
|
13627
|
+
const existingXaiAuthority = await getScheduledTaskXaiProviderAccountAuthoritySnapshot2(
|
|
13143
13628
|
input.db,
|
|
13144
13629
|
input.existing.workspaceId,
|
|
13145
13630
|
input.existing.id
|
|
@@ -13429,7 +13914,7 @@ function manualScheduledTaskTriggerUsageKey(workspaceId, taskId, triggerToken) {
|
|
|
13429
13914
|
}
|
|
13430
13915
|
async function validateScheduledTaskAgentConfig(input) {
|
|
13431
13916
|
const actor = scheduledTaskInitiatorForGrant(input.grant).actor;
|
|
13432
|
-
const parent = actor ? await
|
|
13917
|
+
const parent = actor ? await getSession4(input.db, input.workspaceId, actor.sessionId) : null;
|
|
13433
13918
|
if (actor && (!parent || parent.accountId !== input.grant.accountId)) {
|
|
13434
13919
|
throw new HTTPException21(403, {
|
|
13435
13920
|
message: "Scheduled Skill selection requires the creating agent's session"
|
|
@@ -15974,6 +16459,7 @@ import {
|
|
|
15974
16459
|
getSandbox as getSandbox5,
|
|
15975
16460
|
getVariableSet as getVariableSet3,
|
|
15976
16461
|
NewSessionDraftAccessError,
|
|
16462
|
+
newSessionDraftModelProvided,
|
|
15977
16463
|
newSessionDraftSelectedProjectChannelId,
|
|
15978
16464
|
newSessionDraftToolsProvided,
|
|
15979
16465
|
newSessionSelectionHistory,
|
|
@@ -15984,6 +16470,7 @@ import {
|
|
|
15984
16470
|
withWorkspaceSubjectRls as withWorkspaceSubjectRls6
|
|
15985
16471
|
} from "@opengeni/db";
|
|
15986
16472
|
import { HTTPException as HTTPException23 } from "hono/http-exception";
|
|
16473
|
+
import { canonicalizeConfiguredModelId as canonicalizeConfiguredModelId3 } from "@opengeni/config";
|
|
15987
16474
|
function hasOwn(value, key) {
|
|
15988
16475
|
return typeof value === "object" && value !== null && Object.hasOwn(value, key);
|
|
15989
16476
|
}
|
|
@@ -15999,16 +16486,39 @@ function mapNewSessionDraft(row) {
|
|
|
15999
16486
|
model: row.model,
|
|
16000
16487
|
reasoningEffort: row.reasoningEffort,
|
|
16001
16488
|
latencyMode: row.latencyMode,
|
|
16489
|
+
...newSessionDraftModelProvided(row) !== void 0 ? { modelProvided: newSessionDraftModelProvided(row) } : {},
|
|
16002
16490
|
...selectedProjectChannelId !== void 0 ? { selectedProjectChannelId } : {},
|
|
16003
16491
|
options: publicNewSessionDraftOptions(row),
|
|
16004
16492
|
selectionHistory: newSessionSelectionHistory(row),
|
|
16005
16493
|
updatedAt: row.updatedAt.toISOString()
|
|
16006
16494
|
});
|
|
16007
16495
|
}
|
|
16008
|
-
|
|
16496
|
+
function draftModelProvided(settings, draft) {
|
|
16497
|
+
if (draft.modelProvided !== void 0) return draft.modelProvided;
|
|
16498
|
+
return !(canonicalizeConfiguredModelId3(settings, draft.model) === canonicalizeConfiguredModelId3(settings, settings.openaiModel) && draft.reasoningEffort === settings.openaiReasoningEffort && draft.latencyMode === "standard");
|
|
16499
|
+
}
|
|
16500
|
+
async function actorDefaultModel(deps, grant, workspaceId) {
|
|
16501
|
+
return await resolveDefaultSessionModel(deps.db, deps.settings, {
|
|
16502
|
+
accountId: grant.accountId,
|
|
16503
|
+
workspaceId,
|
|
16504
|
+
subjectId: grant.subjectId
|
|
16505
|
+
});
|
|
16506
|
+
}
|
|
16507
|
+
async function hydrateNewSessionDraft(deps, grant, workspaceId, row, readOptions = {}) {
|
|
16009
16508
|
if (!row) return null;
|
|
16010
|
-
const
|
|
16011
|
-
if (!
|
|
16509
|
+
const stored = mapNewSessionDraft(row);
|
|
16510
|
+
if (!stored) return null;
|
|
16511
|
+
const modelProvided = draftModelProvided(deps.settings, stored);
|
|
16512
|
+
let mapped = { ...stored, modelProvided };
|
|
16513
|
+
if (!modelProvided && readOptions.projectDefaultModel !== false) {
|
|
16514
|
+
const resolved = await actorDefaultModel(deps, grant, workspaceId);
|
|
16515
|
+
mapped = {
|
|
16516
|
+
...mapped,
|
|
16517
|
+
model: resolved.model,
|
|
16518
|
+
reasoningEffort: resolved.reasoningEffort,
|
|
16519
|
+
latencyMode: resolved.model === stored.model ? stored.latencyMode : "standard"
|
|
16520
|
+
};
|
|
16521
|
+
}
|
|
16012
16522
|
const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
|
|
16013
16523
|
deps.db,
|
|
16014
16524
|
workspaceId,
|
|
@@ -16098,7 +16608,7 @@ async function hydrateNewSessionDraft(deps, grant, workspaceId, row) {
|
|
|
16098
16608
|
options
|
|
16099
16609
|
};
|
|
16100
16610
|
}
|
|
16101
|
-
async function getActorNewSessionDraftInFileScope(deps, grant, workspaceId) {
|
|
16611
|
+
async function getActorNewSessionDraftInFileScope(deps, grant, workspaceId, readOptions = {}) {
|
|
16102
16612
|
const row = await withWorkspaceSubjectRls6(
|
|
16103
16613
|
deps.db,
|
|
16104
16614
|
workspaceId,
|
|
@@ -16108,15 +16618,19 @@ async function getActorNewSessionDraftInFileScope(deps, grant, workspaceId) {
|
|
|
16108
16618
|
subjectId: grant.subjectId
|
|
16109
16619
|
})
|
|
16110
16620
|
);
|
|
16111
|
-
|
|
16621
|
+
const hydrated = await hydrateNewSessionDraft(deps, grant, workspaceId, row, readOptions);
|
|
16622
|
+
if (hydrated) return hydrated;
|
|
16623
|
+
const resolved = readOptions.projectDefaultModel === false ? { model: deps.settings.openaiModel, reasoningEffort: deps.settings.openaiReasoningEffort } : await actorDefaultModel(deps, grant, workspaceId);
|
|
16624
|
+
return {
|
|
16112
16625
|
revision: 0,
|
|
16113
16626
|
text: "",
|
|
16114
16627
|
resources: [],
|
|
16115
16628
|
tools: [],
|
|
16116
16629
|
toolsProvided: false,
|
|
16117
|
-
model:
|
|
16118
|
-
reasoningEffort:
|
|
16630
|
+
model: resolved.model,
|
|
16631
|
+
reasoningEffort: resolved.reasoningEffort,
|
|
16119
16632
|
latencyMode: "standard",
|
|
16633
|
+
modelProvided: false,
|
|
16120
16634
|
options: {},
|
|
16121
16635
|
selectionHistory: { projects: [] },
|
|
16122
16636
|
updatedAt: null
|
|
@@ -16167,6 +16681,7 @@ async function saveActorNewSessionDraftInFileScope(deps, grant, workspaceId, raw
|
|
|
16167
16681
|
model: input.model,
|
|
16168
16682
|
reasoningEffort: input.reasoningEffort,
|
|
16169
16683
|
latencyMode: input.latencyMode,
|
|
16684
|
+
...input.modelProvided !== void 0 ? { modelProvided: input.modelProvided } : {},
|
|
16170
16685
|
...input.selectedProjectChannelId !== void 0 ? { selectedProjectChannelId: input.selectedProjectChannelId } : {},
|
|
16171
16686
|
options: input.options,
|
|
16172
16687
|
// Only managed people are removed through removeWorkspaceMember().
|
|
@@ -16182,7 +16697,8 @@ async function saveActorNewSessionDraftInFileScope(deps, grant, workspaceId, raw
|
|
|
16182
16697
|
})
|
|
16183
16698
|
)
|
|
16184
16699
|
);
|
|
16185
|
-
|
|
16700
|
+
const mapped = mapNewSessionDraft(saved);
|
|
16701
|
+
return { ...mapped, modelProvided: draftModelProvided(deps.settings, mapped) };
|
|
16186
16702
|
} catch (error) {
|
|
16187
16703
|
if (error instanceof NewSessionDraftAccessError) {
|
|
16188
16704
|
throw new HTTPException23(403, { message: error.message });
|
|
@@ -16190,11 +16706,11 @@ async function saveActorNewSessionDraftInFileScope(deps, grant, workspaceId, raw
|
|
|
16190
16706
|
throw error;
|
|
16191
16707
|
}
|
|
16192
16708
|
}
|
|
16193
|
-
async function getActorNewSessionDraft(deps, grant, workspaceId, authorization) {
|
|
16709
|
+
async function getActorNewSessionDraft(deps, grant, workspaceId, authorization, readOptions = {}) {
|
|
16194
16710
|
const actor = authorization ? await fileOwnerContextForAccess(deps, authorization, "sessions:read") : { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
|
|
16195
16711
|
return withSessionRlsActorContext6(
|
|
16196
16712
|
actor,
|
|
16197
|
-
() => getActorNewSessionDraftInFileScope(deps, grant, workspaceId)
|
|
16713
|
+
() => getActorNewSessionDraftInFileScope(deps, grant, workspaceId, readOptions)
|
|
16198
16714
|
);
|
|
16199
16715
|
}
|
|
16200
16716
|
async function saveActorNewSessionDraft(...args) {
|
|
@@ -16203,11 +16719,15 @@ async function saveActorNewSessionDraft(...args) {
|
|
|
16203
16719
|
return withSessionRlsActorContext6(actor, () => saveActorNewSessionDraftInFileScope(...args));
|
|
16204
16720
|
}
|
|
16205
16721
|
async function getActorNewSessionDefaults(deps, grant, workspaceId) {
|
|
16206
|
-
const draft = await getActorNewSessionDraft(deps, grant, workspaceId
|
|
16722
|
+
const draft = await getActorNewSessionDraft(deps, grant, workspaceId, void 0, {
|
|
16723
|
+
projectDefaultModel: false
|
|
16724
|
+
});
|
|
16207
16725
|
const options = draft.options;
|
|
16208
16726
|
return {
|
|
16209
|
-
//
|
|
16210
|
-
|
|
16727
|
+
// Only a model the person chose is carried over. A draft that follows the
|
|
16728
|
+
// default (including the synthetic revision-zero form) leaves the model
|
|
16729
|
+
// out, so session creation resolves the same default itself.
|
|
16730
|
+
...draft.revision > 0 && draft.modelProvided === true ? {
|
|
16211
16731
|
model: draft.model,
|
|
16212
16732
|
reasoningEffort: draft.reasoningEffort,
|
|
16213
16733
|
latencyMode: draft.latencyMode
|
|
@@ -16270,7 +16790,7 @@ import {
|
|
|
16270
16790
|
deleteSessionQueueItemInTransaction,
|
|
16271
16791
|
editQueuedTurnInTransaction,
|
|
16272
16792
|
getComposerDraftInTransaction,
|
|
16273
|
-
getSession as
|
|
16793
|
+
getSession as getSession5,
|
|
16274
16794
|
getSessionEvent as getSessionEvent3,
|
|
16275
16795
|
getWorkspaceControlEvent as getWorkspaceControlEvent2,
|
|
16276
16796
|
getSessionQueueSnapshot,
|
|
@@ -16968,7 +17488,7 @@ async function getHumanComposerDraft(deps, context) {
|
|
|
16968
17488
|
);
|
|
16969
17489
|
const mapped = composerDraft(row);
|
|
16970
17490
|
if (mapped) return mapped;
|
|
16971
|
-
const session = await
|
|
17491
|
+
const session = await getSession5(deps.db, context.workspaceId, context.sessionId);
|
|
16972
17492
|
if (!session) throw new Error(`Session not found: ${context.sessionId}`);
|
|
16973
17493
|
return {
|
|
16974
17494
|
revision: 0,
|
|
@@ -17339,7 +17859,7 @@ var CATALOG_PAGE_SIZE = 25;
|
|
|
17339
17859
|
var CATALOG_PAGE_BUDGET = 40;
|
|
17340
17860
|
var DESCRIPTION_CHARS = 2e3;
|
|
17341
17861
|
var CATALOG_BYTES = 256 * 1024;
|
|
17342
|
-
async function prepareKnowledgeSave(db, context, input, embedder, services = defaults) {
|
|
17862
|
+
async function prepareKnowledgeSave(db, context, input, embedder, services = defaults, settings) {
|
|
17343
17863
|
const request = KnowledgeSavePreparationRequest.parse(input);
|
|
17344
17864
|
if (context.actor.kind !== "agent" && !(context.actor.kind === "human" && context.actor.review)) {
|
|
17345
17865
|
throw Object.assign(
|
|
@@ -17364,20 +17884,31 @@ async function prepareKnowledgeSave(db, context, input, embedder, services = def
|
|
|
17364
17884
|
complete: true,
|
|
17365
17885
|
nextCursors: { published: null, needs_review: null }
|
|
17366
17886
|
};
|
|
17367
|
-
const
|
|
17368
|
-
|
|
17369
|
-
|
|
17370
|
-
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
|
|
17379
|
-
|
|
17380
|
-
|
|
17887
|
+
const paid = settings != null && paidDocumentEmbedding(settings);
|
|
17888
|
+
const published = await services.search(
|
|
17889
|
+
db,
|
|
17890
|
+
context,
|
|
17891
|
+
{
|
|
17892
|
+
query: request.query,
|
|
17893
|
+
limit: request.limit,
|
|
17894
|
+
view: "published",
|
|
17895
|
+
...paid ? { mode: "keyword" } : {}
|
|
17896
|
+
},
|
|
17897
|
+
sharedEmbedder,
|
|
17898
|
+
paid ? void 0 : settings
|
|
17899
|
+
);
|
|
17900
|
+
const needsReview = await services.search(
|
|
17901
|
+
db,
|
|
17902
|
+
context,
|
|
17903
|
+
{
|
|
17904
|
+
query: request.query,
|
|
17905
|
+
limit: request.limit,
|
|
17906
|
+
view: "needs_review",
|
|
17907
|
+
...published.searchMode === "keyword" ? { mode: "keyword" } : {}
|
|
17908
|
+
},
|
|
17909
|
+
sharedEmbedder
|
|
17910
|
+
);
|
|
17911
|
+
const matches = { published, needs_review: needsReview };
|
|
17381
17912
|
for (const view of ["published", "needs_review"]) {
|
|
17382
17913
|
if (request.collectionCursors && request.collectionCursors[view] === null) continue;
|
|
17383
17914
|
let cursor = request.collectionCursors?.[view] ?? void 0;
|
|
@@ -17786,6 +18317,8 @@ export {
|
|
|
17786
18317
|
InMemoryEditableArtifactLiveTicketStore,
|
|
17787
18318
|
InMemoryEditableArtifactStableIdFactory,
|
|
17788
18319
|
InMemoryEditableArtifactStore,
|
|
18320
|
+
KnowledgeVectorFundingError,
|
|
18321
|
+
KnowledgeVectorQueryRejectedError,
|
|
17789
18322
|
MAX_CHECKS_PER_RIG,
|
|
17790
18323
|
MAX_CREDENTIAL_HOOKS_PER_RIG,
|
|
17791
18324
|
MAX_DEFAULT_VARIABLE_SETS_PER_RIG,
|
|
@@ -17896,6 +18429,7 @@ export {
|
|
|
17896
18429
|
causalFrontierDominates,
|
|
17897
18430
|
causalFrontiersEqual,
|
|
17898
18431
|
checkLimit,
|
|
18432
|
+
clampReasoningEffortForConfiguredModel,
|
|
17899
18433
|
classifyRigVerificationOutcome,
|
|
17900
18434
|
codexAppsCatalogItem,
|
|
17901
18435
|
compareCodeUnits,
|
|
@@ -17921,10 +18455,12 @@ export {
|
|
|
17921
18455
|
createSessionForRequestWithOutcome,
|
|
17922
18456
|
createValidatedScheduledTask,
|
|
17923
18457
|
creationInitiatorForGrant,
|
|
18458
|
+
creditsDefaultSessionModel,
|
|
17924
18459
|
decodeEditableArtifactBrokerHint,
|
|
17925
18460
|
decodeEditableArtifactLiveClientWireFrame,
|
|
17926
18461
|
decodeEditableArtifactLiveServerWireFrame,
|
|
17927
18462
|
defaultPrReviewProviderBaseUrl,
|
|
18463
|
+
defaultReasoningEffortForConfiguredModel,
|
|
17928
18464
|
defaultSessionMcpServerIds,
|
|
17929
18465
|
defaultVideoGenerationPolicy,
|
|
17930
18466
|
deleteHumanQueuePrompt,
|
|
@@ -17934,6 +18470,8 @@ export {
|
|
|
17934
18470
|
directRetainedProcessMatchesBackend,
|
|
17935
18471
|
disableCapability,
|
|
17936
18472
|
discoverMcpRegistryCapabilities,
|
|
18473
|
+
documentEmbeddingCostMicros,
|
|
18474
|
+
draftModelProvided,
|
|
17937
18475
|
editHumanQueuePrompt,
|
|
17938
18476
|
editableArtifactActorKey,
|
|
17939
18477
|
editableArtifactAuthorizationRevisionPortFromPostgres,
|
|
@@ -18038,6 +18576,7 @@ export {
|
|
|
18038
18576
|
listRigVersionsForApi,
|
|
18039
18577
|
listSkills,
|
|
18040
18578
|
loadRigDefaultVariableSetEnvironment,
|
|
18579
|
+
loadWorkspaceModelSelectionInput,
|
|
18041
18580
|
lockActiveCustomModelForAdmission,
|
|
18042
18581
|
lookupExternalIdentityForRequest,
|
|
18043
18582
|
managedSessionGroupBackend,
|
|
@@ -18076,6 +18615,7 @@ export {
|
|
|
18076
18615
|
openGeniSlackBotMetadata,
|
|
18077
18616
|
organizationIntegrationCatalog,
|
|
18078
18617
|
organizationMembershipHttpStatus,
|
|
18618
|
+
paidDocumentEmbedding,
|
|
18079
18619
|
parseGitHubRepositoryCoordinates,
|
|
18080
18620
|
parseSkillSource,
|
|
18081
18621
|
personalAtlassianDelegationsFromVisibleConnections,
|
|
@@ -18155,12 +18695,16 @@ export {
|
|
|
18155
18695
|
resolveCatalogSettings,
|
|
18156
18696
|
resolveChildGoalFromAcceptedSnapshot,
|
|
18157
18697
|
resolveCodexAppsCredentialIdForRun,
|
|
18698
|
+
resolveDefaultSessionModel,
|
|
18699
|
+
resolveDefaultSessionModelForSelections,
|
|
18158
18700
|
resolveFikenDefaultCompanySlug,
|
|
18159
18701
|
resolveFirstPartyMcpToolsForCreate,
|
|
18160
18702
|
resolveGitHubRepositoryBindings,
|
|
18161
18703
|
resolveMemberSubjectId,
|
|
18162
18704
|
resolveRigProviderImageForRun,
|
|
18163
18705
|
resolveRigProviderImageSelection,
|
|
18706
|
+
resolveScheduledTaskDefaultModel,
|
|
18707
|
+
resolveScheduledTaskPreflightModel,
|
|
18164
18708
|
resolveSessionCreateScope,
|
|
18165
18709
|
resolveSessionCreateVisibility,
|
|
18166
18710
|
resolveSessionSandboxRuntime,
|
|
@@ -18201,6 +18745,7 @@ export {
|
|
|
18201
18745
|
scheduledTaskTriggerToken,
|
|
18202
18746
|
searchCapabilityCatalogItems,
|
|
18203
18747
|
searchKnowledgeEntries,
|
|
18748
|
+
selectDefaultSessionModel,
|
|
18204
18749
|
selectedPersonalConnectionServers,
|
|
18205
18750
|
sendAgentSessionMessage,
|
|
18206
18751
|
sessionGroupMachinePresentation,
|