@opengeni/api-router 4.1.0 → 4.1.2-canary.36079201993001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/{chunk-24C5LPNE.js → chunk-PTO4RZT5.js} +798 -281
- package/dist/{chunk-24C5LPNE.js.map → chunk-PTO4RZT5.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/github-lens-connect.d.ts +1 -1
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/documents.d.ts +2 -0
- package/dist/mcp/first-party-tool-permissions.d.ts +12 -0
- package/dist/mcp/scheduled-task-view.d.ts +3 -3
- package/dist/routes/browser-sessions.d.ts +3 -0
- package/dist/routes/github-browser-pages.d.ts +5 -0
- package/dist/routes/insights.d.ts +26 -0
- package/dist/sandbox-file-artifacts.d.ts +17 -1
- package/package.json +19 -19
- package/src/mcp/documents.ts +9 -2
- package/src/mcp/first-party-tool-permissions.ts +6 -0
- package/src/mcp/knowledge-entries.ts +15 -2
- package/src/mcp/server.ts +118 -3
- package/src/routes/browser-sessions.ts +167 -0
- package/src/routes/computer-sessions.ts +18 -1
- package/src/routes/documents.ts +1 -0
- package/src/routes/files.ts +4 -0
- package/src/routes/github-browser-pages.ts +102 -0
- package/src/routes/github.ts +6 -47
- package/src/routes/insights.ts +70 -6
- package/src/routes/knowledge.ts +19 -0
- package/src/routes/managed-onboarding.ts +3 -0
- package/src/routes/organization-memberships.ts +3 -0
- package/src/routes/sessions.ts +89 -0
- package/src/sandbox/channel-a.ts +8 -0
- package/src/sandbox/viewer.ts +16 -3
- package/src/sandbox-file-artifacts.ts +37 -26
- package/src/workspace-tool-gateway.ts +1 -0
|
@@ -294,6 +294,8 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
294
294
|
browser_open: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
295
295
|
browser_tabs: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
296
296
|
browser_observe: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
297
|
+
browser_read: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
298
|
+
browser_screenshot: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
297
299
|
browser_act: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
298
300
|
browser_clipboard: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
299
301
|
browser_debug: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
@@ -329,6 +331,10 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
329
331
|
sessionRequired: true,
|
|
330
332
|
allOf: ["workspace:read"]
|
|
331
333
|
},
|
|
334
|
+
custom_mcp_setup_request: {
|
|
335
|
+
sessionRequired: true,
|
|
336
|
+
allOf: ["workspace:read"]
|
|
337
|
+
},
|
|
332
338
|
github_connect_link: { allOf: ["github:use"] },
|
|
333
339
|
github_repositories_list: { allOf: ["github:use"] },
|
|
334
340
|
social_connections_list: { allOf: ["connections:read"] },
|
|
@@ -4600,6 +4606,9 @@ var Name = class {
|
|
|
4600
4606
|
return new SQL([this]);
|
|
4601
4607
|
}
|
|
4602
4608
|
};
|
|
4609
|
+
function isDriverValueEncoder(value) {
|
|
4610
|
+
return typeof value === "object" && value !== null && "mapToDriverValue" in value && typeof value.mapToDriverValue === "function";
|
|
4611
|
+
}
|
|
4603
4612
|
var noopDecoder = {
|
|
4604
4613
|
mapFromDriverValue: (value) => value
|
|
4605
4614
|
};
|
|
@@ -4732,6 +4741,33 @@ Subquery.prototype.getSQL = function() {
|
|
|
4732
4741
|
return new SQL([this]);
|
|
4733
4742
|
};
|
|
4734
4743
|
|
|
4744
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+1d2c014f134ec9f4/node_modules/drizzle-orm/sql/expressions/conditions.js
|
|
4745
|
+
function bindIfParam(value, column) {
|
|
4746
|
+
if (isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder) && !is(value, Column) && !is(value, Table) && !is(value, View)) {
|
|
4747
|
+
return new Param(value, column);
|
|
4748
|
+
}
|
|
4749
|
+
return value;
|
|
4750
|
+
}
|
|
4751
|
+
var eq = (left, right) => {
|
|
4752
|
+
return sql`${left} = ${bindIfParam(right, left)}`;
|
|
4753
|
+
};
|
|
4754
|
+
function and(...unfilteredConditions) {
|
|
4755
|
+
const conditions = unfilteredConditions.filter(
|
|
4756
|
+
(c) => c !== void 0
|
|
4757
|
+
);
|
|
4758
|
+
if (conditions.length === 0) {
|
|
4759
|
+
return void 0;
|
|
4760
|
+
}
|
|
4761
|
+
if (conditions.length === 1) {
|
|
4762
|
+
return new SQL(conditions);
|
|
4763
|
+
}
|
|
4764
|
+
return new SQL([
|
|
4765
|
+
new StringChunk("("),
|
|
4766
|
+
sql.join(conditions, new StringChunk(" and ")),
|
|
4767
|
+
new StringChunk(")")
|
|
4768
|
+
]);
|
|
4769
|
+
}
|
|
4770
|
+
|
|
4735
4771
|
// src/auth/managed-auth.ts
|
|
4736
4772
|
import { Pool } from "pg";
|
|
4737
4773
|
|
|
@@ -7598,7 +7634,14 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
7598
7634
|
inputSchema: KnowledgeSavePreparationRequest.shape
|
|
7599
7635
|
},
|
|
7600
7636
|
(input) => run(
|
|
7601
|
-
(context) => prepareKnowledgeSave(
|
|
7637
|
+
(context) => prepareKnowledgeSave(
|
|
7638
|
+
deps.db,
|
|
7639
|
+
context,
|
|
7640
|
+
input,
|
|
7641
|
+
() => deps.getDocumentServices().embedder,
|
|
7642
|
+
void 0,
|
|
7643
|
+
deps.settings
|
|
7644
|
+
)
|
|
7602
7645
|
)
|
|
7603
7646
|
);
|
|
7604
7647
|
server.registerTool(
|
|
@@ -7613,7 +7656,13 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
7613
7656
|
}).extend({ view: z8.enum(["published", "needs_review"]).default("published") }).shape
|
|
7614
7657
|
},
|
|
7615
7658
|
(input) => run(
|
|
7616
|
-
(context) => searchKnowledgeEntries(
|
|
7659
|
+
(context) => searchKnowledgeEntries(
|
|
7660
|
+
deps.db,
|
|
7661
|
+
context,
|
|
7662
|
+
input,
|
|
7663
|
+
() => deps.getDocumentServices().embedder,
|
|
7664
|
+
deps.settings
|
|
7665
|
+
)
|
|
7617
7666
|
)
|
|
7618
7667
|
);
|
|
7619
7668
|
server.registerTool(
|
|
@@ -7901,26 +7950,26 @@ async function listWorkspaceGitHubRepositoryBranches(deps, input, services = wor
|
|
|
7901
7950
|
])) {
|
|
7902
7951
|
throw new GitHubRepositoryBranchAuthorityError("changed");
|
|
7903
7952
|
}
|
|
7904
|
-
const
|
|
7953
|
+
const page2 = await services.listProviderBranches(deps, {
|
|
7905
7954
|
installationId: input.installationId,
|
|
7906
7955
|
repositoryId: input.repositoryId,
|
|
7907
7956
|
page: input.query.cursor,
|
|
7908
7957
|
limit: input.query.limit
|
|
7909
7958
|
});
|
|
7910
|
-
if (!
|
|
7959
|
+
if (!page2) {
|
|
7911
7960
|
throw new GitHubAppApiError(
|
|
7912
7961
|
"The configured GitHub provider cannot list exact repository branches"
|
|
7913
7962
|
);
|
|
7914
7963
|
}
|
|
7915
|
-
if (
|
|
7964
|
+
if (page2.installationId !== input.installationId || page2.repositoryId !== input.repositoryId || page2.branches.length > input.query.limit || page2.nextPage !== null && page2.nextPage !== input.query.cursor + 1 || page2.branches.length < input.query.limit && page2.nextPage !== null) {
|
|
7916
7965
|
throw new GitHubAppApiError("GitHub returned an invalid repository branches page");
|
|
7917
7966
|
}
|
|
7918
7967
|
const response = GitHubRepositoryBranchesResponseSchema.safeParse({
|
|
7919
|
-
branches:
|
|
7968
|
+
branches: page2.branches.map((name) => ({
|
|
7920
7969
|
name,
|
|
7921
|
-
isDefault: name ===
|
|
7970
|
+
isDefault: name === page2.defaultBranch
|
|
7922
7971
|
})),
|
|
7923
|
-
nextCursor:
|
|
7972
|
+
nextCursor: page2.nextPage
|
|
7924
7973
|
});
|
|
7925
7974
|
if (!response.success) {
|
|
7926
7975
|
throw new GitHubAppApiError("GitHub returned an invalid repository branches page");
|
|
@@ -8009,6 +8058,11 @@ import {
|
|
|
8009
8058
|
} from "@opengeni/db";
|
|
8010
8059
|
import { retryWhileMissing as retryWhileMissing4 } from "@opengeni/storage";
|
|
8011
8060
|
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
8061
|
+
import {
|
|
8062
|
+
isConnectedMachineAbsolutePath,
|
|
8063
|
+
relativeConnectedMachinePath,
|
|
8064
|
+
resolveConnectedMachinePath
|
|
8065
|
+
} from "@opengeni/runtime/sandbox";
|
|
8012
8066
|
|
|
8013
8067
|
// src/sandbox/channel-a.ts
|
|
8014
8068
|
import {
|
|
@@ -8016,6 +8070,7 @@ import {
|
|
|
8016
8070
|
hasGitCredentialRepositorySelection,
|
|
8017
8071
|
hasGitHubRepositorySelection,
|
|
8018
8072
|
sandboxLifecycleTransitionWaitMs,
|
|
8073
|
+
sandboxWarmRateMicrosPerSecond,
|
|
8019
8074
|
stableSandboxEnvironmentForRun
|
|
8020
8075
|
} from "@opengeni/config";
|
|
8021
8076
|
import { githubAppBotIdentity } from "@opengeni/github";
|
|
@@ -8034,6 +8089,7 @@ import {
|
|
|
8034
8089
|
SandboxImageConflictError,
|
|
8035
8090
|
SandboxProviderReadLockUnavailableError,
|
|
8036
8091
|
SandboxRigConflictError,
|
|
8092
|
+
SandboxPaidComputeAdmissionError,
|
|
8037
8093
|
withSandboxProviderReadLock
|
|
8038
8094
|
} from "@opengeni/db";
|
|
8039
8095
|
import { appendAndPublishEvents } from "@opengeni/events";
|
|
@@ -8853,6 +8909,10 @@ async function withChannelAOperation(services, ctx, readOnly, fn) {
|
|
|
8853
8909
|
holderId,
|
|
8854
8910
|
subjectId: session.id,
|
|
8855
8911
|
backend: session.sandboxBackend,
|
|
8912
|
+
warmBilling: {
|
|
8913
|
+
mode: settings.sandboxWarmBillingMode,
|
|
8914
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond(settings, session.sandboxBackend)
|
|
8915
|
+
},
|
|
8856
8916
|
os: session.sandboxOs,
|
|
8857
8917
|
image: sandboxRuntime.image,
|
|
8858
8918
|
rigVersionId: session.rigVersionId,
|
|
@@ -9153,6 +9213,8 @@ async function withChannelAOperation(services, ctx, readOnly, fn) {
|
|
|
9153
9213
|
}
|
|
9154
9214
|
function mapChannelAError(error, waitSignal) {
|
|
9155
9215
|
if (error instanceof HTTPException6) return error;
|
|
9216
|
+
if (error instanceof SandboxPaidComputeAdmissionError)
|
|
9217
|
+
return new HTTPException6(402, { message: error.message, cause: error });
|
|
9156
9218
|
if (isChannelARequestCancellation(error, waitSignal))
|
|
9157
9219
|
return new HTTPException6(499, {
|
|
9158
9220
|
message: "request cancelled",
|
|
@@ -9335,6 +9397,7 @@ import {
|
|
|
9335
9397
|
retainedGeneratedImageReferenceFromFile,
|
|
9336
9398
|
retainedGeneratedVideoReferenceFromFile,
|
|
9337
9399
|
retainedScreenshotReferenceFromFile,
|
|
9400
|
+
retainedSessionScreenshotKindFromObjectKey,
|
|
9338
9401
|
VideoArtifactPlaybackSource,
|
|
9339
9402
|
resolveRetainedOutputRange
|
|
9340
9403
|
} from "@opengeni/contracts";
|
|
@@ -9631,7 +9694,13 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
9631
9694
|
{
|
|
9632
9695
|
type: "text",
|
|
9633
9696
|
text: JSON.stringify(
|
|
9634
|
-
await searchKnowledgeEntries2(
|
|
9697
|
+
await searchKnowledgeEntries2(
|
|
9698
|
+
db,
|
|
9699
|
+
context,
|
|
9700
|
+
input,
|
|
9701
|
+
() => documentServices.embedder,
|
|
9702
|
+
options.settings
|
|
9703
|
+
)
|
|
9635
9704
|
)
|
|
9636
9705
|
}
|
|
9637
9706
|
]
|
|
@@ -9917,7 +9986,8 @@ async function prepareWorkspaceToolGatewayForGrantInternal(routeDeps, grant, all
|
|
|
9917
9986
|
grant.workspaceId,
|
|
9918
9987
|
routeDeps.getDocumentServices(),
|
|
9919
9988
|
{
|
|
9920
|
-
knowledge: await knowledgeContextForGateway(routeDeps, grant)
|
|
9989
|
+
knowledge: await knowledgeContextForGateway(routeDeps, grant),
|
|
9990
|
+
settings: gatewaySettings
|
|
9921
9991
|
}
|
|
9922
9992
|
)
|
|
9923
9993
|
)
|
|
@@ -11718,12 +11788,15 @@ function retainedGeneratedImageMetadata(artifact) {
|
|
|
11718
11788
|
}
|
|
11719
11789
|
function retainedScreenshotMetadata(artifact) {
|
|
11720
11790
|
if (artifact.status === "ready" && artifact.sessionId && artifact.retentionExpiresAt.getTime() > Date.now()) {
|
|
11791
|
+
const kind = retainedSessionScreenshotKindFromObjectKey(artifact.file.objectKey);
|
|
11792
|
+
if (!kind) return retainedArtifactUnavailable(artifact.artifactId, "invalid_content");
|
|
11721
11793
|
const reference = retainedScreenshotReferenceFromFile({
|
|
11722
11794
|
...artifact.file,
|
|
11723
11795
|
sessionId: artifact.sessionId,
|
|
11724
11796
|
width: artifact.width,
|
|
11725
11797
|
height: artifact.height,
|
|
11726
|
-
expiresAt: artifact.retentionExpiresAt.toISOString()
|
|
11798
|
+
expiresAt: artifact.retentionExpiresAt.toISOString(),
|
|
11799
|
+
kind
|
|
11727
11800
|
});
|
|
11728
11801
|
if (reference) return reference;
|
|
11729
11802
|
}
|
|
@@ -11798,13 +11871,12 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
11798
11871
|
message: "object storage cannot verify immutable artifact files"
|
|
11799
11872
|
});
|
|
11800
11873
|
}
|
|
11801
|
-
const path = sandboxArtifactRelativePath(input.path);
|
|
11802
11874
|
const maxArtifactBytes = Math.min(SANDBOX_FILE_ARTIFACT_MAX_BYTES, storage.maxSinglePutSizeBytes);
|
|
11803
11875
|
if (maxArtifactBytes < 1) {
|
|
11804
11876
|
throw new HTTPException12(503, { message: "object storage cannot accept artifact files" });
|
|
11805
11877
|
}
|
|
11806
11878
|
const readLimit = Math.min(25 * 1024 * 1024, maxArtifactBytes + FILE_READ_SENTINEL_BYTES);
|
|
11807
|
-
const read = await withChannelARead(
|
|
11879
|
+
const { path, sandboxPath, read } = await withChannelARead(
|
|
11808
11880
|
{
|
|
11809
11881
|
db: deps.db,
|
|
11810
11882
|
settings: deps.settings,
|
|
@@ -11819,7 +11891,7 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
11819
11891
|
...input.signal ? { waitSignal: input.signal } : {},
|
|
11820
11892
|
operation: "artifact.publish"
|
|
11821
11893
|
},
|
|
11822
|
-
({ service }) => service.
|
|
11894
|
+
({ service }) => readSandboxArtifactFile(service, input.path, readLimit)
|
|
11823
11895
|
);
|
|
11824
11896
|
if (read.truncated || read.sizeBytes > maxArtifactBytes) {
|
|
11825
11897
|
throw new HTTPException12(413, {
|
|
@@ -11929,42 +12001,46 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
11929
12001
|
});
|
|
11930
12002
|
return SandboxFileArtifactReceipt.parse({
|
|
11931
12003
|
type: "sandbox_file",
|
|
11932
|
-
sandboxPath
|
|
12004
|
+
sandboxPath,
|
|
11933
12005
|
filename,
|
|
11934
12006
|
artifact
|
|
11935
12007
|
});
|
|
11936
12008
|
}
|
|
11937
|
-
function
|
|
12009
|
+
async function readSandboxArtifactFile(service, value, maxBytes) {
|
|
12010
|
+
const root2 = service.capabilities().FileSystem.root;
|
|
12011
|
+
const path = sandboxArtifactRelativePath(value, root2);
|
|
12012
|
+
const sandboxPath = resolveConnectedMachinePath(root2, path);
|
|
12013
|
+
const read = await service.fsRead({ path, encoding: "base64", maxBytes });
|
|
12014
|
+
return { path, sandboxPath, read };
|
|
12015
|
+
}
|
|
12016
|
+
function sandboxArtifactRelativePath(value, workspaceRoot = "/workspace") {
|
|
11938
12017
|
let path = value.trim();
|
|
11939
12018
|
if (path.startsWith("sandbox:")) {
|
|
11940
12019
|
path = path.slice("sandbox:".length);
|
|
11941
12020
|
}
|
|
11942
|
-
if (path
|
|
12021
|
+
if (!path || /[\\/]$/.test(path)) {
|
|
11943
12022
|
throw new HTTPException12(400, { message: "sandbox artifact path must name a file" });
|
|
11944
12023
|
}
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
12024
|
+
let absolute;
|
|
12025
|
+
let relative;
|
|
12026
|
+
try {
|
|
12027
|
+
if (!isConnectedMachineAbsolutePath(workspaceRoot)) throw new Error("Missing workspace root");
|
|
12028
|
+
absolute = resolveConnectedMachinePath(workspaceRoot, path);
|
|
12029
|
+
relative = relativeConnectedMachinePath(workspaceRoot, absolute);
|
|
12030
|
+
} catch {
|
|
11948
12031
|
throw new HTTPException12(400, {
|
|
11949
|
-
message: "sandbox artifact path
|
|
12032
|
+
message: "sandbox artifact path is invalid for this workspace"
|
|
11950
12033
|
});
|
|
11951
12034
|
}
|
|
11952
|
-
if (!
|
|
11953
|
-
throw new HTTPException12(400, { message: "sandbox artifact path must name a file" });
|
|
11954
|
-
}
|
|
11955
|
-
if (path.includes("\0")) {
|
|
11956
|
-
throw new HTTPException12(400, { message: "sandbox artifact path is invalid" });
|
|
11957
|
-
}
|
|
11958
|
-
const normalized = posix.normalize(path);
|
|
11959
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith("../") || normalized.endsWith("/")) {
|
|
12035
|
+
if (!relative) {
|
|
11960
12036
|
throw new HTTPException12(400, {
|
|
11961
|
-
message: "sandbox artifact path must
|
|
12037
|
+
message: "sandbox artifact path must name a file inside the active workspace root"
|
|
11962
12038
|
});
|
|
11963
12039
|
}
|
|
11964
|
-
if (
|
|
12040
|
+
if (absolute.length > SANDBOX_ARTIFACT_ABSOLUTE_PATH_MAX_CHARS) {
|
|
11965
12041
|
throw new HTTPException12(400, { message: "sandbox artifact path is too long" });
|
|
11966
12042
|
}
|
|
11967
|
-
return
|
|
12043
|
+
return relative;
|
|
11968
12044
|
}
|
|
11969
12045
|
function sandboxArtifactSafeFilename(filename) {
|
|
11970
12046
|
return sanitizeFilename(filename).slice(0, SANDBOX_ARTIFACT_SAFE_FILENAME_MAX_CHARS);
|
|
@@ -15624,16 +15700,16 @@ function capEventPayload(event, perFieldChars) {
|
|
|
15624
15700
|
function prettyJsonBytes(value) {
|
|
15625
15701
|
return Buffer.byteLength(JSON.stringify(value, null, 2), "utf8");
|
|
15626
15702
|
}
|
|
15627
|
-
function setMeasuredBytes(
|
|
15628
|
-
let measured =
|
|
15703
|
+
function setMeasuredBytes(page2) {
|
|
15704
|
+
let measured = page2.bytes;
|
|
15629
15705
|
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
15630
|
-
|
|
15631
|
-
const next = prettyJsonBytes(
|
|
15706
|
+
page2.bytes = measured;
|
|
15707
|
+
const next = prettyJsonBytes(page2);
|
|
15632
15708
|
if (next === measured) return next;
|
|
15633
15709
|
measured = next;
|
|
15634
15710
|
}
|
|
15635
|
-
|
|
15636
|
-
return prettyJsonBytes(
|
|
15711
|
+
page2.bytes = measured;
|
|
15712
|
+
return prettyJsonBytes(page2);
|
|
15637
15713
|
}
|
|
15638
15714
|
function boundSessionEventMcpPage(input) {
|
|
15639
15715
|
const maxBytes = Math.max(8 * 1024, input.maxBytes ?? SESSION_EVENT_MCP_MAX_BYTES);
|
|
@@ -15655,7 +15731,7 @@ function boundSessionEventMcpPage(input) {
|
|
|
15655
15731
|
if (modelRowsDropped) reasons.push("model_bytes");
|
|
15656
15732
|
const nextAfter = input.direction === "after" ? last ?? input.after : null;
|
|
15657
15733
|
const nextBefore = input.direction === "before" ? first ?? input.before : null;
|
|
15658
|
-
const
|
|
15734
|
+
const page3 = {
|
|
15659
15735
|
mode: input.mode,
|
|
15660
15736
|
payloadMode: input.payloadMode,
|
|
15661
15737
|
direction: input.direction,
|
|
@@ -15675,20 +15751,20 @@ function boundSessionEventMcpPage(input) {
|
|
|
15675
15751
|
bytes: 0,
|
|
15676
15752
|
maxBytes
|
|
15677
15753
|
};
|
|
15678
|
-
setMeasuredBytes(
|
|
15679
|
-
return
|
|
15754
|
+
setMeasuredBytes(page3);
|
|
15755
|
+
return page3;
|
|
15680
15756
|
};
|
|
15681
|
-
let
|
|
15682
|
-
while (
|
|
15757
|
+
let page2 = build();
|
|
15758
|
+
while (page2.bytes > maxBytes && events.length > 0) {
|
|
15683
15759
|
if (input.direction === "before") events.shift();
|
|
15684
15760
|
else events.pop();
|
|
15685
15761
|
modelRowsDropped = true;
|
|
15686
|
-
|
|
15762
|
+
page2 = build();
|
|
15687
15763
|
}
|
|
15688
|
-
if (
|
|
15764
|
+
if (page2.bytes > maxBytes) {
|
|
15689
15765
|
throw new RangeError(`Session-event MCP metadata exceeds its ${maxBytes}-byte envelope`);
|
|
15690
15766
|
}
|
|
15691
|
-
return
|
|
15767
|
+
return page2;
|
|
15692
15768
|
}
|
|
15693
15769
|
function modelStringProjection(value, maxBytes) {
|
|
15694
15770
|
const originalBytes = Buffer.byteLength(value, "utf8");
|
|
@@ -16145,9 +16221,9 @@ function boundRigDetailMcp(rig, versionsPage, changesPage, maxBytes = RIG_DETAIL
|
|
|
16145
16221
|
}
|
|
16146
16222
|
|
|
16147
16223
|
// src/mcp/child-read-evidence.ts
|
|
16148
|
-
function completeChildReadSequences(
|
|
16149
|
-
if (!
|
|
16150
|
-
return
|
|
16224
|
+
function completeChildReadSequences(page2) {
|
|
16225
|
+
if (!page2.sourceExact || !["conversation", "results"].includes(page2.view)) return [];
|
|
16226
|
+
return page2.events.filter((event) => {
|
|
16151
16227
|
if (event.sourceOmitted) return false;
|
|
16152
16228
|
if (event.fragment === void 0) return true;
|
|
16153
16229
|
if (!event.fragment || typeof event.fragment !== "object") return false;
|
|
@@ -17042,7 +17118,7 @@ function boundScheduledTaskMcpPage(input) {
|
|
|
17042
17118
|
const rowsDroppedForBytes = droppedTasks.length > 0;
|
|
17043
17119
|
const hasMore = input.sourceHasMore || rowsDroppedForBytes;
|
|
17044
17120
|
const nextOffset = hasMore && input.tasks.length > 0 ? input.offset + input.tasks.length : null;
|
|
17045
|
-
const
|
|
17121
|
+
const page3 = {
|
|
17046
17122
|
tasks: summaries,
|
|
17047
17123
|
page: {
|
|
17048
17124
|
limit: input.limit,
|
|
@@ -17070,20 +17146,20 @@ function boundScheduledTaskMcpPage(input) {
|
|
|
17070
17146
|
}
|
|
17071
17147
|
};
|
|
17072
17148
|
settleMeasuredBytes(
|
|
17073
|
-
|
|
17074
|
-
() =>
|
|
17149
|
+
page3,
|
|
17150
|
+
() => page3.projection.bytes,
|
|
17075
17151
|
(bytes) => {
|
|
17076
|
-
|
|
17152
|
+
page3.projection.bytes = bytes;
|
|
17077
17153
|
}
|
|
17078
17154
|
);
|
|
17079
|
-
return
|
|
17155
|
+
return page3;
|
|
17080
17156
|
};
|
|
17081
|
-
let
|
|
17082
|
-
while (
|
|
17157
|
+
let page2 = build();
|
|
17158
|
+
while (page2.projection.bytes > maxBytes && summaries.length > 0) {
|
|
17083
17159
|
summaries = summaries.slice(0, -1);
|
|
17084
|
-
|
|
17160
|
+
page2 = build();
|
|
17085
17161
|
}
|
|
17086
|
-
return
|
|
17162
|
+
return page2;
|
|
17087
17163
|
}
|
|
17088
17164
|
|
|
17089
17165
|
// src/sandbox/viewer.ts
|
|
@@ -17094,6 +17170,7 @@ import {
|
|
|
17094
17170
|
hasGitHubRepositorySelection as hasGitHubRepositorySelection2,
|
|
17095
17171
|
resolveStreamTokenSecret,
|
|
17096
17172
|
sandboxLifecycleTransitionWaitMs as sandboxLifecycleTransitionWaitMs2,
|
|
17173
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond2,
|
|
17097
17174
|
stableSandboxEnvironmentForRun as stableSandboxEnvironmentForRun2
|
|
17098
17175
|
} from "@opengeni/config";
|
|
17099
17176
|
import { githubAppBotIdentity as githubAppBotIdentity2 } from "@opengeni/github";
|
|
@@ -17103,7 +17180,7 @@ import {
|
|
|
17103
17180
|
getSandbox as getSandbox2,
|
|
17104
17181
|
getScheduledScopedRigVersionMetadata as getScheduledScopedRigVersionMetadata2,
|
|
17105
17182
|
getSandboxSessionEnvelope as getSandboxSessionEnvelope2,
|
|
17106
|
-
|
|
17183
|
+
heartbeatLeaseHolderStatus,
|
|
17107
17184
|
loadWorkspaceEnvironmentForRun as loadWorkspaceEnvironmentForRun2,
|
|
17108
17185
|
markSandboxProviderReady,
|
|
17109
17186
|
markWarmLeaseInstanceLost as markWarmLeaseInstanceLost2,
|
|
@@ -17113,6 +17190,7 @@ import {
|
|
|
17113
17190
|
releaseLeaseHolder as releaseLeaseHolder2,
|
|
17114
17191
|
SandboxLeaseSupersededError as SandboxLeaseSupersededError2,
|
|
17115
17192
|
SandboxViewerAdmissionBlockedError,
|
|
17193
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError2,
|
|
17116
17194
|
getSessionAuthorityEpoch,
|
|
17117
17195
|
namedSubjectHasLiveWorkspaceAuthority
|
|
17118
17196
|
} from "@opengeni/db";
|
|
@@ -17242,6 +17320,10 @@ async function attachViewer(services, input) {
|
|
|
17242
17320
|
...attachSubjectId ? { viewerSubjectId: attachSubjectId } : {},
|
|
17243
17321
|
...attachAuthorityEpoch !== null ? { viewerAuthorityEpoch: attachAuthorityEpoch } : {},
|
|
17244
17322
|
backend: session.sandboxBackend,
|
|
17323
|
+
warmBilling: {
|
|
17324
|
+
mode: settings.sandboxWarmBillingMode,
|
|
17325
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond2(settings, session.sandboxBackend)
|
|
17326
|
+
},
|
|
17245
17327
|
os: session.sandboxOs,
|
|
17246
17328
|
image: sandboxRuntime.image,
|
|
17247
17329
|
rigVersionId: session.rigVersionId,
|
|
@@ -17251,6 +17333,9 @@ async function attachViewer(services, input) {
|
|
|
17251
17333
|
...input.waitSignal ? { waitSignal: input.waitSignal } : {}
|
|
17252
17334
|
});
|
|
17253
17335
|
} catch (error) {
|
|
17336
|
+
if (error instanceof SandboxPaidComputeAdmissionError2) {
|
|
17337
|
+
throw new HTTPException19(402, { message: error.message, cause: error });
|
|
17338
|
+
}
|
|
17254
17339
|
if (error instanceof SandboxViewerAdmissionBlockedError) {
|
|
17255
17340
|
throw new HTTPException19(error.reason === "balance" ? 402 : 429, {
|
|
17256
17341
|
message: error.reason === "balance" ? "insufficient OpenGeni credits for an idle sandbox viewer" : "workspace sandbox warm allowance exhausted",
|
|
@@ -17437,16 +17522,17 @@ async function ensureSessionGroupReady(services, input) {
|
|
|
17437
17522
|
throw lastError ?? new Error("sandbox readiness could not be established");
|
|
17438
17523
|
}
|
|
17439
17524
|
async function heartbeatViewer(services, input) {
|
|
17440
|
-
const
|
|
17525
|
+
const status = await heartbeatLeaseHolderStatus(services.db, {
|
|
17441
17526
|
accountId: input.accountId,
|
|
17442
17527
|
workspaceId: input.workspaceId,
|
|
17443
17528
|
sandboxGroupId: input.sandboxGroupId,
|
|
17444
17529
|
kind: "viewer",
|
|
17445
17530
|
holderId: input.viewerId,
|
|
17446
17531
|
leaseTtlMs: services.settings.sandboxLeaseTtlMs,
|
|
17447
|
-
expectedEpoch: input.expectedEpoch
|
|
17532
|
+
expectedEpoch: input.expectedEpoch,
|
|
17533
|
+
billingMode: services.settings.sandboxWarmBillingMode
|
|
17448
17534
|
});
|
|
17449
|
-
if (!
|
|
17535
|
+
if (!status.leaseExtended) return status.holderAlive && status.fence === "funding";
|
|
17450
17536
|
const lease = await readLease2(services.db, input.workspaceId, input.sandboxGroupId);
|
|
17451
17537
|
if (lease?.liveness === "warm" && lease.leaseEpoch === input.expectedEpoch && lease.instanceId) {
|
|
17452
17538
|
await renewSandboxProviderExpiration({
|
|
@@ -18326,7 +18412,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18326
18412
|
let reactedMessage = null;
|
|
18327
18413
|
const checkpointCreatedAtMs = restored?.state.createdAtMs ?? Date.now();
|
|
18328
18414
|
const firstPage = restored?.state.pageCount ?? 0;
|
|
18329
|
-
for (let
|
|
18415
|
+
for (let page2 = firstPage; page2 < MAX_REACTION_CONTEXT_PAGES; page2 += 1) {
|
|
18330
18416
|
const payload = await this.call(headers, "conversations.replies", {
|
|
18331
18417
|
channel: input.channelId,
|
|
18332
18418
|
// Slack accepts either the parent timestamp or a message timestamp from
|
|
@@ -18350,7 +18436,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18350
18436
|
throw new SlackBotProviderError("reaction_pagination_invalid");
|
|
18351
18437
|
}
|
|
18352
18438
|
seenCursors.add(nextCursor);
|
|
18353
|
-
const pageCount =
|
|
18439
|
+
const pageCount = page2 + 1;
|
|
18354
18440
|
if (pageCount >= MAX_REACTION_CONTEXT_PAGES) {
|
|
18355
18441
|
throw new SlackBotProviderError("reaction_pagination_exhausted");
|
|
18356
18442
|
}
|
|
@@ -18576,14 +18662,14 @@ var OpenGeniSlackBotClient = class {
|
|
|
18576
18662
|
if (offset > content.length) {
|
|
18577
18663
|
throw new SlackBotProviderError("invalid_file_offset");
|
|
18578
18664
|
}
|
|
18579
|
-
const
|
|
18580
|
-
const nextOffset = offset +
|
|
18665
|
+
const page2 = content.slice(offset, offset + SLACK_FILE_CONTENT_PAGE_CHARS);
|
|
18666
|
+
const nextOffset = offset + page2.length < content.length ? offset + page2.length : null;
|
|
18581
18667
|
return {
|
|
18582
18668
|
channel: info,
|
|
18583
18669
|
file,
|
|
18584
18670
|
contentType,
|
|
18585
18671
|
offset,
|
|
18586
|
-
content:
|
|
18672
|
+
content: page2,
|
|
18587
18673
|
nextOffset,
|
|
18588
18674
|
truncated: nextOffset !== null
|
|
18589
18675
|
};
|
|
@@ -18985,7 +19071,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18985
19071
|
let cursor = null;
|
|
18986
19072
|
let matchedTimestamp = null;
|
|
18987
19073
|
let exhausted = false;
|
|
18988
|
-
for (let
|
|
19074
|
+
for (let page2 = 0; page2 < MAX_SLACK_POST_RECONCILIATION_PAGES; page2 += 1) {
|
|
18989
19075
|
const payload = await this.call(headers, method, {
|
|
18990
19076
|
channel: input.channelId,
|
|
18991
19077
|
limit: String(input.threadTimestamp ? MAX_THREAD_PAGE : MAX_HISTORY_PAGE),
|
|
@@ -20092,13 +20178,13 @@ function nextSlackFilesListPage(payload, requested, returnedFileCount) {
|
|
|
20092
20178
|
}
|
|
20093
20179
|
const count = paging?.count;
|
|
20094
20180
|
const total = paging?.total;
|
|
20095
|
-
const
|
|
20181
|
+
const page2 = paging?.page;
|
|
20096
20182
|
const pages = paging?.pages;
|
|
20097
|
-
if (!positiveSafeInt(count) || !nonNegativeSafeInt(total) || !positiveSafeInt(
|
|
20183
|
+
if (!positiveSafeInt(count) || !nonNegativeSafeInt(total) || !positiveSafeInt(page2) || !nonNegativeSafeInt(pages) || count !== requested.count || page2 !== requested.page || returnedFileCount > count || pages !== (total === 0 ? 0 : Math.ceil(total / count)) || page2 > Math.max(1, pages)) {
|
|
20098
20184
|
throw new SlackBotProviderError("invalid_files_paging");
|
|
20099
20185
|
}
|
|
20100
|
-
if (
|
|
20101
|
-
const nextPage =
|
|
20186
|
+
if (page2 >= pages) return null;
|
|
20187
|
+
const nextPage = page2 + 1;
|
|
20102
20188
|
if (!positiveSafeInt(nextPage)) {
|
|
20103
20189
|
throw new SlackBotProviderError("invalid_files_paging");
|
|
20104
20190
|
}
|
|
@@ -20459,14 +20545,14 @@ var FikenClient = class {
|
|
|
20459
20545
|
resolveCredential;
|
|
20460
20546
|
expectedConnectionVersion;
|
|
20461
20547
|
async listCompanies(input = {}) {
|
|
20462
|
-
const { payload, page } = await this.request("companies.list", "GET", "/companies", {
|
|
20548
|
+
const { payload, page: page2 } = await this.request("companies.list", "GET", "/companies", {
|
|
20463
20549
|
query: pageQuery(input)
|
|
20464
20550
|
});
|
|
20465
|
-
return { companies: projectArray(payload), page };
|
|
20551
|
+
return { companies: projectArray(payload), page: page2 };
|
|
20466
20552
|
}
|
|
20467
20553
|
async listContacts(input) {
|
|
20468
20554
|
const slug = this.companySlugFor(input.companySlug);
|
|
20469
|
-
const { payload, page } = await this.request(
|
|
20555
|
+
const { payload, page: page2 } = await this.request(
|
|
20470
20556
|
"contacts.list",
|
|
20471
20557
|
"GET",
|
|
20472
20558
|
`/companies/${slug}/contacts`,
|
|
@@ -20482,7 +20568,7 @@ var FikenClient = class {
|
|
|
20482
20568
|
}
|
|
20483
20569
|
}
|
|
20484
20570
|
);
|
|
20485
|
-
return { companySlug: slug, contacts: projectArray(payload), page };
|
|
20571
|
+
return { companySlug: slug, contacts: projectArray(payload), page: page2 };
|
|
20486
20572
|
}
|
|
20487
20573
|
async createContact(input) {
|
|
20488
20574
|
const slug = this.companySlugFor(input.companySlug);
|
|
@@ -20508,7 +20594,7 @@ var FikenClient = class {
|
|
|
20508
20594
|
}
|
|
20509
20595
|
async listProducts(input) {
|
|
20510
20596
|
const slug = this.companySlugFor(input.companySlug);
|
|
20511
|
-
const { payload, page } = await this.request(
|
|
20597
|
+
const { payload, page: page2 } = await this.request(
|
|
20512
20598
|
"products.list",
|
|
20513
20599
|
"GET",
|
|
20514
20600
|
`/companies/${slug}/products`,
|
|
@@ -20520,11 +20606,11 @@ var FikenClient = class {
|
|
|
20520
20606
|
}
|
|
20521
20607
|
}
|
|
20522
20608
|
);
|
|
20523
|
-
return { companySlug: slug, products: projectArray(payload), page };
|
|
20609
|
+
return { companySlug: slug, products: projectArray(payload), page: page2 };
|
|
20524
20610
|
}
|
|
20525
20611
|
async listInvoices(input) {
|
|
20526
20612
|
const slug = this.companySlugFor(input.companySlug);
|
|
20527
|
-
const { payload, page } = await this.request(
|
|
20613
|
+
const { payload, page: page2 } = await this.request(
|
|
20528
20614
|
"invoices.list",
|
|
20529
20615
|
"GET",
|
|
20530
20616
|
`/companies/${slug}/invoices`,
|
|
@@ -20539,7 +20625,7 @@ var FikenClient = class {
|
|
|
20539
20625
|
}
|
|
20540
20626
|
}
|
|
20541
20627
|
);
|
|
20542
|
-
return { companySlug: slug, invoices: projectArray(payload), page };
|
|
20628
|
+
return { companySlug: slug, invoices: projectArray(payload), page: page2 };
|
|
20543
20629
|
}
|
|
20544
20630
|
async getInvoice(input) {
|
|
20545
20631
|
const slug = this.companySlugFor(input.companySlug);
|
|
@@ -20623,7 +20709,7 @@ var FikenClient = class {
|
|
|
20623
20709
|
}
|
|
20624
20710
|
async listBankAccounts(input) {
|
|
20625
20711
|
const slug = this.companySlugFor(input.companySlug);
|
|
20626
|
-
const { payload, page } = await this.request(
|
|
20712
|
+
const { payload, page: page2 } = await this.request(
|
|
20627
20713
|
"bank_accounts.list",
|
|
20628
20714
|
"GET",
|
|
20629
20715
|
`/companies/${slug}/bankAccounts`,
|
|
@@ -20634,11 +20720,11 @@ var FikenClient = class {
|
|
|
20634
20720
|
}
|
|
20635
20721
|
}
|
|
20636
20722
|
);
|
|
20637
|
-
return { companySlug: slug, bankAccounts: projectArray(payload), page };
|
|
20723
|
+
return { companySlug: slug, bankAccounts: projectArray(payload), page: page2 };
|
|
20638
20724
|
}
|
|
20639
20725
|
async listPurchases(input) {
|
|
20640
20726
|
const slug = this.companySlugFor(input.companySlug);
|
|
20641
|
-
const { payload, page } = await this.request(
|
|
20727
|
+
const { payload, page: page2 } = await this.request(
|
|
20642
20728
|
"purchases.list",
|
|
20643
20729
|
"GET",
|
|
20644
20730
|
`/companies/${slug}/purchases`,
|
|
@@ -20651,11 +20737,11 @@ var FikenClient = class {
|
|
|
20651
20737
|
}
|
|
20652
20738
|
}
|
|
20653
20739
|
);
|
|
20654
|
-
return { companySlug: slug, purchases: projectArray(payload), page };
|
|
20740
|
+
return { companySlug: slug, purchases: projectArray(payload), page: page2 };
|
|
20655
20741
|
}
|
|
20656
20742
|
async listSales(input) {
|
|
20657
20743
|
const slug = this.companySlugFor(input.companySlug);
|
|
20658
|
-
const { payload, page } = await this.request("sales.list", "GET", `/companies/${slug}/sales`, {
|
|
20744
|
+
const { payload, page: page2 } = await this.request("sales.list", "GET", `/companies/${slug}/sales`, {
|
|
20659
20745
|
query: {
|
|
20660
20746
|
...pageQuery(input),
|
|
20661
20747
|
...input.dateGe ? { dateGe: input.dateGe } : {},
|
|
@@ -20663,7 +20749,7 @@ var FikenClient = class {
|
|
|
20663
20749
|
...input.settled !== void 0 ? { settled: String(input.settled) } : {}
|
|
20664
20750
|
}
|
|
20665
20751
|
});
|
|
20666
|
-
return { companySlug: slug, sales: projectArray(payload), page };
|
|
20752
|
+
return { companySlug: slug, sales: projectArray(payload), page: page2 };
|
|
20667
20753
|
}
|
|
20668
20754
|
/**
|
|
20669
20755
|
* The company scope for a call: an explicit slug wins, then the connection's
|
|
@@ -20865,11 +20951,11 @@ function boundedInt2(value, max, fallback) {
|
|
|
20865
20951
|
return Math.min(value, max);
|
|
20866
20952
|
}
|
|
20867
20953
|
function pageFromHeaders(headers) {
|
|
20868
|
-
const
|
|
20954
|
+
const page2 = headerInt(headers, "fiken-api-page");
|
|
20869
20955
|
const pageSize = headerInt(headers, "fiken-api-page-size");
|
|
20870
|
-
if (
|
|
20956
|
+
if (page2 === null || pageSize === null) return null;
|
|
20871
20957
|
return {
|
|
20872
|
-
page,
|
|
20958
|
+
page: page2,
|
|
20873
20959
|
pageSize,
|
|
20874
20960
|
pageCount: headerInt(headers, "fiken-api-page-count"),
|
|
20875
20961
|
resultCount: headerInt(headers, "fiken-api-result-count")
|
|
@@ -21828,24 +21914,24 @@ async function getAtlassianLiveItem(deps, input) {
|
|
|
21828
21914
|
);
|
|
21829
21915
|
url.searchParams.set("body-format", "storage");
|
|
21830
21916
|
try {
|
|
21831
|
-
const
|
|
21917
|
+
const page2 = objectRecord(
|
|
21832
21918
|
await atlassianApiRequest(deps, { ...input, url, label: "Confluence live page" })
|
|
21833
21919
|
);
|
|
21834
21920
|
const source = sources.find(
|
|
21835
|
-
(candidate) => candidate.resourceId === optionalString(
|
|
21921
|
+
(candidate) => candidate.resourceId === optionalString(page2.spaceId)
|
|
21836
21922
|
);
|
|
21837
21923
|
if (!source) continue;
|
|
21838
21924
|
const comments = await readConfluenceLiveComments(deps, input, cloudId);
|
|
21839
|
-
const webUi = optionalString(objectRecord(
|
|
21925
|
+
const webUi = optionalString(objectRecord(page2._links).webui);
|
|
21840
21926
|
return {
|
|
21841
21927
|
kind: "confluence_page",
|
|
21842
|
-
id: requiredString2(
|
|
21843
|
-
title: requiredString2(
|
|
21928
|
+
id: requiredString2(page2.id, "page.id"),
|
|
21929
|
+
title: requiredString2(page2.title, "page.title"),
|
|
21844
21930
|
source: { id: source.id, name: source.name, siteName: source.siteName },
|
|
21845
|
-
status: optionalString(
|
|
21846
|
-
createdAt: optionalString(
|
|
21847
|
-
updatedAt: optionalString(objectRecord(
|
|
21848
|
-
content: optionalString(objectRecord(objectRecord(
|
|
21931
|
+
status: optionalString(page2.status),
|
|
21932
|
+
createdAt: optionalString(page2.createdAt),
|
|
21933
|
+
updatedAt: optionalString(objectRecord(page2.version).createdAt),
|
|
21934
|
+
content: optionalString(objectRecord(objectRecord(page2.body).storage).value) ?? "",
|
|
21849
21935
|
comments,
|
|
21850
21936
|
url: webUi ? new URL(webUi.startsWith("/wiki/") ? webUi : `/wiki${webUi}`, source.siteUrl).toString() : source.siteUrl
|
|
21851
21937
|
};
|
|
@@ -22359,7 +22445,7 @@ async function materializeSchedules(deps, input) {
|
|
|
22359
22445
|
async function browseJiraProjects(deps, input, site) {
|
|
22360
22446
|
const items = [];
|
|
22361
22447
|
let startAt = 0;
|
|
22362
|
-
for (let
|
|
22448
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22363
22449
|
const url = new URL(
|
|
22364
22450
|
`https://api.atlassian.com/ex/jira/${encodeURIComponent(site.cloudId)}/rest/api/3/project/search`
|
|
22365
22451
|
);
|
|
@@ -22402,7 +22488,7 @@ async function browseConfluenceSpaces(deps, input, site) {
|
|
|
22402
22488
|
let url = new URL(
|
|
22403
22489
|
`https://api.atlassian.com/ex/confluence/${encodeURIComponent(site.cloudId)}/wiki/api/v2/spaces?limit=100`
|
|
22404
22490
|
);
|
|
22405
|
-
for (let
|
|
22491
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22406
22492
|
const payload = objectRecord(
|
|
22407
22493
|
await atlassianApiRequest(deps, { ...input, url, label: "Confluence spaces" })
|
|
22408
22494
|
);
|
|
@@ -22802,7 +22888,7 @@ function cqlString(value) {
|
|
|
22802
22888
|
async function readJiraLiveComments(deps, input, cloudId) {
|
|
22803
22889
|
const comments = [];
|
|
22804
22890
|
let startAt = 0;
|
|
22805
|
-
for (let
|
|
22891
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22806
22892
|
const url = new URL(
|
|
22807
22893
|
`https://api.atlassian.com/ex/jira/${encodeURIComponent(cloudId)}/rest/api/3/issue/${encodeURIComponent(input.id)}/comment`
|
|
22808
22894
|
);
|
|
@@ -22830,7 +22916,7 @@ async function readJiraLiveComments(deps, input, cloudId) {
|
|
|
22830
22916
|
async function readConfluenceLiveComments(deps, input, cloudId) {
|
|
22831
22917
|
const comments = [];
|
|
22832
22918
|
let cursor = null;
|
|
22833
|
-
for (let
|
|
22919
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22834
22920
|
const url = new URL(
|
|
22835
22921
|
`https://api.atlassian.com/ex/confluence/${encodeURIComponent(cloudId)}/wiki/api/v2/pages/${encodeURIComponent(input.id)}/footer-comments`
|
|
22836
22922
|
);
|
|
@@ -27285,9 +27371,9 @@ function registerFikenTools(server, deps, grant, sessionId, json) {
|
|
|
27285
27371
|
...pageInputs
|
|
27286
27372
|
}
|
|
27287
27373
|
},
|
|
27288
|
-
async ({ connectionId, page, pageSize }) => json(
|
|
27374
|
+
async ({ connectionId, page: page2, pageSize }) => json(
|
|
27289
27375
|
await (await clientFor(connectionId)).listCompanies({
|
|
27290
|
-
...
|
|
27376
|
+
...page2 !== void 0 ? { page: page2 } : {},
|
|
27291
27377
|
...pageSize !== void 0 ? { pageSize } : {}
|
|
27292
27378
|
})
|
|
27293
27379
|
)
|
|
@@ -27669,7 +27755,7 @@ function registerGoalTools(server, deps, grant, sessionId, json) {
|
|
|
27669
27755
|
server.registerTool(
|
|
27670
27756
|
"goal_update",
|
|
27671
27757
|
{
|
|
27672
|
-
description: "
|
|
27758
|
+
description: "Maintain your operational goal as user direction or meaningful new evidence clarifies the intended outcome. Changes apply directly unless the user explicitly configured review_changes; refinement, adaptation, and replacement are audit classifications, not approval gates under the default policy. Use the exact expected objective revision and a concise rationale. Updating a goal grants no additional authority and cannot change root constraints. Use goal_progress for an execution-progress audit fact rather than a goal rewrite.",
|
|
27673
27759
|
inputSchema: {
|
|
27674
27760
|
text: goalText.optional(),
|
|
27675
27761
|
successCriteria: successCriteriaSchema.nullable().optional(),
|
|
@@ -29223,7 +29309,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29223
29309
|
if (decodedCursor && decodedCursor.updatedAfter !== (normalizedUpdatedAfter ?? null)) {
|
|
29224
29310
|
throw new Error("sessions_list cursor does not match updatedAfter");
|
|
29225
29311
|
}
|
|
29226
|
-
const
|
|
29312
|
+
const page2 = await listSessionDiscoverySummaries(deps.db, grant.workspaceId, {
|
|
29227
29313
|
limit: boundedSessionDiscoveryLimit(limit),
|
|
29228
29314
|
...decodedCursor ? { cursor: decodedCursor } : {},
|
|
29229
29315
|
includeLastMessage: includeLastMessage === true,
|
|
@@ -29243,7 +29329,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29243
29329
|
subjectId: grant.subjectId,
|
|
29244
29330
|
...authorizationScope ? { authorizationScope } : {}
|
|
29245
29331
|
});
|
|
29246
|
-
const result = detail === "full" ? capSessionDiscoveryPage(
|
|
29332
|
+
const result = detail === "full" ? capSessionDiscoveryPage(page2, includeLastMessage === true) : capSessionDiscoveryCompactPage(page2, {
|
|
29247
29333
|
includeLastMessage: includeLastMessage === true,
|
|
29248
29334
|
includeRelatedWork: relatedWorkRequested
|
|
29249
29335
|
});
|
|
@@ -29409,8 +29495,8 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29409
29495
|
}
|
|
29410
29496
|
if (view !== "debug" && !auditRequested) {
|
|
29411
29497
|
const { readSessionEventView } = await import("./session-event-view-MU3HMNV3.js");
|
|
29412
|
-
const { listSessionEventSlices } = await import("@opengeni/db/session-event-slices");
|
|
29413
|
-
const
|
|
29498
|
+
const { listSessionEventSlices: listSessionEventSlices2 } = await import("@opengeni/db/session-event-slices");
|
|
29499
|
+
const page3 = await readSessionEventView(
|
|
29414
29500
|
{
|
|
29415
29501
|
sessionId,
|
|
29416
29502
|
view,
|
|
@@ -29423,7 +29509,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29423
29509
|
direction: requestedDirection,
|
|
29424
29510
|
limit
|
|
29425
29511
|
},
|
|
29426
|
-
(options) =>
|
|
29512
|
+
(options) => listSessionEventSlices2(
|
|
29427
29513
|
deps.db,
|
|
29428
29514
|
grant.workspaceId,
|
|
29429
29515
|
sessionId,
|
|
@@ -29431,8 +29517,8 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29431
29517
|
(legacyOptions) => listSessionEventPage(deps.db, grant.workspaceId, sessionId, legacyOptions)
|
|
29432
29518
|
)
|
|
29433
29519
|
);
|
|
29434
|
-
await acknowledgeReads([{ sessionId, sequences: completeChildReadSequences(
|
|
29435
|
-
return json(
|
|
29520
|
+
await acknowledgeReads([{ sessionId, sequences: completeChildReadSequences(page3) }]);
|
|
29521
|
+
return json(page3);
|
|
29436
29522
|
}
|
|
29437
29523
|
if (cursor !== void 0 || callId !== void 0 || includeArguments !== void 0 || includeOutput !== void 0) {
|
|
29438
29524
|
throw new Error("cursor/callId/includeArguments/includeOutput require a non-debug view");
|
|
@@ -29477,7 +29563,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29477
29563
|
}
|
|
29478
29564
|
return json(result);
|
|
29479
29565
|
}
|
|
29480
|
-
const
|
|
29566
|
+
const page2 = boundSessionEventMcpPage({
|
|
29481
29567
|
events: dbPage.events,
|
|
29482
29568
|
mode,
|
|
29483
29569
|
payloadMode,
|
|
@@ -29487,12 +29573,12 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29487
29573
|
after: after ?? 0,
|
|
29488
29574
|
before: before ?? null
|
|
29489
29575
|
});
|
|
29490
|
-
if (payloadMode === "full" && dbPage.fullPayloadsExact && !
|
|
29576
|
+
if (payloadMode === "full" && dbPage.fullPayloadsExact && !page2.truncation?.reasons.includes("model_payload")) {
|
|
29491
29577
|
await acknowledgeReads([
|
|
29492
|
-
{ sessionId, sequences:
|
|
29578
|
+
{ sessionId, sequences: page2.events.map((event) => event.sequence) }
|
|
29493
29579
|
]);
|
|
29494
29580
|
}
|
|
29495
|
-
return json(
|
|
29581
|
+
return json(page2);
|
|
29496
29582
|
}
|
|
29497
29583
|
);
|
|
29498
29584
|
server.registerTool(
|
|
@@ -29548,7 +29634,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29548
29634
|
}
|
|
29549
29635
|
},
|
|
29550
29636
|
readTargetEvents: async (target) => {
|
|
29551
|
-
const
|
|
29637
|
+
const page2 = await listSessionEventPage(deps.db, workspaceId, target.sessionId, {
|
|
29552
29638
|
after: target.afterSequence,
|
|
29553
29639
|
direction: "after",
|
|
29554
29640
|
limit: SESSION_WAIT_EVENTS_PER_TARGET,
|
|
@@ -29556,10 +29642,10 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29556
29642
|
includeTypes: targetEventTypes,
|
|
29557
29643
|
maxBytes: SESSION_EVENT_MCP_MAX_BYTES * 4
|
|
29558
29644
|
});
|
|
29559
|
-
if (!
|
|
29560
|
-
for (const event of
|
|
29645
|
+
if (!page2.fullPayloadsExact) {
|
|
29646
|
+
for (const event of page2.events) incompleteWaitEvents.add(event.id);
|
|
29561
29647
|
}
|
|
29562
|
-
return { events:
|
|
29648
|
+
return { events: page2.events, hasMore: page2.hasMore };
|
|
29563
29649
|
},
|
|
29564
29650
|
readOwnPendingUpdateKinds: ownSessionId === null ? null : async () => (await listOutstandingSessionSystemUpdates(deps.db, workspaceId, ownSessionId)).map((update) => update.kind),
|
|
29565
29651
|
subscribe: (targetSessionId, onEvents) => deps.bus.subscribe(workspaceId, targetSessionId, onEvents)
|
|
@@ -30443,9 +30529,12 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30443
30529
|
};
|
|
30444
30530
|
const setupProjections = async (items) => {
|
|
30445
30531
|
const availableServerIds = /* @__PURE__ */ new Set();
|
|
30532
|
+
const availableFirstPartyTools = /* @__PURE__ */ new Set();
|
|
30446
30533
|
const acceptedServerIds = /* @__PURE__ */ new Set();
|
|
30447
30534
|
let accountSelectionKnown = false;
|
|
30448
|
-
if (items.some(
|
|
30535
|
+
if (items.some(
|
|
30536
|
+
(item) => item.enabled && (item.connectionRef || item.surfaceType === "first_party_fiken")
|
|
30537
|
+
)) {
|
|
30449
30538
|
const claims = exactAgentCommandContext(grant, sessionId);
|
|
30450
30539
|
const attemptCatalog = await getAttemptToolCatalog2(deps.db, {
|
|
30451
30540
|
accountId: grant.accountId,
|
|
@@ -30453,7 +30542,11 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30453
30542
|
attemptId: claims.callerAttemptId
|
|
30454
30543
|
});
|
|
30455
30544
|
if (attemptCatalog?.sessionId === sessionId && attemptCatalog.turnId === claims.callerTurnId && attemptCatalog.executionGeneration === claims.callerExecutionGeneration) {
|
|
30456
|
-
for (const entry2 of attemptCatalog.entries)
|
|
30545
|
+
for (const entry2 of attemptCatalog.entries) {
|
|
30546
|
+
availableServerIds.add(entry2.identity.serverId);
|
|
30547
|
+
if (entry2.identity.serverId === "opengeni")
|
|
30548
|
+
availableFirstPartyTools.add(entry2.identity.toolName);
|
|
30549
|
+
}
|
|
30457
30550
|
const bindings = await getSessionTurnMcpAccountBindings(
|
|
30458
30551
|
deps.db,
|
|
30459
30552
|
grant.workspaceId,
|
|
@@ -30474,7 +30567,9 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30474
30567
|
item,
|
|
30475
30568
|
availableServerIds,
|
|
30476
30569
|
acceptedServerIds,
|
|
30477
|
-
accountSelectionKnown
|
|
30570
|
+
accountSelectionKnown,
|
|
30571
|
+
availableFirstPartyTools,
|
|
30572
|
+
new Set(grant.metadata?.firstPartyMcpTools ?? [])
|
|
30478
30573
|
)
|
|
30479
30574
|
)
|
|
30480
30575
|
);
|
|
@@ -30592,8 +30687,93 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30592
30687
|
});
|
|
30593
30688
|
}
|
|
30594
30689
|
);
|
|
30690
|
+
server.registerTool(
|
|
30691
|
+
"custom_mcp_setup_request",
|
|
30692
|
+
{
|
|
30693
|
+
description: "Show a review card for a remote HTTPS MCP server that is not in the workspace catalog. Use only an endpoint supplied by the user or established by reliable documentation; do not invent a URL. Never include query parameters or secrets in this URL; the human can edit it in the protected setup form. The agent cannot add, enable, or contact the server. Search the catalog first and do not propose an already available integration.",
|
|
30694
|
+
inputSchema: {
|
|
30695
|
+
name: z43.string().trim().min(1).max(256),
|
|
30696
|
+
endpointUrl: z43.string().url().max(2048).refine((url) => {
|
|
30697
|
+
const parsed = new URL(url);
|
|
30698
|
+
return parsed.protocol === "https:" && !parsed.username && !parsed.password && !parsed.hash && !parsed.search;
|
|
30699
|
+
}),
|
|
30700
|
+
rationale: z43.string().trim().min(1).max(2e3)
|
|
30701
|
+
}
|
|
30702
|
+
},
|
|
30703
|
+
async ({ name, endpointUrl, rationale }) => {
|
|
30704
|
+
await authorize();
|
|
30705
|
+
const current = await catalog();
|
|
30706
|
+
const existing = current.items.find(
|
|
30707
|
+
(item) => item.kind === "mcp" && item.endpointUrl === endpointUrl && !item.stale
|
|
30708
|
+
);
|
|
30709
|
+
if (existing) {
|
|
30710
|
+
return json({
|
|
30711
|
+
status: "already_in_catalog",
|
|
30712
|
+
capabilityId: existing.id,
|
|
30713
|
+
message: "Use the catalog authorization flow for this server instead."
|
|
30714
|
+
});
|
|
30715
|
+
}
|
|
30716
|
+
const claims = exactAgentCommandContext(grant, sessionId);
|
|
30717
|
+
const payload = ToolAuthNeededPayload.parse({
|
|
30718
|
+
serverId: "opengeni",
|
|
30719
|
+
toolName: "custom_mcp_setup_request",
|
|
30720
|
+
providerDomain: new URL(endpointUrl).hostname,
|
|
30721
|
+
reason: "missing_connection",
|
|
30722
|
+
setupRequest: { kind: "mcp", name, endpointUrl, rationale }
|
|
30723
|
+
});
|
|
30724
|
+
const appended = await appendAndPublishTurnEventsFenced(
|
|
30725
|
+
deps.db,
|
|
30726
|
+
deps.bus,
|
|
30727
|
+
grant.workspaceId,
|
|
30728
|
+
sessionId,
|
|
30729
|
+
claims.callerTurnId,
|
|
30730
|
+
claims.callerExecutionGeneration,
|
|
30731
|
+
claims.callerAttemptId,
|
|
30732
|
+
[{ type: "tool.auth_needed", payload }]
|
|
30733
|
+
);
|
|
30734
|
+
if (!appended.accepted) {
|
|
30735
|
+
throw new Error("The calling turn was replaced before the setup request committed.");
|
|
30736
|
+
}
|
|
30737
|
+
return json({
|
|
30738
|
+
status: "setup_requested",
|
|
30739
|
+
eventId: appended.events[0]?.id ?? null,
|
|
30740
|
+
message: "The human review card was posted. No server was added or contacted."
|
|
30741
|
+
});
|
|
30742
|
+
}
|
|
30743
|
+
);
|
|
30595
30744
|
}
|
|
30596
|
-
async function capabilitySetupProjection(deps, workspaceId, item, availableServerIds, acceptedServerIds, accountSelectionKnown) {
|
|
30745
|
+
async function capabilitySetupProjection(deps, workspaceId, item, availableServerIds, acceptedServerIds, accountSelectionKnown, availableFirstPartyTools, selectedFirstPartyTools) {
|
|
30746
|
+
if (item.surfaceType === "first_party_fiken") {
|
|
30747
|
+
if (!item.enabled || item.metadata.connectionStatus !== "active") {
|
|
30748
|
+
return {
|
|
30749
|
+
status: "authorization_required",
|
|
30750
|
+
action: "connect",
|
|
30751
|
+
detail: item.metadata.connectionStatus === "needs_reauth" ? "The workspace Fiken connection needs reconnection." : "Connect Fiken through the protected setup form."
|
|
30752
|
+
};
|
|
30753
|
+
}
|
|
30754
|
+
const selected = FIRST_PARTY_MCP_TOOL_NAMES2.filter(
|
|
30755
|
+
(name) => name.startsWith("fiken_") && selectedFirstPartyTools.has(name)
|
|
30756
|
+
);
|
|
30757
|
+
if (selected.length === 0) {
|
|
30758
|
+
return {
|
|
30759
|
+
status: "authorization_required",
|
|
30760
|
+
action: "enable",
|
|
30761
|
+
detail: "Fiken is connected, but its tools are not selected for this conversation. Ask the user to add its tools through the setup card, then send a new message."
|
|
30762
|
+
};
|
|
30763
|
+
}
|
|
30764
|
+
if (selected.some((name) => availableFirstPartyTools.has(name))) {
|
|
30765
|
+
return {
|
|
30766
|
+
status: "ready",
|
|
30767
|
+
action: null,
|
|
30768
|
+
detail: "Fiken is connected and has tools available in this turn."
|
|
30769
|
+
};
|
|
30770
|
+
}
|
|
30771
|
+
return {
|
|
30772
|
+
status: "unavailable",
|
|
30773
|
+
action: null,
|
|
30774
|
+
detail: "Fiken is connected, but its selected tools are unavailable in this execution. Check tool permissions and setup before retrying; reconnection is not required by this status."
|
|
30775
|
+
};
|
|
30776
|
+
}
|
|
30597
30777
|
if (item.id === "api:github-app" || item.surfaceType === "first_party_github") {
|
|
30598
30778
|
const missing = githubAppMissingSettings(deps.settings);
|
|
30599
30779
|
if (missing.length > 0) {
|
|
@@ -30947,9 +31127,9 @@ function decodeSessionDiscoveryCursor(value) {
|
|
|
30947
31127
|
throw new Error("sessions_list cursor is invalid");
|
|
30948
31128
|
}
|
|
30949
31129
|
}
|
|
30950
|
-
function capSessionDiscoveryCompactPage(
|
|
31130
|
+
function capSessionDiscoveryCompactPage(page2, options = {}, maxBytes = SESSION_DISCOVERY_PAGE_MAX_BYTES) {
|
|
30951
31131
|
let previewBytes = 0;
|
|
30952
|
-
const projected =
|
|
31132
|
+
const projected = page2.sessions.map((session) => {
|
|
30953
31133
|
const row = {
|
|
30954
31134
|
...compactSessionMcpListRow(session, options.includeRelatedWork),
|
|
30955
31135
|
...options.includeLastMessage && session.queuedPromptCount > 0 ? { queuedPromptCount: session.queuedPromptCount } : {}
|
|
@@ -30986,24 +31166,24 @@ function capSessionDiscoveryCompactPage(page, options = {}, maxBytes = SESSION_D
|
|
|
30986
31166
|
let kept = projected;
|
|
30987
31167
|
const build = () => {
|
|
30988
31168
|
const dropped = kept.length < projected.length;
|
|
30989
|
-
const last =
|
|
31169
|
+
const last = page2.sessions[kept.length - 1];
|
|
30990
31170
|
const cursor = dropped && last ? {
|
|
30991
|
-
orderBy:
|
|
31171
|
+
orderBy: page2.orderBy,
|
|
30992
31172
|
sortRank: last.sortRank,
|
|
30993
31173
|
sortRevision: last.sortRevision,
|
|
30994
31174
|
sortAt: last.sortAt,
|
|
30995
31175
|
id: last.id,
|
|
30996
|
-
snapshotAt:
|
|
30997
|
-
snapshotRevision:
|
|
30998
|
-
updatedAfter:
|
|
30999
|
-
filterHash:
|
|
31000
|
-
...
|
|
31001
|
-
} :
|
|
31176
|
+
snapshotAt: page2.snapshotAt,
|
|
31177
|
+
snapshotRevision: page2.snapshotRevision,
|
|
31178
|
+
updatedAfter: page2.updatedAfter,
|
|
31179
|
+
filterHash: page2.filterHash,
|
|
31180
|
+
...page2.originSiteId ? { originSiteId: page2.originSiteId } : {}
|
|
31181
|
+
} : page2.nextCursor;
|
|
31002
31182
|
return {
|
|
31003
31183
|
sessions: kept,
|
|
31004
|
-
total:
|
|
31184
|
+
total: page2.total,
|
|
31005
31185
|
nextCursor: cursor ? encodeSessionDiscoveryCursor(cursor) : null,
|
|
31006
|
-
...
|
|
31186
|
+
...page2.orderBy === "updatedAt" ? { updatedThrough: page2.updatedThrough } : {},
|
|
31007
31187
|
...dropped ? {
|
|
31008
31188
|
responseTruncated: true,
|
|
31009
31189
|
truncationReason: `response exceeded ${maxBytes} bytes; continue with nextCursor`
|
|
@@ -31020,8 +31200,8 @@ function capSessionDiscoveryCompactPage(page, options = {}, maxBytes = SESSION_D
|
|
|
31020
31200
|
}
|
|
31021
31201
|
return result;
|
|
31022
31202
|
}
|
|
31023
|
-
function capSessionDiscoveryPage(
|
|
31024
|
-
const projected =
|
|
31203
|
+
function capSessionDiscoveryPage(page2, includeLastMessage) {
|
|
31204
|
+
const projected = page2.sessions.map((session) => {
|
|
31025
31205
|
const title = capSessionDiscoveryText(session.title, 200, session.titleOriginalChars);
|
|
31026
31206
|
const goal = session.goal ? capSessionDiscoveryText(
|
|
31027
31207
|
session.goal.text,
|
|
@@ -31108,29 +31288,29 @@ function capSessionDiscoveryPage(page, includeLastMessage) {
|
|
|
31108
31288
|
}).length : 0;
|
|
31109
31289
|
const lastKept = kept.at(-1);
|
|
31110
31290
|
const droppedForByteCap = kept.length < projected.length;
|
|
31111
|
-
const sourceLast = lastKept ?
|
|
31291
|
+
const sourceLast = lastKept ? page2.sessions.find((session) => session.id === lastKept.id) : void 0;
|
|
31112
31292
|
const nextCursor = droppedForByteCap ? sourceLast ? encodeSessionDiscoveryCursor({
|
|
31113
|
-
orderBy:
|
|
31293
|
+
orderBy: page2.orderBy,
|
|
31114
31294
|
sortRank: sourceLast.sortRank,
|
|
31115
31295
|
sortRevision: sourceLast.sortRevision,
|
|
31116
31296
|
sortAt: sourceLast.sortAt,
|
|
31117
31297
|
id: sourceLast.id,
|
|
31118
|
-
snapshotAt:
|
|
31119
|
-
snapshotRevision:
|
|
31120
|
-
updatedAfter:
|
|
31121
|
-
filterHash:
|
|
31122
|
-
...
|
|
31123
|
-
}) : null :
|
|
31298
|
+
snapshotAt: page2.snapshotAt,
|
|
31299
|
+
snapshotRevision: page2.snapshotRevision,
|
|
31300
|
+
updatedAfter: page2.updatedAfter,
|
|
31301
|
+
filterHash: page2.filterHash,
|
|
31302
|
+
...page2.originSiteId ? { originSiteId: page2.originSiteId } : {}
|
|
31303
|
+
}) : null : page2.nextCursor ? encodeSessionDiscoveryCursor(page2.nextCursor) : null;
|
|
31124
31304
|
const result2 = {
|
|
31125
31305
|
sessions: kept,
|
|
31126
|
-
total:
|
|
31127
|
-
hasMore:
|
|
31306
|
+
total: page2.total,
|
|
31307
|
+
hasMore: page2.hasMore || droppedForByteCap,
|
|
31128
31308
|
nextCursor,
|
|
31129
|
-
orderBy:
|
|
31130
|
-
snapshotAt:
|
|
31131
|
-
snapshotRevision:
|
|
31132
|
-
updatedAfter:
|
|
31133
|
-
updatedThrough:
|
|
31309
|
+
orderBy: page2.orderBy,
|
|
31310
|
+
snapshotAt: page2.snapshotAt,
|
|
31311
|
+
snapshotRevision: page2.snapshotRevision,
|
|
31312
|
+
updatedAfter: page2.updatedAfter,
|
|
31313
|
+
updatedThrough: page2.updatedThrough,
|
|
31134
31314
|
...includeLastMessage ? {
|
|
31135
31315
|
latestMessagePreviewBudget: {
|
|
31136
31316
|
bytes: previewBytes,
|
|
@@ -67405,7 +67585,8 @@ function registerDocumentRoutes(app, deps) {
|
|
|
67405
67585
|
deps,
|
|
67406
67586
|
await requireAccessGrantAuthorization8(c, deps, workspaceId, "documents:search"),
|
|
67407
67587
|
"documents:search"
|
|
67408
|
-
)
|
|
67588
|
+
),
|
|
67589
|
+
settings: deps.settings
|
|
67409
67590
|
}
|
|
67410
67591
|
);
|
|
67411
67592
|
await server.connect(transport);
|
|
@@ -67492,6 +67673,8 @@ import {
|
|
|
67492
67673
|
prepareKnowledgeFile as prepareKnowledgeFile2,
|
|
67493
67674
|
prepareKnowledgeSave as prepareKnowledgeSave2,
|
|
67494
67675
|
searchKnowledgeEntries as searchKnowledgeEntries3,
|
|
67676
|
+
KnowledgeVectorFundingError,
|
|
67677
|
+
KnowledgeVectorQueryRejectedError,
|
|
67495
67678
|
hasPermission as hasPermission13,
|
|
67496
67679
|
knowledgeContextForAccess as knowledgeContextForAccess2,
|
|
67497
67680
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization9,
|
|
@@ -67531,6 +67714,18 @@ var WriteSettings = ReadSettings.extend({
|
|
|
67531
67714
|
var Id = z22.uuid();
|
|
67532
67715
|
function knowledgeHttpError(error) {
|
|
67533
67716
|
if (error instanceof HTTPException42) throw error;
|
|
67717
|
+
if (error instanceof KnowledgeVectorFundingError)
|
|
67718
|
+
throw new ApiHttpError(402, {
|
|
67719
|
+
code: "payment_required",
|
|
67720
|
+
message: error.message,
|
|
67721
|
+
details: { code: error.code, keywordAvailable: true }
|
|
67722
|
+
});
|
|
67723
|
+
if (error instanceof KnowledgeVectorQueryRejectedError)
|
|
67724
|
+
throw new ApiHttpError(error.code === "quota" ? 429 : 422, {
|
|
67725
|
+
code: error.code === "quota" ? "limit_exceeded" : "validation_failed",
|
|
67726
|
+
message: error.message,
|
|
67727
|
+
details: { code: error.code, keywordAvailable: true }
|
|
67728
|
+
});
|
|
67534
67729
|
if (error instanceof z22.ZodError)
|
|
67535
67730
|
throw new HTTPException42(422, {
|
|
67536
67731
|
message: error.issues[0]?.message ?? "Invalid Knowledge request"
|
|
@@ -67662,7 +67857,9 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67662
67857
|
deps.db,
|
|
67663
67858
|
context,
|
|
67664
67859
|
KnowledgeSavePreparationRequest2.parse(await c.req.json()),
|
|
67665
|
-
() => deps.getDocumentServices().embedder
|
|
67860
|
+
() => deps.getDocumentServices().embedder,
|
|
67861
|
+
void 0,
|
|
67862
|
+
deps.settings
|
|
67666
67863
|
)
|
|
67667
67864
|
);
|
|
67668
67865
|
})
|
|
@@ -67677,7 +67874,8 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67677
67874
|
deps.db,
|
|
67678
67875
|
context,
|
|
67679
67876
|
KnowledgeEntryListRequest3.parse(await c.req.json()),
|
|
67680
|
-
() => deps.getDocumentServices().embedder
|
|
67877
|
+
() => deps.getDocumentServices().embedder,
|
|
67878
|
+
deps.settings
|
|
67681
67879
|
)
|
|
67682
67880
|
)
|
|
67683
67881
|
)
|
|
@@ -67724,7 +67922,8 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67724
67922
|
...query,
|
|
67725
67923
|
...query.limit ? { limit: Number(query.limit) } : {}
|
|
67726
67924
|
}),
|
|
67727
|
-
() => deps.getDocumentServices().embedder
|
|
67925
|
+
() => deps.getDocumentServices().embedder,
|
|
67926
|
+
deps.settings
|
|
67728
67927
|
)
|
|
67729
67928
|
);
|
|
67730
67929
|
})
|
|
@@ -70394,7 +70593,8 @@ import { randomUUID as randomUUID7 } from "crypto";
|
|
|
70394
70593
|
import {
|
|
70395
70594
|
environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes5,
|
|
70396
70595
|
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret3,
|
|
70397
|
-
resolveStreamTokenSecret as resolveStreamTokenSecret2
|
|
70596
|
+
resolveStreamTokenSecret as resolveStreamTokenSecret2,
|
|
70597
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond3
|
|
70398
70598
|
} from "@opengeni/config";
|
|
70399
70599
|
import {
|
|
70400
70600
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX,
|
|
@@ -70412,6 +70612,8 @@ import {
|
|
|
70412
70612
|
BrowserDownloadSaveRequest,
|
|
70413
70613
|
BrowserDownloadSaveResponse,
|
|
70414
70614
|
BrowserDownloadListResponse,
|
|
70615
|
+
BrowserDomReadRequest,
|
|
70616
|
+
BrowserDomReadResponse,
|
|
70415
70617
|
BrowserExternalAuthCommand,
|
|
70416
70618
|
BrowserOpenTargetRequest,
|
|
70417
70619
|
BrowserObservation,
|
|
@@ -70423,6 +70625,7 @@ import {
|
|
|
70423
70625
|
BrowserSessionListResponse,
|
|
70424
70626
|
BrowserSessionMutationResponse,
|
|
70425
70627
|
BrowserTargetListResponse,
|
|
70628
|
+
BrowserTargetState,
|
|
70426
70629
|
CreateBrowserSessionRequest,
|
|
70427
70630
|
ExternalAuthInteractiveRequest,
|
|
70428
70631
|
ExternalAuthInteractiveResponse,
|
|
@@ -70454,6 +70657,7 @@ import {
|
|
|
70454
70657
|
BrowserSessionNotFoundError,
|
|
70455
70658
|
BrowserSessionOperationConflictError,
|
|
70456
70659
|
BrowserSessionStateError as BrowserSessionStateError2,
|
|
70660
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError3,
|
|
70457
70661
|
completeBrowserSessionEnd,
|
|
70458
70662
|
completeExternalAuth,
|
|
70459
70663
|
completeBrowserDownloadSave,
|
|
@@ -70467,6 +70671,8 @@ import {
|
|
|
70467
70671
|
dispatchExternalAuth,
|
|
70468
70672
|
dispatchProtectedAuthFill,
|
|
70469
70673
|
failBrowserSessionOperation,
|
|
70674
|
+
failPreparedBrowserSessionEnd,
|
|
70675
|
+
failPreparedBrowserSessionSuspend,
|
|
70470
70676
|
failBrowserSessionResume,
|
|
70471
70677
|
failBrowserSessionResumePreparation,
|
|
70472
70678
|
failBrowserSessionSuspension,
|
|
@@ -72355,6 +72561,68 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72355
72561
|
return context.json(result);
|
|
72356
72562
|
}
|
|
72357
72563
|
);
|
|
72564
|
+
app.get(
|
|
72565
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/state",
|
|
72566
|
+
async (context) => {
|
|
72567
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72568
|
+
context,
|
|
72569
|
+
"sessions:read"
|
|
72570
|
+
);
|
|
72571
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72572
|
+
const result = await withActiveBrowserController(
|
|
72573
|
+
context,
|
|
72574
|
+
grant,
|
|
72575
|
+
workspaceId,
|
|
72576
|
+
browserSessionId,
|
|
72577
|
+
"session.read",
|
|
72578
|
+
"browser.read",
|
|
72579
|
+
async ({ sessionClient }) => await sessionClient.targetState(targetId)
|
|
72580
|
+
);
|
|
72581
|
+
return context.json(BrowserTargetState.parse(result));
|
|
72582
|
+
}
|
|
72583
|
+
);
|
|
72584
|
+
app.post(
|
|
72585
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/dom-read",
|
|
72586
|
+
async (context) => {
|
|
72587
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72588
|
+
context,
|
|
72589
|
+
"sessions:read"
|
|
72590
|
+
);
|
|
72591
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72592
|
+
const request = await parseJsonBody2(context, BrowserDomReadRequest);
|
|
72593
|
+
const result = await withActiveBrowserController(
|
|
72594
|
+
context,
|
|
72595
|
+
grant,
|
|
72596
|
+
workspaceId,
|
|
72597
|
+
browserSessionId,
|
|
72598
|
+
"session.read",
|
|
72599
|
+
"browser.read",
|
|
72600
|
+
async ({ sessionClient }) => await sessionClient.readDom(targetId, request)
|
|
72601
|
+
);
|
|
72602
|
+
return context.json(BrowserDomReadResponse.parse(result));
|
|
72603
|
+
}
|
|
72604
|
+
);
|
|
72605
|
+
app.get(
|
|
72606
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/screenshot",
|
|
72607
|
+
async (context) => {
|
|
72608
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72609
|
+
context,
|
|
72610
|
+
"sessions:read"
|
|
72611
|
+
);
|
|
72612
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72613
|
+
const captureOptions = parseBrowserScreenshotOptions(new URL(context.req.url).searchParams);
|
|
72614
|
+
const frame = await withActiveBrowserController(
|
|
72615
|
+
context,
|
|
72616
|
+
grant,
|
|
72617
|
+
workspaceId,
|
|
72618
|
+
browserSessionId,
|
|
72619
|
+
"session.read",
|
|
72620
|
+
"browser.read",
|
|
72621
|
+
async ({ sessionClient }) => await sessionClient.capture(targetId, captureOptions)
|
|
72622
|
+
);
|
|
72623
|
+
return browserScreenshotResponse(frame);
|
|
72624
|
+
}
|
|
72625
|
+
);
|
|
72358
72626
|
app.post(
|
|
72359
72627
|
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/actions",
|
|
72360
72628
|
async (context) => {
|
|
@@ -73388,6 +73656,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73388
73656
|
const request = await parseJsonBody2(context, BrowserSessionLifecycleRequest);
|
|
73389
73657
|
const startedAtMs = performance.now();
|
|
73390
73658
|
const origin = requestOrigin(context, deps.settings);
|
|
73659
|
+
let preparedForDispatch = false;
|
|
73391
73660
|
try {
|
|
73392
73661
|
const before = await getBrowserSessionControlRecord(deps.db, {
|
|
73393
73662
|
accountId: grant.accountId,
|
|
@@ -73436,6 +73705,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73436
73705
|
observeLifecycleResult(deps.observability, startedAtMs, parsed2);
|
|
73437
73706
|
return context.json(parsed2, 200);
|
|
73438
73707
|
}
|
|
73708
|
+
preparedForDispatch = true;
|
|
73439
73709
|
const record6 = await getBrowserSessionControlRecord(deps.db, {
|
|
73440
73710
|
accountId: grant.accountId,
|
|
73441
73711
|
workspaceId,
|
|
@@ -73594,6 +73864,15 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73594
73864
|
observeLifecycleResult(deps.observability, startedAtMs, parsed);
|
|
73595
73865
|
return context.json(parsed, 200);
|
|
73596
73866
|
} catch (error) {
|
|
73867
|
+
if (preparedForDispatch) {
|
|
73868
|
+
await failPreparedBrowserSessionSuspend(deps.db, {
|
|
73869
|
+
accountId: grant.accountId,
|
|
73870
|
+
workspaceId,
|
|
73871
|
+
browserSessionId,
|
|
73872
|
+
operationId: request.operationId,
|
|
73873
|
+
error: interactionFailure(error)
|
|
73874
|
+
});
|
|
73875
|
+
}
|
|
73597
73876
|
throw browserRouteError(error);
|
|
73598
73877
|
}
|
|
73599
73878
|
}
|
|
@@ -73844,6 +74123,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73844
74123
|
const request = await parseJsonBody2(context, BrowserSessionLifecycleRequest);
|
|
73845
74124
|
const startedAtMs = performance.now();
|
|
73846
74125
|
const origin = requestOrigin(context, deps.settings);
|
|
74126
|
+
let endPreparation = null;
|
|
73847
74127
|
try {
|
|
73848
74128
|
const before = await getBrowserSessionControlRecord(deps.db, {
|
|
73849
74129
|
accountId: grant.accountId,
|
|
@@ -73857,7 +74137,10 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73857
74137
|
workspaceId,
|
|
73858
74138
|
browserSessionId,
|
|
73859
74139
|
operationId: request.operationId,
|
|
73860
|
-
actorSubjectId: grant.subjectId
|
|
74140
|
+
actorSubjectId: grant.subjectId,
|
|
74141
|
+
expectedLifecycle: before.session.lifecycle,
|
|
74142
|
+
expectedFailureCode: before.session.failureCode,
|
|
74143
|
+
expectedControllerGeneration: before.session.controller?.controllerGeneration ?? null
|
|
73861
74144
|
});
|
|
73862
74145
|
if (isTerminalOperation(prepared.operation.state)) {
|
|
73863
74146
|
if (prepared.operation.state === "completed") {
|
|
@@ -73873,6 +74156,13 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73873
74156
|
observeLifecycleResult(deps.observability, startedAtMs, parsed2);
|
|
73874
74157
|
return context.json(parsed2, 200);
|
|
73875
74158
|
}
|
|
74159
|
+
if (before.session.lifecycle !== "ending") {
|
|
74160
|
+
endPreparation = {
|
|
74161
|
+
restoreLifecycle: before.session.lifecycle,
|
|
74162
|
+
restoreFailureCode: before.session.failureCode,
|
|
74163
|
+
expectedControllerGeneration: before.session.controller?.controllerGeneration ?? null
|
|
74164
|
+
};
|
|
74165
|
+
}
|
|
73876
74166
|
const record6 = await getBrowserSessionControlRecord(deps.db, {
|
|
73877
74167
|
accountId: grant.accountId,
|
|
73878
74168
|
workspaceId,
|
|
@@ -73962,6 +74252,16 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73962
74252
|
observeLifecycleResult(deps.observability, startedAtMs, parsed);
|
|
73963
74253
|
return context.json(parsed, 200);
|
|
73964
74254
|
} catch (error) {
|
|
74255
|
+
if (endPreparation) {
|
|
74256
|
+
await failPreparedBrowserSessionEnd(deps.db, {
|
|
74257
|
+
accountId: grant.accountId,
|
|
74258
|
+
workspaceId,
|
|
74259
|
+
browserSessionId,
|
|
74260
|
+
operationId: request.operationId,
|
|
74261
|
+
...endPreparation,
|
|
74262
|
+
error: interactionFailure(error)
|
|
74263
|
+
});
|
|
74264
|
+
}
|
|
73965
74265
|
throw browserRouteError(error);
|
|
73966
74266
|
}
|
|
73967
74267
|
}
|
|
@@ -74082,6 +74382,11 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
74082
74382
|
const resolved = await handle.routingSession.prime();
|
|
74083
74383
|
if (expectedPlacement?.kind === "connected_machine") {
|
|
74084
74384
|
if (resolved.kind !== "selfhosted" || resolved.sandboxId !== expectedPlacement.sandboxId) {
|
|
74385
|
+
if (operation === "browser.create") {
|
|
74386
|
+
throw new HTTPException51(422, {
|
|
74387
|
+
message: "The requested Connected Machine is not this session's current placement. Move the session to that machine before creating an interaction resource."
|
|
74388
|
+
});
|
|
74389
|
+
}
|
|
74085
74390
|
return await throwBrowserSourcePlacementChanged(
|
|
74086
74391
|
grant,
|
|
74087
74392
|
sourceSession.id,
|
|
@@ -74797,6 +75102,10 @@ async function ensureInteractionHolder(deps, grant, sourceSession, browserSessio
|
|
|
74797
75102
|
holderId: interactionHolderId(browserSessionId),
|
|
74798
75103
|
subjectId: sourceSession.id,
|
|
74799
75104
|
backend: placement.lease.backend,
|
|
75105
|
+
warmBilling: {
|
|
75106
|
+
mode: deps.settings.sandboxWarmBillingMode,
|
|
75107
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond3(deps.settings, placement.lease.backend)
|
|
75108
|
+
},
|
|
74800
75109
|
os: placement.lease.os,
|
|
74801
75110
|
image: sandboxRuntime.image,
|
|
74802
75111
|
rigVersionId: sourceSession.rigVersionId,
|
|
@@ -74994,6 +75303,7 @@ async function settleBrowserSessionSuspensionCaptureFailure(deps, input, error)
|
|
|
74994
75303
|
return await failBrowserSessionSuspension(deps.db, {
|
|
74995
75304
|
...input,
|
|
74996
75305
|
...outcomeUnknown ? { state: "outcome_unknown" } : {},
|
|
75306
|
+
missingControllerSession: error.status === 404 && isMissingBrowserControllerSession(error),
|
|
74997
75307
|
error: error.error
|
|
74998
75308
|
});
|
|
74999
75309
|
}
|
|
@@ -75086,6 +75396,41 @@ function optionalBoundedInteger(value, minimum, maximum) {
|
|
|
75086
75396
|
}
|
|
75087
75397
|
return parsed;
|
|
75088
75398
|
}
|
|
75399
|
+
function parseBrowserScreenshotOptions(query) {
|
|
75400
|
+
for (const key of ["fullPage", "format", "quality"]) {
|
|
75401
|
+
if (query.getAll(key).length > 1) {
|
|
75402
|
+
throw new HTTPException51(400, { message: `duplicate browser screenshot ${key}` });
|
|
75403
|
+
}
|
|
75404
|
+
}
|
|
75405
|
+
const fullPage = query.get("fullPage");
|
|
75406
|
+
if (fullPage !== null && fullPage !== "true" && fullPage !== "false") {
|
|
75407
|
+
throw new HTTPException51(400, { message: "invalid browser screenshot fullPage" });
|
|
75408
|
+
}
|
|
75409
|
+
const format = query.get("format");
|
|
75410
|
+
if (format !== null && format !== "jpeg" && format !== "png") {
|
|
75411
|
+
throw new HTTPException51(400, { message: "invalid browser screenshot format" });
|
|
75412
|
+
}
|
|
75413
|
+
const quality = query.get("quality");
|
|
75414
|
+
const parsedQuality = quality === null ? null : optionalBoundedInteger(quality, 1, 100);
|
|
75415
|
+
if (quality !== null && parsedQuality === null) {
|
|
75416
|
+
throw new HTTPException51(400, { message: "invalid browser screenshot quality" });
|
|
75417
|
+
}
|
|
75418
|
+
return {
|
|
75419
|
+
...fullPage === null ? {} : { fullPage: fullPage === "true" },
|
|
75420
|
+
...format === null ? {} : { format },
|
|
75421
|
+
...parsedQuality === null ? {} : { quality: parsedQuality }
|
|
75422
|
+
};
|
|
75423
|
+
}
|
|
75424
|
+
function browserScreenshotResponse(frame) {
|
|
75425
|
+
return new Response(Uint8Array.from(frame.data).buffer, {
|
|
75426
|
+
status: 200,
|
|
75427
|
+
headers: {
|
|
75428
|
+
"cache-control": "no-store",
|
|
75429
|
+
"content-type": frame.mediaType,
|
|
75430
|
+
"x-opengeni-browser-frame": frame.metadataHeader
|
|
75431
|
+
}
|
|
75432
|
+
});
|
|
75433
|
+
}
|
|
75089
75434
|
function isUuid(value) {
|
|
75090
75435
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value);
|
|
75091
75436
|
}
|
|
@@ -75480,6 +75825,8 @@ function browserRouteError(error) {
|
|
|
75480
75825
|
const connectedMachineError = interactionControlApiError(error, "browser");
|
|
75481
75826
|
if (connectedMachineError) return connectedMachineError;
|
|
75482
75827
|
if (error instanceof HTTPException51) return error;
|
|
75828
|
+
if (error instanceof SandboxPaidComputeAdmissionError3)
|
|
75829
|
+
return new HTTPException51(402, { message: error.message, cause: error });
|
|
75483
75830
|
if (error instanceof BrowserSessionNotFoundError) {
|
|
75484
75831
|
return new HTTPException51(404, { message: error.message, cause: error });
|
|
75485
75832
|
}
|
|
@@ -75533,7 +75880,11 @@ function isAbort(error) {
|
|
|
75533
75880
|
|
|
75534
75881
|
// src/routes/computer-sessions.ts
|
|
75535
75882
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
75536
|
-
import {
|
|
75883
|
+
import {
|
|
75884
|
+
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret4,
|
|
75885
|
+
resolveStreamTokenSecret as resolveStreamTokenSecret3,
|
|
75886
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond4
|
|
75887
|
+
} from "@opengeni/config";
|
|
75537
75888
|
import {
|
|
75538
75889
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX as BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX2,
|
|
75539
75890
|
BROWSER_CONTROL_PORT as BROWSER_CONTROL_PORT2,
|
|
@@ -75560,6 +75911,7 @@ import {
|
|
|
75560
75911
|
ComputerSessionNotFoundError,
|
|
75561
75912
|
ComputerSessionOperationConflictError,
|
|
75562
75913
|
ComputerSessionStateError,
|
|
75914
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError4,
|
|
75563
75915
|
dispatchComputerSessionOperation,
|
|
75564
75916
|
failComputerSessionOperation,
|
|
75565
75917
|
findComputerSessionControlRecordByOperation,
|
|
@@ -76447,6 +76799,11 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76447
76799
|
}
|
|
76448
76800
|
if (expectedPlacement?.kind === "connected_machine") {
|
|
76449
76801
|
if (resolved.kind !== "selfhosted" || resolved.sandboxId !== expectedPlacement.sandboxId) {
|
|
76802
|
+
if (operation === "computer.create") {
|
|
76803
|
+
throw new HTTPException52(422, {
|
|
76804
|
+
message: "The requested Connected Machine is not this session's current placement. Move the session to that machine before creating an interaction resource."
|
|
76805
|
+
});
|
|
76806
|
+
}
|
|
76450
76807
|
return await throwComputerSourcePlacementChanged(
|
|
76451
76808
|
grant,
|
|
76452
76809
|
sourceSession.id,
|
|
@@ -76733,6 +77090,10 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76733
77090
|
holderId: interactionHolderId2(computerSessionId),
|
|
76734
77091
|
subjectId: sourceSession.id,
|
|
76735
77092
|
backend: placement.lease.backend,
|
|
77093
|
+
warmBilling: {
|
|
77094
|
+
mode: deps.settings.sandboxWarmBillingMode,
|
|
77095
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond4(deps.settings, placement.lease.backend)
|
|
77096
|
+
},
|
|
76736
77097
|
os: placement.lease.os,
|
|
76737
77098
|
image: sandboxRuntime.image,
|
|
76738
77099
|
rigVersionId: sourceSession.rigVersionId,
|
|
@@ -77055,6 +77416,8 @@ function computerRouteError(error) {
|
|
|
77055
77416
|
const connectedMachineError = interactionControlApiError(error, "computer");
|
|
77056
77417
|
if (connectedMachineError) return connectedMachineError;
|
|
77057
77418
|
if (error instanceof HTTPException52) return error;
|
|
77419
|
+
if (error instanceof SandboxPaidComputeAdmissionError4)
|
|
77420
|
+
return new HTTPException52(402, { message: error.message, cause: error });
|
|
77058
77421
|
if (error instanceof ComputerSessionNotFoundError) {
|
|
77059
77422
|
return new HTTPException52(404, { message: error.message, cause: error });
|
|
77060
77423
|
}
|
|
@@ -77203,6 +77566,92 @@ async function integrationCommitGrant(authorization, permissions, request) {
|
|
|
77203
77566
|
};
|
|
77204
77567
|
}
|
|
77205
77568
|
|
|
77569
|
+
// src/routes/github-browser-pages.ts
|
|
77570
|
+
var pageStyle = `
|
|
77571
|
+
:root{color-scheme:dark;--bg:oklch(.155 .012 260);--surface:oklch(.19 .014 260);--raised:oklch(.225 .015 260);--border:oklch(.3 .014 260);--border-strong:oklch(.42 .016 260);--fg:oklch(.955 .005 260);--muted:oklch(.73 .012 260);--blue:oklch(.54 .18 255);--blue-light:oklch(.72 .15 255)}
|
|
77572
|
+
*{box-sizing:border-box}
|
|
77573
|
+
html{min-height:100%;background:var(--bg)}
|
|
77574
|
+
body{margin:0;min-height:100vh;min-height:100dvh;color:var(--fg);background:var(--bg);font-family:"Inter Variable",Inter,ui-sans-serif,system-ui,sans-serif;font-feature-settings:"cv11","ss01","ss03";-webkit-font-smoothing:antialiased}
|
|
77575
|
+
.shell{width:min(100% - 48px,700px);margin:0 auto}
|
|
77576
|
+
header{height:84px;display:flex;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--border)}
|
|
77577
|
+
.brand{font-size:16px;font-weight:670;letter-spacing:-.045em;color:var(--fg);text-decoration:none}
|
|
77578
|
+
.context{font-size:12px;color:var(--muted)}
|
|
77579
|
+
main{padding:clamp(48px,10vh,100px) 0 96px}
|
|
77580
|
+
h1{margin:0 0 14px;font-size:clamp(27px,4vw,36px);font-weight:640;letter-spacing:-.05em;line-height:1.17}
|
|
77581
|
+
p{margin:0;color:var(--muted);font-size:14px;line-height:1.65;max-width:59ch}
|
|
77582
|
+
.intro{margin-bottom:32px}
|
|
77583
|
+
.options{display:grid;gap:10px;margin:0 0 24px;padding:0;border:0;max-height:min(390px,52vh);overflow:auto}
|
|
77584
|
+
.option{display:flex;gap:14px;align-items:center;min-height:70px;padding:14px 16px;border:1px solid var(--border);border-radius:10px;background:var(--surface);cursor:pointer;transition:background .15s,border-color .15s}
|
|
77585
|
+
.option:hover{background:var(--raised)}
|
|
77586
|
+
.option:has(input:checked){border-color:var(--blue-light);background:var(--raised)}
|
|
77587
|
+
.option:has(input:focus-visible){outline:2px solid var(--blue-light);outline-offset:3px}
|
|
77588
|
+
.option input{margin:0;flex:none;width:17px;height:17px;accent-color:var(--blue-light)}
|
|
77589
|
+
.option-text{min-width:0;display:grid;gap:3px}
|
|
77590
|
+
.option strong{overflow-wrap:anywhere;font-size:14px;font-weight:600}
|
|
77591
|
+
.option small{font-size:12px;color:var(--muted)}
|
|
77592
|
+
.actions{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:24px}
|
|
77593
|
+
.button{display:inline-flex;min-height:42px;align-items:center;justify-content:center;padding:0 17px;border:1px solid var(--blue);border-radius:8px;background:var(--blue);color:#fff;font-family:inherit;font-size:13px;font-weight:600;text-decoration:none;cursor:pointer}
|
|
77594
|
+
.button:hover{background:oklch(.6 .18 255)}
|
|
77595
|
+
.button:disabled{cursor:wait;opacity:.7}
|
|
77596
|
+
.secondary{border-color:var(--border);background:transparent;color:var(--fg)}
|
|
77597
|
+
.secondary:hover{background:var(--raised)}
|
|
77598
|
+
:is(button,a):focus-visible{outline:2px solid var(--blue-light);outline-offset:3px}
|
|
77599
|
+
.note{margin-top:30px;padding-top:20px;border-top:1px solid var(--border);font-size:12px}
|
|
77600
|
+
.env-header{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:36px}
|
|
77601
|
+
h2{margin:0;font-size:14px;font-weight:600}
|
|
77602
|
+
pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:380px;overflow:auto;padding:18px;border:1px solid var(--border);border-radius:10px;background:var(--surface);font:12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
77603
|
+
@media(max-width:480px){.shell{width:calc(100% - 32px)}header{height:70px}main{padding-top:56px}.actions{align-items:stretch;flex-direction:column}.actions form,.actions .button{width:100%}}
|
|
77604
|
+
@media(prefers-reduced-motion:reduce){.option{transition:none}}
|
|
77605
|
+
`;
|
|
77606
|
+
function page(title, content) {
|
|
77607
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${escapeHtml4(title)} \xB7 OpenGeni</title><style>${pageStyle}</style></head><body><div class="shell"><header><span class="brand">OpenGeni</span><span class="context">GitHub connection</span></header><main>${content}</main></div></body></html>`;
|
|
77608
|
+
}
|
|
77609
|
+
function githubInstallationChooserHtml(candidates, state, workspaceId, baseUrl) {
|
|
77610
|
+
const action = `${baseUrl}/v1/workspaces/${encodeURIComponent(workspaceId)}/github/installations/select`;
|
|
77611
|
+
const options = candidates.map(({ installation, authorityKind }, index) => {
|
|
77612
|
+
const account = escapeHtml4(
|
|
77613
|
+
installation.accountLogin ?? `installation ${installation.installationId}`
|
|
77614
|
+
);
|
|
77615
|
+
const label = authorityKind === "personal_owner" ? "Personal account" : "Organization owner";
|
|
77616
|
+
return `<label class="option"><input type="radio" name="installation_id" value="${installation.installationId}" required${candidates.length === 1 && index === 0 ? " checked" : ""}><span class="option-text"><strong>${account}</strong><small>${label}</small></span></label>`;
|
|
77617
|
+
}).join("");
|
|
77618
|
+
return page(
|
|
77619
|
+
"Choose a GitHub account",
|
|
77620
|
+
`<h1>Choose a GitHub account</h1><p class="intro">Connect an account where the OpenGeni GitHub App is already installed, or install it on another account.</p><form id="existing-account" method="get" action="${escapeHtml4(action)}"><input type="hidden" name="state" value="${escapeHtml4(state)}"><fieldset class="options" aria-label="Available GitHub accounts">${options}</fieldset></form><div class="actions"><button class="button" type="submit" form="existing-account">Connect selected account</button><form method="get" action="${escapeHtml4(action)}"><input type="hidden" name="state" value="${escapeHtml4(state)}"><input type="hidden" name="installation_id" value="new"><button class="button secondary" type="submit">Install on another account</button></form></div><p class="note">Only accounts GitHub has confirmed you own or manage appear here.</p>`
|
|
77621
|
+
);
|
|
77622
|
+
}
|
|
77623
|
+
function githubSetupSuccessHtml(account, returnUrl2) {
|
|
77624
|
+
return page(
|
|
77625
|
+
"GitHub connected",
|
|
77626
|
+
`<h1>GitHub connected</h1><p class="intro"><strong>${escapeHtml4(account)}</strong> is now available in this OpenGeni workspace. OpenGeni can access only the repositories allowed for this installation.</p><a class="button" href="${escapeHtml4(returnUrl2)}">Back to OpenGeni</a>`
|
|
77627
|
+
);
|
|
77628
|
+
}
|
|
77629
|
+
function githubSetupPendingHtml() {
|
|
77630
|
+
return page(
|
|
77631
|
+
"GitHub approval pending",
|
|
77632
|
+
`<h1>Waiting for an organization owner</h1><p>An owner needs to approve your GitHub App request before you can connect. OpenGeni has not created a workspace binding.</p>`
|
|
77633
|
+
);
|
|
77634
|
+
}
|
|
77635
|
+
function githubSuccessHtml(envLines) {
|
|
77636
|
+
const escaped = escapeHtml4(envLines.join("\n"));
|
|
77637
|
+
return page(
|
|
77638
|
+
"GitHub App created",
|
|
77639
|
+
`<h1>GitHub App created</h1><p>Add these values to .env, then restart API and worker.</p><div class="env-header"><h2>Environment variables</h2><button class="button secondary" id="copy-env" type="button">Copy env</button></div><pre id="env-lines">${escaped}</pre><script>(()=>{const button=document.getElementById("copy-env");const env=document.getElementById("env-lines");async function copyText(text){if(navigator.clipboard&&window.isSecureContext){await navigator.clipboard.writeText(text);return;}const area=document.createElement("textarea");area.value=text;area.setAttribute("readonly","");area.style.position="fixed";area.style.inset="-9999px";document.body.append(area);area.select();document.execCommand("copy");area.remove();}button?.addEventListener("click",async()=>{try{await copyText(env?.textContent||"");button.textContent="Copied";setTimeout(()=>button.textContent="Copy env",1600);}catch{button.textContent="Copy failed";setTimeout(()=>button.textContent="Copy env",2200);}});})();</script>`
|
|
77640
|
+
);
|
|
77641
|
+
}
|
|
77642
|
+
function escapeHtml4(value) {
|
|
77643
|
+
return value.replace(
|
|
77644
|
+
/[&<>"']/g,
|
|
77645
|
+
(char) => ({
|
|
77646
|
+
"&": "&",
|
|
77647
|
+
"<": "<",
|
|
77648
|
+
">": ">",
|
|
77649
|
+
'"': """,
|
|
77650
|
+
"'": "'"
|
|
77651
|
+
})[char] ?? char
|
|
77652
|
+
);
|
|
77653
|
+
}
|
|
77654
|
+
|
|
77206
77655
|
// src/routes/github.ts
|
|
77207
77656
|
var githubStateCookie = "opengeni_github_state";
|
|
77208
77657
|
var githubBindingStateMaxAgeSeconds = 10 * 60;
|
|
@@ -78006,28 +78455,6 @@ function requirePublicGitHubRepositoryVerificationPermission(grant) {
|
|
|
78006
78455
|
function isSecureRequest(c, deps) {
|
|
78007
78456
|
return deps.settings.publicBaseUrl?.startsWith("https://") || c.req.header("x-forwarded-proto") === "https" || new URL(c.req.url).protocol === "https:";
|
|
78008
78457
|
}
|
|
78009
|
-
function githubSuccessHtml(envLines) {
|
|
78010
|
-
const envText = envLines.join("\n");
|
|
78011
|
-
const escaped = escapeHtml4(envText);
|
|
78012
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Created</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(760px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0 0 18px;color:#d4d4d8}.env-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:22px 0 8px}.env-header h2{margin:0;font-size:13px;line-height:1.2;text-transform:uppercase;letter-spacing:.08em;color:#a1a1aa}pre{white-space:pre-wrap;word-break:break-word;max-height:380px;overflow:auto;background:#09090b;border:1px solid #27272a;border-radius:8px;padding:16px;font-size:13px;line-height:1.5}button{display:inline-flex;align-items:center;justify-content:center;min-height:36px;border-radius:6px;border:1px solid #3f3f46;padding:0 12px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;cursor:pointer}button:disabled{cursor:not-allowed;opacity:.7}</style></head><body><main><h1>GitHub App created</h1><p>Add these values to .env, then restart API and worker.</p><div class="env-header"><h2>Environment variables</h2><button id="copy-env" type="button">Copy env</button></div><pre id="env-lines">${escaped}</pre><script>(()=>{const button=document.getElementById("copy-env");const env=document.getElementById("env-lines");async function copyText(text){if(navigator.clipboard&&window.isSecureContext){await navigator.clipboard.writeText(text);return;}const area=document.createElement("textarea");area.value=text;area.setAttribute("readonly","");area.style.position="fixed";area.style.inset="-9999px";document.body.append(area);area.select();document.execCommand("copy");area.remove();}button?.addEventListener("click",async()=>{try{await copyText(env?.textContent||"");button.textContent="Copied";setTimeout(()=>button.textContent="Copy env",1600);}catch{button.textContent="Copy failed";setTimeout(()=>button.textContent="Copy env",2200);}});})();</script></main></body></html>`;
|
|
78013
|
-
}
|
|
78014
|
-
function githubSetupSuccessHtml(account, returnUrl2) {
|
|
78015
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Connected</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0 0 18px;color:#d4d4d8}.button{display:inline-flex;align-items:center;justify-content:center;min-height:36px;border-radius:6px;border:1px solid #3f3f46;padding:0 12px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;text-decoration:none}</style></head><body><main><h1>GitHub App connected</h1><p>${escapeHtml4(account)} is now available to this OpenGeni workspace through an explicit repository allowlist.</p><a class="button" href="${escapeHtml4(returnUrl2)}">Back to OpenGeni</a></main></body></html>`;
|
|
78016
|
-
}
|
|
78017
|
-
function githubInstallationChooserHtml(candidates, state, workspaceId, baseUrl) {
|
|
78018
|
-
const action = `${baseUrl}/v1/workspaces/${encodeURIComponent(workspaceId)}/github/installations/select`;
|
|
78019
|
-
const options = candidates.map(({ installation, authorityKind }, index) => {
|
|
78020
|
-
const account = escapeHtml4(
|
|
78021
|
-
installation.accountLogin ?? `installation ${installation.installationId}`
|
|
78022
|
-
);
|
|
78023
|
-
const label = authorityKind === "personal_owner" ? "Personal account" : "Organization owner";
|
|
78024
|
-
return `<label class="option"><input type="radio" name="installation_id" value="${installation.installationId}" required${candidates.length === 1 && index === 0 ? " checked" : ""}><span><strong>${account}</strong><small>${label}</small></span></label>`;
|
|
78025
|
-
}).join("");
|
|
78026
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Choose GitHub installation</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:12px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px}p{margin:0 0 18px;color:#d4d4d8}.options{display:grid;gap:8px;margin-bottom:18px}.option{display:flex;align-items:center;gap:12px;border:1px solid #3f3f46;border-radius:8px;padding:12px;cursor:pointer}.option span{display:grid;gap:2px}.option small{color:#a1a1aa}button{min-height:38px;border-radius:7px;border:1px solid #3f3f46;padding:0 14px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;cursor:pointer}.secondary{margin-left:8px;background:transparent;color:#f4f4f5}</style></head><body><main><h1>Choose a GitHub account</h1><p>These accounts already have the OpenGeni GitHub App installed and GitHub proved you are the personal owner or an active organization owner.</p><form method="get" action="${escapeHtml4(action)}"><input type="hidden" name="state" value="${escapeHtml4(state)}"><div class="options">${options}</div><button type="submit">Connect selected</button><button class="secondary" type="submit" name="installation_id" value="new" formnovalidate>Install on another account</button></form></main></body></html>`;
|
|
78027
|
-
}
|
|
78028
|
-
function githubSetupPendingHtml() {
|
|
78029
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Requested</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0;color:#d4d4d8}</style></head><body><main><h1>GitHub App request sent</h1><p>A GitHub organization owner must approve the installation. OpenGeni has not created a workspace binding.</p></main></body></html>`;
|
|
78030
|
-
}
|
|
78031
78458
|
function parsePositiveInteger(value) {
|
|
78032
78459
|
if (!value || !/^\d+$/.test(value)) {
|
|
78033
78460
|
return null;
|
|
@@ -78039,18 +78466,6 @@ function isFreshGitHubBindingState(payload) {
|
|
|
78039
78466
|
const age = Math.floor(Date.now() / 1e3) - payload.iat;
|
|
78040
78467
|
return age >= 0 && age < githubBindingStateMaxAgeSeconds;
|
|
78041
78468
|
}
|
|
78042
|
-
function escapeHtml4(value) {
|
|
78043
|
-
return value.replace(
|
|
78044
|
-
/[&<>"']/g,
|
|
78045
|
-
(char) => ({
|
|
78046
|
-
"&": "&",
|
|
78047
|
-
"<": "<",
|
|
78048
|
-
">": ">",
|
|
78049
|
-
'"': """,
|
|
78050
|
-
"'": "'"
|
|
78051
|
-
})[char] ?? char
|
|
78052
|
-
);
|
|
78053
|
-
}
|
|
78054
78469
|
function openGeniReturnUrl(settings, c, workspaceId, returnPath = null) {
|
|
78055
78470
|
const baseUrl = openGeniBaseUrl(settings, c) || new URL(c.req.url).origin;
|
|
78056
78471
|
const safeReturnPath4 = githubSessionReturnPath(returnPath, workspaceId);
|
|
@@ -78636,7 +79051,7 @@ function registerPersonalGitHubRoutes(app, deps) {
|
|
|
78636
79051
|
const query = ListPersonalGitHubRepositoriesQuery.parse(c.req.query());
|
|
78637
79052
|
try {
|
|
78638
79053
|
const selection = await loadRepositorySelectionState(deps, access.grant, connection);
|
|
78639
|
-
const
|
|
79054
|
+
const page2 = await listLivePersonalGitHubRepositories(deps, {
|
|
78640
79055
|
accountId: access.grant.accountId,
|
|
78641
79056
|
workspaceId,
|
|
78642
79057
|
subjectId: access.grant.subjectId,
|
|
@@ -78653,11 +79068,11 @@ function registerPersonalGitHubRoutes(app, deps) {
|
|
|
78653
79068
|
);
|
|
78654
79069
|
return c.json(
|
|
78655
79070
|
ListPersonalGitHubRepositoriesResponse.parse({
|
|
78656
|
-
repositories:
|
|
79071
|
+
repositories: page2.repositories.map((repository) => ({
|
|
78657
79072
|
...repository,
|
|
78658
79073
|
selectedAccess: selectedAccessById.get(repository.repositoryId) ?? null
|
|
78659
79074
|
})),
|
|
78660
|
-
nextCursor:
|
|
79075
|
+
nextCursor: page2.nextPage,
|
|
78661
79076
|
selection
|
|
78662
79077
|
})
|
|
78663
79078
|
);
|
|
@@ -79991,11 +80406,11 @@ async function sseSessionStream(db, bus, workspaceId, sessionId, after, signal,
|
|
|
79991
80406
|
if (targetSequence !== void 0 && lastSent >= targetSequence) return;
|
|
79992
80407
|
const previousLastSent = lastSent;
|
|
79993
80408
|
const limit = targetSequence === void 0 ? SESSION_REPLAY_PAGE_SIZE : Math.min(SESSION_REPLAY_PAGE_SIZE, targetSequence - lastSent);
|
|
79994
|
-
const
|
|
80409
|
+
const page2 = await listSessionEvents(db, workspaceId, sessionId, {
|
|
79995
80410
|
after: lastSent,
|
|
79996
80411
|
limit
|
|
79997
80412
|
});
|
|
79998
|
-
const eligible = targetSequence === void 0 ?
|
|
80413
|
+
const eligible = targetSequence === void 0 ? page2 : page2.filter((event) => event.sequence <= targetSequence);
|
|
79999
80414
|
if (eligible.length === 0) {
|
|
80000
80415
|
if (targetSequence === void 0) return;
|
|
80001
80416
|
throw new Error(
|
|
@@ -80105,16 +80520,16 @@ async function replaySessionEvents(loadPage, send, after, pageSize = SESSION_REP
|
|
|
80105
80520
|
let cursor = after;
|
|
80106
80521
|
while (true) {
|
|
80107
80522
|
const previousCursor = cursor;
|
|
80108
|
-
const
|
|
80109
|
-
if (
|
|
80523
|
+
const page2 = await loadPage(cursor, pageSize);
|
|
80524
|
+
if (page2.length === 0) {
|
|
80110
80525
|
return;
|
|
80111
80526
|
}
|
|
80112
|
-
for (const event of
|
|
80527
|
+
for (const event of page2.sort((a, b) => a.sequence - b.sequence)) {
|
|
80113
80528
|
if (event.sequence <= cursor) continue;
|
|
80114
80529
|
await send(event);
|
|
80115
80530
|
cursor = event.sequence;
|
|
80116
80531
|
}
|
|
80117
|
-
if (
|
|
80532
|
+
if (page2.length < pageSize) {
|
|
80118
80533
|
return;
|
|
80119
80534
|
}
|
|
80120
80535
|
if (cursor === previousCursor) {
|
|
@@ -80506,14 +80921,14 @@ async function replayWorkspaceControlEvents(loadPage, send, after, pageSize) {
|
|
|
80506
80921
|
let cursor = after;
|
|
80507
80922
|
while (true) {
|
|
80508
80923
|
const previousCursor = cursor;
|
|
80509
|
-
const
|
|
80510
|
-
if (
|
|
80511
|
-
for (const event of
|
|
80924
|
+
const page2 = await loadPage(cursor, pageSize);
|
|
80925
|
+
if (page2.length === 0) return;
|
|
80926
|
+
for (const event of page2.sort((a, b) => a.sequence - b.sequence)) {
|
|
80512
80927
|
if (event.sequence <= cursor) continue;
|
|
80513
80928
|
await send(event);
|
|
80514
80929
|
cursor = event.sequence;
|
|
80515
80930
|
}
|
|
80516
|
-
if (
|
|
80931
|
+
if (page2.length < pageSize) return;
|
|
80517
80932
|
if (cursor === previousCursor) {
|
|
80518
80933
|
throw new Error(
|
|
80519
80934
|
`Workspace control replay made no progress after sequence ${cursor}; refusing to repeat a full stale page`
|
|
@@ -84605,10 +85020,10 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
84605
85020
|
...query.data.sessionId ? { sessionId: query.data.sessionId } : {}
|
|
84606
85021
|
}
|
|
84607
85022
|
);
|
|
84608
|
-
const
|
|
84609
|
-
const last =
|
|
85023
|
+
const page2 = rows2.slice(0, query.data.limit);
|
|
85024
|
+
const last = page2.at(-1);
|
|
84610
85025
|
return c.json({
|
|
84611
|
-
skills:
|
|
85026
|
+
skills: page2.map(({ files: _files, ...summary }) => summary),
|
|
84612
85027
|
nextCursor: rows2.length > query.data.limit && last ? Buffer.from(JSON.stringify({ stableKey: last.stableKey, id: last.id })).toString(
|
|
84613
85028
|
"base64url"
|
|
84614
85029
|
) : null
|
|
@@ -85665,6 +86080,8 @@ function registerScheduledTaskRoutes(app, deps) {
|
|
|
85665
86080
|
// src/routes/sessions.ts
|
|
85666
86081
|
import { getRetainedProviderCommand } from "@opengeni/db/retained-provider-commands";
|
|
85667
86082
|
import { searchSessionMessagesForSubject, SessionMessageSearchCursorError } from "@opengeni/db";
|
|
86083
|
+
import { listSessionEventSlices } from "@opengeni/db/session-event-slices";
|
|
86084
|
+
import * as sessionPreviewSchema from "@opengeni/db/schema";
|
|
85668
86085
|
import { SessionMessageSearchRequest } from "@opengeni/contracts";
|
|
85669
86086
|
import { scheduledSessionIds } from "@opengeni/db";
|
|
85670
86087
|
import { withSiteSessionOrigin as withSiteSessionOrigin2 } from "@opengeni/core";
|
|
@@ -87260,9 +87677,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
87260
87677
|
}
|
|
87261
87678
|
const pageView = c.req.query("view") === "page";
|
|
87262
87679
|
const query = sessionListQuery(c.req.query(), pageView);
|
|
87263
|
-
let
|
|
87680
|
+
let page2;
|
|
87264
87681
|
try {
|
|
87265
|
-
|
|
87682
|
+
page2 = await listSessionsForSubject(db, workspaceId, {
|
|
87266
87683
|
subjectId: grant.subjectId,
|
|
87267
87684
|
limit: boundedLimit(query.limit),
|
|
87268
87685
|
materializeSnapshot: pageView,
|
|
@@ -87299,17 +87716,17 @@ function registerSessionRoutes(app, deps) {
|
|
|
87299
87716
|
}
|
|
87300
87717
|
throw error;
|
|
87301
87718
|
}
|
|
87302
|
-
c.header("x-opengeni-pinned-truncated",
|
|
87719
|
+
c.header("x-opengeni-pinned-truncated", page2.pinnedTruncated === true ? "true" : "false");
|
|
87303
87720
|
const policy = await loadEffectivePolicyContext(deps, workspaceId, grant.subjectId);
|
|
87304
87721
|
const commandActivity = await backgroundCommandActivityForSessions(db, {
|
|
87305
87722
|
accountId: grant.accountId,
|
|
87306
87723
|
workspaceId,
|
|
87307
|
-
sessionIds: [...
|
|
87724
|
+
sessionIds: [...page2.pinned, ...page2.sessions].map((session) => session.id)
|
|
87308
87725
|
});
|
|
87309
87726
|
const scheduleTargets = hasPermission19(grant.permissions, "scheduled_tasks:run") && hasPermission19(grant.permissions, "sessions:control") ? await scheduledSessionIds(
|
|
87310
87727
|
db,
|
|
87311
87728
|
workspaceId,
|
|
87312
|
-
[...
|
|
87729
|
+
[...page2.pinned, ...page2.sessions].map((session) => session.id)
|
|
87313
87730
|
) : /* @__PURE__ */ new Set();
|
|
87314
87731
|
const decorate = (session) => {
|
|
87315
87732
|
const activity = commandActivity.get(session.id);
|
|
@@ -87325,14 +87742,14 @@ function registerSessionRoutes(app, deps) {
|
|
|
87325
87742
|
};
|
|
87326
87743
|
if (pageView) {
|
|
87327
87744
|
return c.json({
|
|
87328
|
-
...
|
|
87745
|
+
...page2,
|
|
87329
87746
|
...query.hasPageFilters ? { filtersApplied: true } : {},
|
|
87330
87747
|
...query.originSiteId ? { originSiteId: query.originSiteId } : {},
|
|
87331
|
-
pinned:
|
|
87332
|
-
sessions:
|
|
87748
|
+
pinned: page2.pinned.map(decorate),
|
|
87749
|
+
sessions: page2.sessions.map(decorate)
|
|
87333
87750
|
});
|
|
87334
87751
|
}
|
|
87335
|
-
return c.json([...
|
|
87752
|
+
return c.json([...page2.pinned, ...page2.sessions].map(decorate));
|
|
87336
87753
|
});
|
|
87337
87754
|
app.get("/v1/workspaces/:workspaceId/agent-topology", async (c) => {
|
|
87338
87755
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -87365,7 +87782,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
87365
87782
|
}
|
|
87366
87783
|
try {
|
|
87367
87784
|
const orderBy = query.query || query.subject ? "relevance" : "updatedAt";
|
|
87368
|
-
const
|
|
87785
|
+
const page2 = await listSessionDiscoverySummaries2(db, workspaceId, {
|
|
87369
87786
|
limit: query.limit,
|
|
87370
87787
|
orderBy,
|
|
87371
87788
|
subjectId: grant.subjectId,
|
|
@@ -87384,11 +87801,11 @@ function registerSessionRoutes(app, deps) {
|
|
|
87384
87801
|
const ancestorPaths = query.query || query.subject ? await listSessionDiscoveryAncestorPaths(
|
|
87385
87802
|
db,
|
|
87386
87803
|
workspaceId,
|
|
87387
|
-
|
|
87804
|
+
page2.sessions.map((session) => session.id),
|
|
87388
87805
|
authorizationScope ?? void 0,
|
|
87389
87806
|
grant.subjectId
|
|
87390
87807
|
) : /* @__PURE__ */ new Map();
|
|
87391
|
-
const sessions =
|
|
87808
|
+
const sessions = page2.sessions.map((session) => {
|
|
87392
87809
|
const blocker = session.effectiveControl.primaryBlocker;
|
|
87393
87810
|
return {
|
|
87394
87811
|
id: session.id,
|
|
@@ -87426,11 +87843,11 @@ function registerSessionRoutes(app, deps) {
|
|
|
87426
87843
|
});
|
|
87427
87844
|
const response = {
|
|
87428
87845
|
sessions,
|
|
87429
|
-
total:
|
|
87430
|
-
hasMore:
|
|
87846
|
+
total: page2.total,
|
|
87847
|
+
hasMore: page2.hasMore,
|
|
87431
87848
|
humanAdvisoriesEnabled: settings.workDiscoveryEnabled && settings.workDiscoveryHumanAdvisoriesEnabled,
|
|
87432
|
-
nextCursor:
|
|
87433
|
-
cursor:
|
|
87849
|
+
nextCursor: page2.nextCursor ? encodeAgentTopologyCursor({
|
|
87850
|
+
cursor: page2.nextCursor,
|
|
87434
87851
|
parentSessionId: query.parentSessionId === void 0 ? "all" : query.parentSessionId,
|
|
87435
87852
|
rootSessionId: query.rootSessionId ?? null,
|
|
87436
87853
|
query: query.query ?? null,
|
|
@@ -89211,35 +89628,94 @@ function registerSessionRoutes(app, deps) {
|
|
|
89211
89628
|
const compactProjection = compact ? coalesceSessionEventDeltasWithCoverage2(events) : null;
|
|
89212
89629
|
const projected = compactProjection?.events ?? events;
|
|
89213
89630
|
const forensicExact = !compact && mode === "forensic" && payloadMode === "full" && dbPage.fullPayloadsExact;
|
|
89214
|
-
const
|
|
89631
|
+
const page2 = boundSessionEventHttpPage(projected, {
|
|
89215
89632
|
direction,
|
|
89216
89633
|
eventProjection: payloadMode === "full" ? "exact" : "bounded",
|
|
89217
89634
|
...compactProjection ? { coveredThroughBySequence: compactProjection.coveredThroughBySequence } : {}
|
|
89218
89635
|
});
|
|
89219
|
-
const hasMore = dbPage.hasMore ||
|
|
89220
|
-
c.header("X-OpenGeni-Page-Bytes", String(
|
|
89221
|
-
c.header("X-OpenGeni-Page-Max-Bytes", String(Math.max(1024 * 1024,
|
|
89636
|
+
const hasMore = dbPage.hasMore || page2.truncated;
|
|
89637
|
+
c.header("X-OpenGeni-Page-Bytes", String(page2.bytes));
|
|
89638
|
+
c.header("X-OpenGeni-Page-Max-Bytes", String(Math.max(1024 * 1024, page2.bytes)));
|
|
89222
89639
|
c.header("X-OpenGeni-Page-Truncated", String(hasMore));
|
|
89223
89640
|
c.header("X-OpenGeni-Has-More", String(hasMore));
|
|
89224
89641
|
c.header("X-OpenGeni-Event-Mode", mode);
|
|
89225
89642
|
c.header("X-OpenGeni-Event-Direction", direction);
|
|
89226
89643
|
c.header("X-OpenGeni-Payload-Mode", payloadMode);
|
|
89227
89644
|
c.header("X-OpenGeni-Forensic-Exact", String(forensicExact));
|
|
89228
|
-
const coveredFirst =
|
|
89229
|
-
const coveredLastEvent =
|
|
89645
|
+
const coveredFirst = page2.events[0]?.sequence;
|
|
89646
|
+
const coveredLastEvent = page2.events.at(-1);
|
|
89230
89647
|
const coveredLast = coveredLastEvent === void 0 ? void 0 : compactProjection?.coveredThroughBySequence.get(coveredLastEvent.sequence) ?? coveredLastEvent.sequence;
|
|
89231
89648
|
if (coveredFirst !== void 0) c.header("X-OpenGeni-Covered-First", String(coveredFirst));
|
|
89232
89649
|
if (coveredLast !== void 0) c.header("X-OpenGeni-Covered-Last", String(coveredLast));
|
|
89233
|
-
const truncatedBy =
|
|
89650
|
+
const truncatedBy = page2.truncated ? "http_bytes" : dbPage.truncatedBy;
|
|
89234
89651
|
if (truncatedBy) c.header("X-OpenGeni-Truncated-By", truncatedBy);
|
|
89235
|
-
if (
|
|
89652
|
+
if (page2.nextSequence !== null) {
|
|
89236
89653
|
c.header(
|
|
89237
89654
|
direction === "before" ? "X-OpenGeni-Next-Before" : "X-OpenGeni-Next-After",
|
|
89238
|
-
String(
|
|
89655
|
+
String(page2.nextSequence)
|
|
89239
89656
|
);
|
|
89240
89657
|
}
|
|
89241
|
-
return c.json(
|
|
89658
|
+
return c.json(page2.events);
|
|
89242
89659
|
});
|
|
89660
|
+
app.get(
|
|
89661
|
+
"/v1/workspaces/:workspaceId/sessions/:sessionId/events/:eventId/message-preview",
|
|
89662
|
+
async (c) => {
|
|
89663
|
+
const workspaceId = c.req.param("workspaceId");
|
|
89664
|
+
await requireAccessGrant32(c, deps, workspaceId, "sessions:read");
|
|
89665
|
+
const sessionId = c.req.param("sessionId");
|
|
89666
|
+
await assertSessionExists(db, workspaceId, sessionId);
|
|
89667
|
+
const eventId = c.req.param("eventId");
|
|
89668
|
+
const rawSequence = c.req.query("sequence");
|
|
89669
|
+
const sequence = Number(rawSequence);
|
|
89670
|
+
if (!z27.string().uuid().safeParse(eventId).success || rawSequence === void 0 || !/^\d+$/.test(rawSequence) || !Number.isSafeInteger(sequence) || sequence < 1 || sequence > 2147483647)
|
|
89671
|
+
throw new HTTPException72(400, { message: "Invalid message preview reference" });
|
|
89672
|
+
const notFound = () => new HTTPException72(404, { message: "message not found" });
|
|
89673
|
+
const maxUnits = 12e3;
|
|
89674
|
+
const eventTable = sessionPreviewSchema.sessionEvents;
|
|
89675
|
+
const candidates = await withWorkspaceRls(
|
|
89676
|
+
db,
|
|
89677
|
+
workspaceId,
|
|
89678
|
+
(tx) => tx.select({ kind: sql`jsonb_typeof(${eventTable.payload}->'text')` }).from(eventTable).where(
|
|
89679
|
+
and(
|
|
89680
|
+
eq(eventTable.workspaceId, workspaceId),
|
|
89681
|
+
eq(eventTable.sessionId, sessionId),
|
|
89682
|
+
eq(eventTable.id, eventId),
|
|
89683
|
+
eq(eventTable.sequence, sequence),
|
|
89684
|
+
sql`${eventTable.type} in ('user.message', 'agent.message.completed')`
|
|
89685
|
+
)
|
|
89686
|
+
).limit(1)
|
|
89687
|
+
);
|
|
89688
|
+
if (candidates[0]?.kind !== "string") throw notFound();
|
|
89689
|
+
const read = (offset2) => listSessionEventSlices(db, workspaceId, sessionId, {
|
|
89690
|
+
sourceSequence: sequence,
|
|
89691
|
+
sourceOffset: offset2,
|
|
89692
|
+
after: sequence - 1,
|
|
89693
|
+
before: sequence + 1,
|
|
89694
|
+
includeTypes: ["user.message", "agent.message.completed"],
|
|
89695
|
+
view: "conversation"
|
|
89696
|
+
});
|
|
89697
|
+
const first = await read(0);
|
|
89698
|
+
const event = first.events[0];
|
|
89699
|
+
const slice = first.slices?.[sequence];
|
|
89700
|
+
if (!event || event.id !== eventId || event.sequence !== sequence || !slice || slice.omitted)
|
|
89701
|
+
throw notFound();
|
|
89702
|
+
if (slice.total > maxUnits) return c.json({ status: "unavailable" });
|
|
89703
|
+
let text = slice.text;
|
|
89704
|
+
let offset = slice.unit === "utf16" ? slice.text.length : Array.from(slice.text).length;
|
|
89705
|
+
if (text.length > maxUnits) return c.json({ status: "unavailable" });
|
|
89706
|
+
while (offset < slice.total) {
|
|
89707
|
+
if (offset === 0) throw notFound();
|
|
89708
|
+
const next = await read(offset);
|
|
89709
|
+
const part = next.slices?.[sequence];
|
|
89710
|
+
if (next.events[0]?.id !== eventId || !part || part.omitted || part.unit !== slice.unit || part.total !== slice.total || part.offset !== offset)
|
|
89711
|
+
throw notFound();
|
|
89712
|
+
text += part.text;
|
|
89713
|
+
offset += slice.unit === "utf16" ? part.text.length : Array.from(part.text).length;
|
|
89714
|
+
if (text.length > maxUnits) return c.json({ status: "unavailable" });
|
|
89715
|
+
}
|
|
89716
|
+
return c.json({ status: "available", text });
|
|
89717
|
+
}
|
|
89718
|
+
);
|
|
89243
89719
|
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId/events/stream", async (c) => {
|
|
89244
89720
|
const workspaceId = c.req.param("workspaceId");
|
|
89245
89721
|
const grant = await requireAccessGrant32(c, deps, workspaceId, "sessions:read");
|
|
@@ -90807,6 +91283,8 @@ function sessionAuthorizationOperationForHttp(method, pathname, sessionId) {
|
|
|
90807
91283
|
return verb === "POST" ? "session.context.write" : null;
|
|
90808
91284
|
}
|
|
90809
91285
|
if (suffix === "/events/stream" && verb === "GET") return "session.stream.read";
|
|
91286
|
+
if (/^\/events\/[^/]+\/message-preview$/.test(suffix) && verb === "GET")
|
|
91287
|
+
return "session.events.read";
|
|
90810
91288
|
if (suffix === "/events") {
|
|
90811
91289
|
if (verb === "GET") return "session.events.read";
|
|
90812
91290
|
if (verb === "POST") return "session.append";
|
|
@@ -92641,14 +93119,14 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
92641
93119
|
const limit = boundedLimit(c.req.query("limit"));
|
|
92642
93120
|
const fetched = await listWorkspaceControlEvents2(deps.db, workspaceId, after, limit + 1);
|
|
92643
93121
|
const countHasMore = fetched.length > limit;
|
|
92644
|
-
const
|
|
92645
|
-
const truncated = countHasMore ||
|
|
92646
|
-
c.header("X-OpenGeni-Page-Bytes", String(
|
|
93122
|
+
const page2 = boundWorkspaceControlHttpPage(fetched.slice(0, limit));
|
|
93123
|
+
const truncated = countHasMore || page2.truncated;
|
|
93124
|
+
c.header("X-OpenGeni-Page-Bytes", String(page2.bytes));
|
|
92647
93125
|
c.header("X-OpenGeni-Page-Truncated", String(truncated));
|
|
92648
|
-
if (
|
|
92649
|
-
c.header("X-OpenGeni-Next-After", String(
|
|
93126
|
+
if (page2.nextSequence !== null) {
|
|
93127
|
+
c.header("X-OpenGeni-Next-After", String(page2.nextSequence));
|
|
92650
93128
|
}
|
|
92651
|
-
return c.json(
|
|
93129
|
+
return c.json(page2.events);
|
|
92652
93130
|
});
|
|
92653
93131
|
app.get("/v1/workspaces/:workspaceId/control-events/stream", async (c) => {
|
|
92654
93132
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -93800,10 +94278,10 @@ function preferenceLifecycle(row, generatedAt) {
|
|
|
93800
94278
|
if (row.status === "superseded") return "superseded";
|
|
93801
94279
|
return "historical";
|
|
93802
94280
|
}
|
|
93803
|
-
function preferenceEntries(
|
|
93804
|
-
const visibleRevisionIds = new Set(
|
|
93805
|
-
const visiblePreferenceIds = new Set(
|
|
93806
|
-
return
|
|
94281
|
+
function preferenceEntries(page2, generatedAt) {
|
|
94282
|
+
const visibleRevisionIds = new Set(page2.rows.map((row) => row.revisionId));
|
|
94283
|
+
const visiblePreferenceIds = new Set(page2.rows.map((row) => row.preferenceId));
|
|
94284
|
+
return page2.rows.map((row) => {
|
|
93807
94285
|
const scope = row.scope === "organization" ? "organization" : row.scope === "user" ? "personal" : "workspace";
|
|
93808
94286
|
const lifecycle2 = preferenceLifecycle(row, generatedAt);
|
|
93809
94287
|
const relationships = [];
|
|
@@ -95367,6 +95845,7 @@ import {
|
|
|
95367
95845
|
requireAccessGrant as requireAccessGrant41,
|
|
95368
95846
|
WorkspaceInsightsFilterValidationError
|
|
95369
95847
|
} from "@opengeni/core";
|
|
95848
|
+
import { currentSessionRlsActorIdentityKey } from "@opengeni/db";
|
|
95370
95849
|
import { workspaceInsightsMetricObserver } from "@opengeni/observability";
|
|
95371
95850
|
import { HTTPException as HTTPException85 } from "hono/http-exception";
|
|
95372
95851
|
function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
@@ -95379,9 +95858,36 @@ function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
|
95379
95858
|
throw error;
|
|
95380
95859
|
}
|
|
95381
95860
|
}
|
|
95861
|
+
function createInFlightCoalescer() {
|
|
95862
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
95863
|
+
return {
|
|
95864
|
+
run(key, work) {
|
|
95865
|
+
const pending = inFlight.get(key);
|
|
95866
|
+
if (pending) return pending;
|
|
95867
|
+
const started2 = work().finally(() => {
|
|
95868
|
+
if (inFlight.get(key) === started2) inFlight.delete(key);
|
|
95869
|
+
});
|
|
95870
|
+
inFlight.set(key, started2);
|
|
95871
|
+
return started2;
|
|
95872
|
+
},
|
|
95873
|
+
get size() {
|
|
95874
|
+
return inFlight.size;
|
|
95875
|
+
}
|
|
95876
|
+
};
|
|
95877
|
+
}
|
|
95878
|
+
function workspaceInsightsCoalesceKey(input) {
|
|
95879
|
+
return JSON.stringify([
|
|
95880
|
+
input.workspaceId,
|
|
95881
|
+
input.range,
|
|
95882
|
+
input.provider,
|
|
95883
|
+
input.model,
|
|
95884
|
+
input.rlsActor
|
|
95885
|
+
]);
|
|
95886
|
+
}
|
|
95382
95887
|
function registerInsightsRoutes(app, deps) {
|
|
95383
95888
|
const observeRequest = workspaceInsightsMetricObserver(deps.observability);
|
|
95384
95889
|
const observePhase = workspaceInsightsPhaseMetricObserver(deps.observability);
|
|
95890
|
+
const coalesce = createInFlightCoalescer();
|
|
95385
95891
|
app.get("/v1/workspaces/:workspaceId/insights", async (c) => {
|
|
95386
95892
|
const startedAtMs = performance.now();
|
|
95387
95893
|
const rangeRaw = c.req.query("range") ?? "week";
|
|
@@ -95405,16 +95911,25 @@ function registerInsightsRoutes(app, deps) {
|
|
|
95405
95911
|
}
|
|
95406
95912
|
provider = normalizeWorkspaceInsightsQueryFilter(providerRaw, "provider");
|
|
95407
95913
|
model = normalizeWorkspaceInsightsQueryFilter(modelRaw, "model");
|
|
95408
|
-
const response = await
|
|
95409
|
-
|
|
95410
|
-
deps.settings,
|
|
95411
|
-
{
|
|
95914
|
+
const response = await coalesce.run(
|
|
95915
|
+
workspaceInsightsCoalesceKey({
|
|
95412
95916
|
workspaceId,
|
|
95413
95917
|
range: rangeParsed.data,
|
|
95414
95918
|
provider,
|
|
95415
|
-
model
|
|
95416
|
-
|
|
95417
|
-
|
|
95919
|
+
model,
|
|
95920
|
+
rlsActor: currentSessionRlsActorIdentityKey()
|
|
95921
|
+
}),
|
|
95922
|
+
() => getWorkspaceInsights(
|
|
95923
|
+
deps.db,
|
|
95924
|
+
deps.settings,
|
|
95925
|
+
{
|
|
95926
|
+
workspaceId,
|
|
95927
|
+
range: rangeParsed.data,
|
|
95928
|
+
provider,
|
|
95929
|
+
model
|
|
95930
|
+
},
|
|
95931
|
+
observePhase
|
|
95932
|
+
)
|
|
95418
95933
|
);
|
|
95419
95934
|
c.header("cache-control", "private, no-store");
|
|
95420
95935
|
const result = c.json(WorkspaceInsightsResponse.parse(response));
|
|
@@ -98379,7 +98894,8 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
98379
98894
|
await createManagedOrganization(deps.db, {
|
|
98380
98895
|
subjectId,
|
|
98381
98896
|
subjectLabel: session.user.email || session.user.name,
|
|
98382
|
-
...payload
|
|
98897
|
+
...payload,
|
|
98898
|
+
trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
|
|
98383
98899
|
})
|
|
98384
98900
|
),
|
|
98385
98901
|
201
|
|
@@ -99155,7 +99671,7 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
99155
99671
|
while (index < workspaces.length && sessions.length < query.limit && reads < ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS) {
|
|
99156
99672
|
const workspace = workspaces[index];
|
|
99157
99673
|
reads += 1;
|
|
99158
|
-
const
|
|
99674
|
+
const page2 = await listWorkspaceSessionPage(c, deps, {
|
|
99159
99675
|
workspace,
|
|
99160
99676
|
readAuthority,
|
|
99161
99677
|
innerCursor,
|
|
@@ -99163,21 +99679,21 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
99163
99679
|
limit: query.limit - sessions.length,
|
|
99164
99680
|
query
|
|
99165
99681
|
});
|
|
99166
|
-
if (
|
|
99682
|
+
if (page2 === null) {
|
|
99167
99683
|
index += 1;
|
|
99168
99684
|
innerCursor = null;
|
|
99169
99685
|
pinnedOffset = 0;
|
|
99170
99686
|
continue;
|
|
99171
99687
|
}
|
|
99172
|
-
sessions.push(...
|
|
99173
|
-
if (
|
|
99688
|
+
sessions.push(...page2.sessions);
|
|
99689
|
+
if (page2.nextPinnedOffset !== null) {
|
|
99174
99690
|
innerCursor = null;
|
|
99175
|
-
pinnedOffset =
|
|
99691
|
+
pinnedOffset = page2.nextPinnedOffset;
|
|
99176
99692
|
break;
|
|
99177
99693
|
}
|
|
99178
99694
|
pinnedOffset = 0;
|
|
99179
|
-
if (
|
|
99180
|
-
innerCursor =
|
|
99695
|
+
if (page2.nextCursor) {
|
|
99696
|
+
innerCursor = page2.nextCursor;
|
|
99181
99697
|
} else {
|
|
99182
99698
|
index += 1;
|
|
99183
99699
|
innerCursor = null;
|
|
@@ -99232,24 +99748,24 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
99232
99748
|
personalWorkspaceOwnerException: authorization.canonicalManagedHumanSession
|
|
99233
99749
|
});
|
|
99234
99750
|
const withStatus = (rows3) => input.query.status ? rows3.filter((session) => session.status === input.query.status) : rows3;
|
|
99235
|
-
let
|
|
99751
|
+
let page2 = await list(input.limit);
|
|
99236
99752
|
let rows2;
|
|
99237
99753
|
let nextPinnedOffset = null;
|
|
99238
99754
|
if (cursor) {
|
|
99239
|
-
rows2 =
|
|
99755
|
+
rows2 = page2.sessions;
|
|
99240
99756
|
} else {
|
|
99241
|
-
const pinned =
|
|
99757
|
+
const pinned = page2.pinned.slice(input.pinnedOffset);
|
|
99242
99758
|
if (pinned.length >= input.limit) {
|
|
99243
99759
|
rows2 = pinned.slice(0, input.limit);
|
|
99244
99760
|
nextPinnedOffset = input.pinnedOffset + input.limit;
|
|
99245
99761
|
return { sessions: withStatus(rows2), nextCursor: null, nextPinnedOffset };
|
|
99246
99762
|
}
|
|
99247
|
-
if (pinned.length > 0 &&
|
|
99248
|
-
|
|
99763
|
+
if (pinned.length > 0 && page2.sessions.length > input.limit - pinned.length) {
|
|
99764
|
+
page2 = await list(input.limit - pinned.length);
|
|
99249
99765
|
}
|
|
99250
|
-
rows2 = [...pinned, ...
|
|
99766
|
+
rows2 = [...pinned, ...page2.sessions];
|
|
99251
99767
|
}
|
|
99252
|
-
return { sessions: withStatus(rows2), nextCursor:
|
|
99768
|
+
return { sessions: withStatus(rows2), nextCursor: page2.nextCursor, nextPinnedOffset };
|
|
99253
99769
|
} catch (error) {
|
|
99254
99770
|
if (error instanceof SessionListAccessError2) {
|
|
99255
99771
|
throw new HTTPException91(403, { message: error.message });
|
|
@@ -99591,7 +100107,8 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
99591
100107
|
actorSubjectId: `user:${session.user.id}`,
|
|
99592
100108
|
organizationName,
|
|
99593
100109
|
operationId: parsed.data.operationId,
|
|
99594
|
-
requestFingerprint
|
|
100110
|
+
requestFingerprint,
|
|
100111
|
+
trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
|
|
99595
100112
|
})
|
|
99596
100113
|
)
|
|
99597
100114
|
);
|
|
@@ -99843,7 +100360,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
99843
100360
|
"workspace:read"
|
|
99844
100361
|
);
|
|
99845
100362
|
try {
|
|
99846
|
-
const
|
|
100363
|
+
const page2 = await listManagedHumanUserResourceAuthorities(
|
|
99847
100364
|
deps,
|
|
99848
100365
|
access,
|
|
99849
100366
|
workspaceId,
|
|
@@ -99852,7 +100369,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
99852
100369
|
return context.json(
|
|
99853
100370
|
ListUserResourceAuthoritiesResponse.parse({
|
|
99854
100371
|
scope: "user",
|
|
99855
|
-
...
|
|
100372
|
+
...page2
|
|
99856
100373
|
})
|
|
99857
100374
|
);
|
|
99858
100375
|
} catch (error) {
|
|
@@ -101847,16 +102364,16 @@ async function publishSlackAppHome(deps, installation, refresh, renewLease) {
|
|
|
101847
102364
|
let cursor;
|
|
101848
102365
|
do {
|
|
101849
102366
|
await renewLease();
|
|
101850
|
-
const
|
|
102367
|
+
const page2 = await listSessionsForSubject3(deps.db, installation.workspaceId, {
|
|
101851
102368
|
subjectId: grant.subjectId,
|
|
101852
102369
|
limit: 500,
|
|
101853
102370
|
...cursor ? { cursor } : {},
|
|
101854
102371
|
...authorizationScope ? { authorizationScope } : {}
|
|
101855
102372
|
});
|
|
101856
|
-
if (!cursor) sessions.push(...
|
|
101857
|
-
sessions.push(...
|
|
101858
|
-
if (!
|
|
101859
|
-
cursor = decodeSessionListCursor3(
|
|
102373
|
+
if (!cursor) sessions.push(...page2.pinned);
|
|
102374
|
+
sessions.push(...page2.sessions);
|
|
102375
|
+
if (!page2.nextCursor) break;
|
|
102376
|
+
cursor = decodeSessionListCursor3(page2.nextCursor) ?? void 0;
|
|
101860
102377
|
if (!cursor) throw new Error("Slack App Home session cursor was invalid");
|
|
101861
102378
|
} while (cursor);
|
|
101862
102379
|
} catch (error) {
|
|
@@ -104167,13 +104684,13 @@ async function resolveSlackDeliveryHome(deps, interaction) {
|
|
|
104167
104684
|
}
|
|
104168
104685
|
async function deliverSlackSessionEvents(deps, interaction, claimHolderId) {
|
|
104169
104686
|
if (!interaction.sessionId) return;
|
|
104170
|
-
const
|
|
104687
|
+
const page2 = await listSessionEventPage3(deps.db, interaction.workspaceId, interaction.sessionId, {
|
|
104171
104688
|
after: interaction.lastDeliveredSessionEventSequence,
|
|
104172
104689
|
limit: 100,
|
|
104173
104690
|
includeTypes: [...SLACK_DELIVERY_EVENT_TYPES],
|
|
104174
104691
|
maxBytes: 256 * 1024
|
|
104175
104692
|
});
|
|
104176
|
-
if (
|
|
104693
|
+
if (page2.events.length === 0) {
|
|
104177
104694
|
await releaseSlackInteractionDelivery(deps.db, {
|
|
104178
104695
|
...interaction,
|
|
104179
104696
|
claimHolderId
|
|
@@ -104212,10 +104729,10 @@ async function deliverSlackSessionEvents(deps, interaction, claimHolderId) {
|
|
|
104212
104729
|
};
|
|
104213
104730
|
let lastSequence = interaction.lastDeliveredSessionEventSequence;
|
|
104214
104731
|
let terminal2 = null;
|
|
104215
|
-
const orderedEvents =
|
|
104732
|
+
const orderedEvents = page2.events.filter(
|
|
104216
104733
|
(event) => (event.turnAssociation === null || event.turnAssociation === "current") && event.duplicateOfEventId === null
|
|
104217
104734
|
).sort((left, right) => left.sequence - right.sequence);
|
|
104218
|
-
lastSequence =
|
|
104735
|
+
lastSequence = page2.events.reduce(
|
|
104219
104736
|
(latest, event) => Math.max(latest, event.sequence),
|
|
104220
104737
|
lastSequence
|
|
104221
104738
|
);
|
|
@@ -107113,4 +107630,4 @@ export {
|
|
|
107113
107630
|
withDefaultEnabledCapabilityMcpTools,
|
|
107114
107631
|
workflowIdForSession4 as workflowIdForSession
|
|
107115
107632
|
};
|
|
107116
|
-
//# sourceMappingURL=chunk-
|
|
107633
|
+
//# sourceMappingURL=chunk-PTO4RZT5.js.map
|