@opengeni/api-router 2.5.0 → 2.6.4-canary.0
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.d.ts +2 -1
- package/dist/app.js +3 -1
- package/dist/auth/managed-auth-attempt-context.d.ts +5 -1
- package/dist/auth/managed-auth.d.ts +24 -1
- package/dist/{chunk-QESX7HDK.js → chunk-UOI7KAP3.js} +3240 -791
- package/dist/chunk-UOI7KAP3.js.map +1 -0
- package/dist/http/sse.d.ts +9 -0
- package/dist/index.js +117 -5
- package/dist/index.js.map +1 -1
- package/dist/interaction-metrics.d.ts +2 -0
- package/dist/mcp/company-brain-governed-writes.d.ts +1 -1
- package/dist/mcp/company-profile-agent-admin.d.ts +6 -6
- package/dist/mcp/remember.d.ts +2 -2
- package/dist/mcp/scheduled-task-view.d.ts +3 -3
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/session-view.d.ts +1 -0
- package/dist/mcp/session-wait.d.ts +19 -0
- package/dist/model-catalog.d.ts +5 -31
- package/dist/routes/api-keys.d.ts +2 -0
- package/dist/routes/browser-sessions.d.ts +1 -0
- package/dist/routes/computer-sessions.d.ts +12 -0
- package/dist/routes/managed-auth-session-sets.d.ts +7 -0
- package/dist/routes/workspaces.d.ts +1 -1
- package/dist/sandbox/metrics-ingestion.d.ts +16 -0
- package/dist/workspace-delete-observability.d.ts +10 -0
- package/package.json +19 -19
- package/src/app.ts +206 -29
- package/src/auth/managed-auth-attempt-context.ts +40 -3
- package/src/auth/managed-auth-session-adapter.ts +1 -0
- package/src/auth/managed-auth.ts +164 -4
- package/src/http/sse.ts +279 -45
- package/src/index.ts +13 -1
- package/src/integrations/oauth-client.ts +8 -1
- package/src/integrations/provider-oauth.ts +12 -2
- package/src/integrations/slack-interactions.ts +77 -37
- package/src/interaction-metrics.ts +30 -0
- package/src/mcp/company-brain-governed-writes.ts +38 -23
- package/src/mcp/company-profile-agent-admin.ts +7 -7
- package/src/mcp/remember.ts +19 -8
- package/src/mcp/server.ts +328 -27
- package/src/mcp/session-wait.ts +56 -8
- package/src/model-catalog.ts +45 -337
- package/src/routes/api-integrations.ts +2 -2
- package/src/routes/api-keys.ts +149 -7
- package/src/routes/automations.ts +186 -19
- package/src/routes/browser-sessions.ts +10 -2
- package/src/routes/capabilities.ts +3 -3
- package/src/routes/codex.ts +483 -74
- package/src/routes/company-profile.ts +64 -0
- package/src/routes/computer-sessions.ts +103 -1
- package/src/routes/connections.ts +271 -16
- package/src/routes/github.ts +0 -8
- package/src/routes/integration-facets.ts +8 -5
- package/src/routes/interaction-resources.ts +7 -1
- package/src/routes/managed-auth-session-sets.ts +199 -2
- package/src/routes/organization-memberships.ts +28 -8
- package/src/routes/packs.ts +5 -5
- package/src/routes/plugins.ts +2 -2
- package/src/routes/pr-review.ts +80 -4
- package/src/routes/scheduled-tasks.ts +47 -11
- package/src/routes/sessions.ts +75 -53
- package/src/routes/skills.ts +3 -3
- package/src/routes/supergrok.ts +3 -2
- package/src/routes/workspaces.ts +665 -56
- package/src/sandbox/channel-a.ts +10 -4
- package/src/sandbox/machines.ts +13 -6
- package/src/sandbox/metrics-ingestion.ts +157 -3
- package/src/sandbox/viewer.ts +20 -1
- package/src/workspace-delete-observability.ts +75 -0
- package/dist/chunk-QESX7HDK.js.map +0 -1
|
@@ -25,18 +25,26 @@ import {
|
|
|
25
25
|
listAutomationRuns,
|
|
26
26
|
listAutomationSources,
|
|
27
27
|
listAutomationTriggers,
|
|
28
|
+
lockActiveWorkspaceGatewayCustomModelForAdmission,
|
|
29
|
+
lockActiveWorkspaceOpenRouterCustomModelForAdmission,
|
|
28
30
|
recordAutomationEvent,
|
|
29
31
|
resolveAutomationWebhookEndpoint,
|
|
30
32
|
updateAutomationSource,
|
|
31
33
|
updateAutomationTrigger,
|
|
34
|
+
withWorkspaceGatewayCustomModelReadLock,
|
|
35
|
+
withWorkspaceOpenRouterCustomModelReadLock,
|
|
32
36
|
type AutomationSourceSecret,
|
|
33
37
|
} from "@opengeni/db";
|
|
34
38
|
import {
|
|
35
39
|
automationRequestDigest,
|
|
40
|
+
assertWorkspaceModelPolicyAllows,
|
|
36
41
|
buildAutomationAcceptedExecution,
|
|
42
|
+
canonicalConfiguredModel,
|
|
43
|
+
workspaceCustomModelReference,
|
|
37
44
|
requireAccessGrant,
|
|
38
45
|
requireAutomationAdapter,
|
|
39
46
|
requirePermission,
|
|
47
|
+
resolveWorkspaceCatalogSettings,
|
|
40
48
|
type ApiRouteDeps,
|
|
41
49
|
} from "@opengeni/core";
|
|
42
50
|
import type { Hono } from "hono";
|
|
@@ -157,13 +165,36 @@ export function registerAutomationRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
157
165
|
for (const permission of request.sessionTemplate.firstPartyMcpPermissions) {
|
|
158
166
|
requirePermission(grant, permission);
|
|
159
167
|
}
|
|
168
|
+
const catalogSettings = (
|
|
169
|
+
await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
|
|
170
|
+
accountId: grant.accountId,
|
|
171
|
+
workspaceId,
|
|
172
|
+
})
|
|
173
|
+
).settings;
|
|
174
|
+
const model = canonicalConfiguredModel(catalogSettings, request.sessionTemplate.model) ?? null;
|
|
175
|
+
if (model) {
|
|
176
|
+
await assertWorkspaceModelPolicyAllows(deps.db, catalogSettings, workspaceId, model);
|
|
177
|
+
}
|
|
178
|
+
const normalizedRequest = {
|
|
179
|
+
...request,
|
|
180
|
+
sessionTemplate: { ...request.sessionTemplate, model },
|
|
181
|
+
};
|
|
182
|
+
const beforeCreateCommit = model
|
|
183
|
+
? workspaceCustomModelCommitGuard({
|
|
184
|
+
settings: catalogSettings,
|
|
185
|
+
accountId: grant.accountId,
|
|
186
|
+
workspaceId,
|
|
187
|
+
modelId: model,
|
|
188
|
+
})
|
|
189
|
+
: undefined;
|
|
160
190
|
return c.json(
|
|
161
191
|
await createAutomationTrigger(deps.db, {
|
|
162
192
|
accountId: grant.accountId,
|
|
163
193
|
workspaceId,
|
|
164
194
|
createdBySubjectId: grant.subjectId,
|
|
165
|
-
request,
|
|
195
|
+
request: normalizedRequest,
|
|
166
196
|
adapterId: adapter.id,
|
|
197
|
+
...(beforeCreateCommit ? { beforeCreateCommit } : {}),
|
|
167
198
|
}),
|
|
168
199
|
201,
|
|
169
200
|
);
|
|
@@ -194,12 +225,54 @@ export function registerAutomationRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
194
225
|
requirePermission(grant, permission);
|
|
195
226
|
}
|
|
196
227
|
}
|
|
228
|
+
const catalogSettings = (
|
|
229
|
+
await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
|
|
230
|
+
accountId: grant.accountId,
|
|
231
|
+
workspaceId,
|
|
232
|
+
})
|
|
233
|
+
).settings;
|
|
234
|
+
const normalizedRequest = request.sessionTemplate
|
|
235
|
+
? {
|
|
236
|
+
...request,
|
|
237
|
+
sessionTemplate: {
|
|
238
|
+
...request.sessionTemplate,
|
|
239
|
+
model: canonicalConfiguredModel(catalogSettings, request.sessionTemplate.model) ?? null,
|
|
240
|
+
},
|
|
241
|
+
}
|
|
242
|
+
: request;
|
|
243
|
+
if (normalizedRequest.sessionTemplate?.model) {
|
|
244
|
+
await assertWorkspaceModelPolicyAllows(
|
|
245
|
+
deps.db,
|
|
246
|
+
catalogSettings,
|
|
247
|
+
workspaceId,
|
|
248
|
+
normalizedRequest.sessionTemplate.model,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
const effectiveModel = normalizedRequest.sessionTemplate
|
|
252
|
+
? normalizedRequest.sessionTemplate.model
|
|
253
|
+
: existing.sessionTemplate.model;
|
|
254
|
+
const materialExecutionChange =
|
|
255
|
+
request.eventTypes !== undefined ||
|
|
256
|
+
request.configuration !== undefined ||
|
|
257
|
+
request.parameters !== undefined ||
|
|
258
|
+
request.sessionTemplate !== undefined ||
|
|
259
|
+
(request.status === "active" && existing.status !== "active");
|
|
260
|
+
const beforeUpdateCommit =
|
|
261
|
+
materialExecutionChange && effectiveModel
|
|
262
|
+
? workspaceCustomModelCommitGuard({
|
|
263
|
+
settings: catalogSettings,
|
|
264
|
+
accountId: grant.accountId,
|
|
265
|
+
workspaceId,
|
|
266
|
+
modelId: effectiveModel,
|
|
267
|
+
})
|
|
268
|
+
: undefined;
|
|
197
269
|
try {
|
|
198
270
|
const trigger = await updateAutomationTrigger(deps.db, {
|
|
199
271
|
workspaceId,
|
|
200
272
|
triggerId: c.req.param("triggerId"),
|
|
201
273
|
subjectId: grant.subjectId,
|
|
202
|
-
request,
|
|
274
|
+
request: normalizedRequest,
|
|
275
|
+
...(beforeUpdateCommit ? { beforeUpdateCommit } : {}),
|
|
203
276
|
});
|
|
204
277
|
if (!trigger)
|
|
205
278
|
throw new HTTPException(404, {
|
|
@@ -377,29 +450,86 @@ export async function acceptAutomationEvent(
|
|
|
377
450
|
workspaceId: source.workspaceId,
|
|
378
451
|
sourceId: source.id,
|
|
379
452
|
});
|
|
380
|
-
const
|
|
453
|
+
const matchingByEvent = triggers.filter((trigger) =>
|
|
381
454
|
adapter.matches({ event: input.normalizedEvent, trigger }),
|
|
382
455
|
);
|
|
383
|
-
if (
|
|
456
|
+
if (matchingByEvent.length > AUTOMATION_MAX_MATCHED_TRIGGERS) {
|
|
384
457
|
throw new HTTPException(422, {
|
|
385
458
|
message: `automation event matches more than ${AUTOMATION_MAX_MATCHED_TRIGGERS} triggers`,
|
|
386
459
|
});
|
|
387
460
|
}
|
|
388
|
-
const stored =
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
461
|
+
const stored =
|
|
462
|
+
matchingByEvent.length === 0
|
|
463
|
+
? await recordAutomationEvent(deps.db, {
|
|
464
|
+
accountId: source.accountId,
|
|
465
|
+
workspaceId: source.workspaceId,
|
|
466
|
+
sourceId: source.id,
|
|
467
|
+
sourceVersion: source.version,
|
|
468
|
+
sourceConfiguration: source.configuration,
|
|
469
|
+
matchedTriggerRevisions: [],
|
|
470
|
+
deliveryKey: input.deliveryKey,
|
|
471
|
+
requestDigest: input.requestDigest,
|
|
472
|
+
normalizedEvent: input.normalizedEvent,
|
|
473
|
+
ignoredReason: "no_matching_triggers",
|
|
474
|
+
})
|
|
475
|
+
: await withWorkspaceGatewayCustomModelReadLock(
|
|
476
|
+
deps.db,
|
|
477
|
+
{ accountId: source.accountId, workspaceId: source.workspaceId },
|
|
478
|
+
async (gatewayLockedDb) =>
|
|
479
|
+
await withWorkspaceOpenRouterCustomModelReadLock(
|
|
480
|
+
gatewayLockedDb,
|
|
481
|
+
{ accountId: source.accountId, workspaceId: source.workspaceId },
|
|
482
|
+
async (lockedDb) => {
|
|
483
|
+
const catalogSourceSettings = deps.catalogSourceSettings ?? deps.settings;
|
|
484
|
+
const catalogSettings = (
|
|
485
|
+
await resolveWorkspaceCatalogSettings(lockedDb, catalogSourceSettings, {
|
|
486
|
+
accountId: source.accountId,
|
|
487
|
+
workspaceId: source.workspaceId,
|
|
488
|
+
})
|
|
489
|
+
).settings;
|
|
490
|
+
const matchingAtAcceptance = [];
|
|
491
|
+
for (const trigger of matchingByEvent) {
|
|
492
|
+
try {
|
|
493
|
+
const render = adapter.render({
|
|
494
|
+
event: input.normalizedEvent,
|
|
495
|
+
trigger,
|
|
496
|
+
source,
|
|
497
|
+
});
|
|
498
|
+
const requestedModel =
|
|
499
|
+
render.sessionTemplate.model ?? catalogSettings.openaiModel;
|
|
500
|
+
const model = canonicalConfiguredModel(catalogSettings, requestedModel);
|
|
501
|
+
if (!model) continue;
|
|
502
|
+
await assertWorkspaceModelPolicyAllows(
|
|
503
|
+
lockedDb,
|
|
504
|
+
catalogSettings,
|
|
505
|
+
source.workspaceId,
|
|
506
|
+
model,
|
|
507
|
+
);
|
|
508
|
+
matchingAtAcceptance.push(trigger);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
if (isUnprocessableEntity(error)) continue;
|
|
511
|
+
throw error;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return await recordAutomationEvent(lockedDb, {
|
|
515
|
+
accountId: source.accountId,
|
|
516
|
+
workspaceId: source.workspaceId,
|
|
517
|
+
sourceId: source.id,
|
|
518
|
+
sourceVersion: source.version,
|
|
519
|
+
sourceConfiguration: source.configuration,
|
|
520
|
+
matchedTriggerRevisions: matchingAtAcceptance.map((trigger) => ({
|
|
521
|
+
triggerId: trigger.id,
|
|
522
|
+
revision: trigger.revision,
|
|
523
|
+
})),
|
|
524
|
+
deliveryKey: input.deliveryKey,
|
|
525
|
+
requestDigest: input.requestDigest,
|
|
526
|
+
normalizedEvent: input.normalizedEvent,
|
|
527
|
+
ignoredReason:
|
|
528
|
+
matchingAtAcceptance.length === 0 ? "no_executable_triggers" : null,
|
|
529
|
+
});
|
|
530
|
+
},
|
|
531
|
+
),
|
|
532
|
+
);
|
|
403
533
|
const matching = await getAutomationTriggerRevisions(deps.db, {
|
|
404
534
|
workspaceId: source.workspaceId,
|
|
405
535
|
refs: stored.event.matchedTriggerRevisions,
|
|
@@ -457,6 +587,43 @@ export async function acceptAutomationEvent(
|
|
|
457
587
|
});
|
|
458
588
|
}
|
|
459
589
|
|
|
590
|
+
function isUnprocessableEntity(error: unknown): boolean {
|
|
591
|
+
return (
|
|
592
|
+
error instanceof Error &&
|
|
593
|
+
"status" in error &&
|
|
594
|
+
(error as Error & { status?: unknown }).status === 422
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function workspaceCustomModelCommitGuard(input: {
|
|
599
|
+
settings: ApiRouteDeps["settings"];
|
|
600
|
+
accountId: string;
|
|
601
|
+
workspaceId: string;
|
|
602
|
+
modelId: string;
|
|
603
|
+
}): ((tx: ApiRouteDeps["db"]) => Promise<void>) | undefined {
|
|
604
|
+
const reference = workspaceCustomModelReference(input.settings, input.modelId);
|
|
605
|
+
if (!reference) return undefined;
|
|
606
|
+
return async (tx): Promise<void> => {
|
|
607
|
+
const active =
|
|
608
|
+
reference.providerKind === "openrouter"
|
|
609
|
+
? await lockActiveWorkspaceOpenRouterCustomModelForAdmission(tx, {
|
|
610
|
+
accountId: input.accountId,
|
|
611
|
+
workspaceId: input.workspaceId,
|
|
612
|
+
upstreamModelId: reference.upstreamModelId,
|
|
613
|
+
})
|
|
614
|
+
: await lockActiveWorkspaceGatewayCustomModelForAdmission(tx, {
|
|
615
|
+
accountId: input.accountId,
|
|
616
|
+
workspaceId: input.workspaceId,
|
|
617
|
+
upstreamModelId: reference.upstreamModelId,
|
|
618
|
+
});
|
|
619
|
+
if (!active) {
|
|
620
|
+
throw new HTTPException(422, {
|
|
621
|
+
message: `model is not available: ${input.modelId}`,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
460
627
|
async function requireSource(
|
|
461
628
|
deps: ApiRouteDeps,
|
|
462
629
|
accountId: string,
|
|
@@ -3435,7 +3435,14 @@ async function ensureHeadedBrowserDisplayStack(
|
|
|
3435
3435
|
headless: boolean,
|
|
3436
3436
|
linkedComputer: boolean,
|
|
3437
3437
|
): Promise<void> {
|
|
3438
|
-
if (
|
|
3438
|
+
if (
|
|
3439
|
+
!browserNeedsStandaloneDisplayStack({
|
|
3440
|
+
headless,
|
|
3441
|
+
linkedComputer,
|
|
3442
|
+
nativeBrowserControl: typeof session.ensureBrowserControl === "function",
|
|
3443
|
+
})
|
|
3444
|
+
)
|
|
3445
|
+
return;
|
|
3439
3446
|
if (typeof session.exec !== "function" && typeof session.execCommand !== "function") return;
|
|
3440
3447
|
await ensureDisplayStack(session, {
|
|
3441
3448
|
telemetryContext: { callerKind: "viewer" },
|
|
@@ -3445,8 +3452,9 @@ async function ensureHeadedBrowserDisplayStack(
|
|
|
3445
3452
|
export function browserNeedsStandaloneDisplayStack(input: {
|
|
3446
3453
|
headless: boolean;
|
|
3447
3454
|
linkedComputer: boolean;
|
|
3455
|
+
nativeBrowserControl: boolean;
|
|
3448
3456
|
}): boolean {
|
|
3449
|
-
return !input.headless && !input.linkedComputer;
|
|
3457
|
+
return !input.headless && !input.linkedComputer && !input.nativeBrowserControl;
|
|
3450
3458
|
}
|
|
3451
3459
|
|
|
3452
3460
|
async function ensureLinkedComputerController(
|
|
@@ -32,7 +32,7 @@ export function registerCapabilityRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
32
32
|
|
|
33
33
|
app.post("/v1/workspaces/:workspaceId/capabilities", async (c) => {
|
|
34
34
|
const workspaceId = c.req.param("workspaceId");
|
|
35
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
35
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
36
36
|
const payload = CreateCapabilityCatalogItemRequest.parse(await c.req.json());
|
|
37
37
|
return c.json(
|
|
38
38
|
await createCatalogItem({ db, accountId: grant.accountId, workspaceId, payload }),
|
|
@@ -62,7 +62,7 @@ export function registerCapabilityRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
62
62
|
|
|
63
63
|
app.post("/v1/workspaces/:workspaceId/capabilities/:capabilityId/enable", async (c) => {
|
|
64
64
|
const workspaceId = c.req.param("workspaceId");
|
|
65
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
65
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
66
66
|
const payload = EnableCapabilityRequest.parse(await c.req.json());
|
|
67
67
|
const installation = await enableCapability({
|
|
68
68
|
db,
|
|
@@ -78,7 +78,7 @@ export function registerCapabilityRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
78
78
|
|
|
79
79
|
app.post("/v1/workspaces/:workspaceId/capabilities/:capabilityId/disable", async (c) => {
|
|
80
80
|
const workspaceId = c.req.param("workspaceId");
|
|
81
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
81
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
82
82
|
const installation = await disableCapability({
|
|
83
83
|
db,
|
|
84
84
|
accountId: grant.accountId,
|