@opengeni/core 0.12.7 → 0.14.3
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/access/index.d.ts +22 -0
- package/dist/application/new-session-drafts.d.ts +14 -0
- package/dist/application/session-commands.d.ts +107 -0
- package/dist/billing/limits.d.ts +29 -0
- package/dist/dependencies.d.ts +137 -0
- package/dist/domain/capabilities.d.ts +62 -0
- package/dist/domain/environments.d.ts +33 -0
- package/dist/domain/insights.d.ts +11 -0
- package/dist/domain/packs.d.ts +27 -0
- package/dist/domain/resources.d.ts +32 -0
- package/dist/domain/scheduled-tasks.d.ts +72 -0
- package/dist/domain/session-tool-policy.d.ts +31 -0
- package/dist/domain/sessions.d.ts +256 -0
- package/dist/domain/slack-bot.d.ts +19 -0
- package/dist/domain/workspace-members.d.ts +34 -0
- package/dist/index.d.ts +23 -1189
- package/dist/index.js +758 -115
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-type.d.ts +2 -0
- package/dist/rigs/index.d.ts +57 -0
- package/dist/sandbox/fleet.d.ts +197 -0
- package/dist/sandbox/routing.d.ts +55 -0
- package/dist/sandbox-types.d.ts +52 -0
- package/dist/session-authorization.d.ts +36 -0
- package/dist/transcription.d.ts +71 -0
- package/dist/workflow-wake-contract.d.ts +4 -0
- package/package.json +11 -11
- package/src/access/index.ts +73 -2
- package/src/application/new-session-drafts.ts +3 -0
- package/src/application/session-commands.ts +22 -9
- package/src/dependencies.ts +5 -0
- package/src/domain/insights.ts +480 -0
- package/src/domain/session-tool-policy.ts +22 -39
- package/src/domain/sessions.ts +140 -72
- package/src/domain/slack-bot.ts +2 -4
- package/src/index.ts +2 -0
- package/src/sandbox/fleet.ts +96 -33
- package/src/sandbox/routing.ts +29 -7
- package/src/transcription.ts +142 -0
package/dist/index.js
CHANGED
|
@@ -3,6 +3,79 @@ var SESSION_WORKFLOW_WAKE_DISPATCHER_SCHEDULE_ID = "opengeni-session-workflow-wa
|
|
|
3
3
|
var SESSION_WORKFLOW_WAKE_DISPATCHER_WORKFLOW_TYPE = "sessionWorkflowWakeDispatcherWorkflow";
|
|
4
4
|
var SESSION_WORKFLOW_WAKE_DISPATCHER_PERIOD_MS = 1e4;
|
|
5
5
|
|
|
6
|
+
// src/transcription.ts
|
|
7
|
+
var TranscriptionServiceError = class extends Error {
|
|
8
|
+
code;
|
|
9
|
+
status;
|
|
10
|
+
retryable;
|
|
11
|
+
constructor(input) {
|
|
12
|
+
super(input.message);
|
|
13
|
+
this.name = "TranscriptionServiceError";
|
|
14
|
+
this.code = input.code;
|
|
15
|
+
this.status = input.status ?? statusForVoiceInputError(input.code);
|
|
16
|
+
this.retryable = input.retryable ?? false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function statusForVoiceInputError(code) {
|
|
20
|
+
switch (code) {
|
|
21
|
+
case "permission_denied":
|
|
22
|
+
return 403;
|
|
23
|
+
case "policy_blocked":
|
|
24
|
+
return 403;
|
|
25
|
+
case "not_supported":
|
|
26
|
+
return 415;
|
|
27
|
+
case "unavailable":
|
|
28
|
+
return 503;
|
|
29
|
+
case "too_large":
|
|
30
|
+
return 413;
|
|
31
|
+
case "invalid_audio":
|
|
32
|
+
return 400;
|
|
33
|
+
case "timeout":
|
|
34
|
+
return 504;
|
|
35
|
+
case "cancelled":
|
|
36
|
+
return 499;
|
|
37
|
+
case "network":
|
|
38
|
+
case "provider":
|
|
39
|
+
return 502;
|
|
40
|
+
case "unknown":
|
|
41
|
+
default:
|
|
42
|
+
return 500;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function normalizeMimeType(mimeType) {
|
|
46
|
+
return mimeType.trim().toLowerCase();
|
|
47
|
+
}
|
|
48
|
+
function isAcceptedMimeType(mimeType, accepted) {
|
|
49
|
+
const normalized = normalizeMimeType(mimeType);
|
|
50
|
+
if (accepted.some((candidate) => normalizeMimeType(candidate) === normalized)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
const bare = normalized.split(";")[0]?.trim() ?? normalized;
|
|
54
|
+
return accepted.some((candidate) => {
|
|
55
|
+
const allowed = normalizeMimeType(candidate);
|
|
56
|
+
return allowed === bare || allowed.split(";")[0]?.trim() === bare;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function filenameForMimeType(mimeType) {
|
|
60
|
+
const bare = normalizeMimeType(mimeType).split(";")[0] ?? "audio/webm";
|
|
61
|
+
switch (bare) {
|
|
62
|
+
case "audio/mp4":
|
|
63
|
+
case "audio/m4a":
|
|
64
|
+
return "audio.mp4";
|
|
65
|
+
case "audio/ogg":
|
|
66
|
+
return "audio.ogg";
|
|
67
|
+
case "audio/mpeg":
|
|
68
|
+
case "audio/mp3":
|
|
69
|
+
return "audio.mp3";
|
|
70
|
+
case "audio/wav":
|
|
71
|
+
case "audio/x-wav":
|
|
72
|
+
return "audio.wav";
|
|
73
|
+
case "audio/webm":
|
|
74
|
+
default:
|
|
75
|
+
return "audio.webm";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
6
79
|
// src/sandbox/fleet.ts
|
|
7
80
|
import {
|
|
8
81
|
getEnrollment,
|
|
@@ -22,6 +95,7 @@ import {
|
|
|
22
95
|
import { HTTPException } from "hono/http-exception";
|
|
23
96
|
|
|
24
97
|
// src/sandbox/routing.ts
|
|
98
|
+
import { sandboxArchiveCaptureTimeoutMs } from "@opengeni/config";
|
|
25
99
|
import {
|
|
26
100
|
advanceWorkspaceGenerationForDirectRequest,
|
|
27
101
|
advanceWorkspaceGenerationForRetainedProcess,
|
|
@@ -40,7 +114,8 @@ import {
|
|
|
40
114
|
isProviderSandboxGoneDuringRoutedOperation,
|
|
41
115
|
makeActiveBackendResolver,
|
|
42
116
|
NatsControlRpc,
|
|
43
|
-
RoutingSandboxSession
|
|
117
|
+
RoutingSandboxSession,
|
|
118
|
+
resolveModalCheckpointProviderBindingForSession
|
|
44
119
|
} from "@opengeni/runtime/sandbox";
|
|
45
120
|
function relayConfigFromSettings(settings) {
|
|
46
121
|
const raw = settings.selfhostedRelayUrl?.trim();
|
|
@@ -94,7 +169,8 @@ function wrapChannelABoxWithRouting(services, ids, established) {
|
|
|
94
169
|
if (backend.activeEpoch === void 0) {
|
|
95
170
|
throw new Error("API-direct workspace mutation resolved without an active route epoch");
|
|
96
171
|
}
|
|
97
|
-
|
|
172
|
+
const providerBinding = homeLease.backend === "modal" ? await resolveModalCheckpointProviderBindingForSession(settings, backend.session) : null;
|
|
173
|
+
const admission = await advanceWorkspaceGenerationForDirectRequest(db, {
|
|
98
174
|
accountId: ids.accountId,
|
|
99
175
|
workspaceId: ids.workspaceId,
|
|
100
176
|
sessionId: ids.sessionId,
|
|
@@ -105,8 +181,10 @@ function wrapChannelABoxWithRouting(services, ids, established) {
|
|
|
105
181
|
expectedInstanceId: backend.providerInstanceId,
|
|
106
182
|
routeTargetId: backend.sandboxId,
|
|
107
183
|
routeEpoch: backend.activeEpoch,
|
|
108
|
-
operation: op
|
|
184
|
+
operation: op,
|
|
185
|
+
captureWaitMs: sandboxArchiveCaptureTimeoutMs(settings)
|
|
109
186
|
});
|
|
187
|
+
return { admission, providerBinding };
|
|
110
188
|
} : void 0;
|
|
111
189
|
const afterMutation = homeLease ? async ({
|
|
112
190
|
op,
|
|
@@ -116,10 +194,14 @@ function wrapChannelABoxWithRouting(services, ids, established) {
|
|
|
116
194
|
retainedProcess
|
|
117
195
|
}) => {
|
|
118
196
|
if (admission === null) return;
|
|
119
|
-
if (!admission || typeof admission !== "object" ||
|
|
197
|
+
if (!admission || typeof admission !== "object" || backend.leaseEpoch === void 0 || backend.providerInstanceId === void 0 || backend.activeEpoch === void 0) {
|
|
120
198
|
throw new Error("API-direct workspace mutation settlement lacked its exact admission");
|
|
121
199
|
}
|
|
122
|
-
const
|
|
200
|
+
const boundAdmission = admission;
|
|
201
|
+
const exactAdmission = boundAdmission.admission;
|
|
202
|
+
if (!exactAdmission || typeof exactAdmission.id !== "string" || typeof exactAdmission.workspaceGeneration !== "number" || !("providerBinding" in boundAdmission)) {
|
|
203
|
+
throw new Error("API-direct workspace mutation settlement lacked its bound admission");
|
|
204
|
+
}
|
|
123
205
|
if (outcome === "resolved" && retainedProcess) {
|
|
124
206
|
await retainWorkspaceMutationProcess(db, {
|
|
125
207
|
accountId: ids.accountId,
|
|
@@ -130,6 +212,7 @@ function wrapChannelABoxWithRouting(services, ids, established) {
|
|
|
130
212
|
admissionId: exactAdmission.id,
|
|
131
213
|
admittedWorkspaceGeneration: exactAdmission.workspaceGeneration,
|
|
132
214
|
operation: op,
|
|
215
|
+
providerBinding: boundAdmission.providerBinding ?? null,
|
|
133
216
|
owner: {
|
|
134
217
|
kind: "direct",
|
|
135
218
|
requestId: ids.directRequest.requestId,
|
|
@@ -167,7 +250,8 @@ function wrapChannelABoxWithRouting(services, ids, established) {
|
|
|
167
250
|
workspaceId: ids.workspaceId,
|
|
168
251
|
sessionId: ids.sessionId,
|
|
169
252
|
processId: process.id,
|
|
170
|
-
operation: op
|
|
253
|
+
operation: op,
|
|
254
|
+
captureWaitMs: sandboxArchiveCaptureTimeoutMs(settings)
|
|
171
255
|
}) : void 0;
|
|
172
256
|
const afterProcessMutation = homeLease ? async ({
|
|
173
257
|
op,
|
|
@@ -555,47 +639,37 @@ async function swapActiveSandbox(services, ctx, target, workingDir) {
|
|
|
555
639
|
await readinessHold?.release().catch(() => void 0);
|
|
556
640
|
}
|
|
557
641
|
}
|
|
558
|
-
async function
|
|
559
|
-
const sandbox = await getSandbox2(services.db, ctx.workspaceId, target);
|
|
560
|
-
if (!sandbox) {
|
|
561
|
-
return {
|
|
562
|
-
target,
|
|
563
|
-
kind: op.kind,
|
|
564
|
-
ok: false,
|
|
565
|
-
reason: `sandbox ${target} not found in this workspace`
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
if (sandbox.kind !== "selfhosted" || !sandbox.enrollmentId) {
|
|
569
|
-
return {
|
|
570
|
-
target,
|
|
571
|
-
kind: op.kind,
|
|
572
|
-
ok: false,
|
|
573
|
-
reason: `run_on routes one-off ops to enrolled selfhosted machines; ${sandbox.kind} targets are reached via the active sandbox (swap to it first)`
|
|
574
|
-
};
|
|
575
|
-
}
|
|
576
|
-
const enrollment = await getEnrollment(services.db, ctx.workspaceId, sandbox.enrollmentId);
|
|
577
|
-
if (!enrollment || enrollment.status !== "active") {
|
|
578
|
-
return { target, kind: op.kind, ok: false, reason: `sandbox ${target} is not enrolled/active` };
|
|
579
|
-
}
|
|
642
|
+
async function executeRunOnSelfhostedMachine(machine, target, op) {
|
|
580
643
|
const session = new SelfhostedSession({
|
|
581
|
-
workspaceId:
|
|
582
|
-
agentId:
|
|
583
|
-
controlRpc: controlRpc
|
|
584
|
-
relay:
|
|
644
|
+
workspaceId: machine.workspaceId,
|
|
645
|
+
agentId: machine.agentId,
|
|
646
|
+
controlRpc: machine.controlRpc,
|
|
647
|
+
relay: machine.relay,
|
|
648
|
+
timeoutMs: machine.controlTimeoutMs,
|
|
649
|
+
execTimeoutMs: machine.execTimeoutMs
|
|
585
650
|
});
|
|
586
651
|
try {
|
|
587
652
|
if (op.kind === "exec") {
|
|
653
|
+
const deadlineMs = session.effectiveExecDeadlineMs;
|
|
588
654
|
const res = await session.exec({
|
|
589
655
|
cmd: op.cmd,
|
|
590
656
|
...op.workdir ? { workdir: op.workdir } : {}
|
|
591
657
|
});
|
|
658
|
+
const timedOut = res.timedOut === true;
|
|
659
|
+
const hasTerminalExit = res.exitCode !== null;
|
|
592
660
|
return {
|
|
593
661
|
target,
|
|
594
662
|
kind: "exec",
|
|
595
|
-
ok
|
|
663
|
+
// `ok` means the one-off operation reached a terminal response. Preserve
|
|
664
|
+
// the established non-zero-exit behavior, but never claim success when
|
|
665
|
+
// the machine killed the child or returned no terminal exit proof.
|
|
666
|
+
ok: !timedOut && hasTerminalExit,
|
|
596
667
|
stdout: res.stdout,
|
|
597
668
|
stderr: res.stderr,
|
|
598
|
-
exitCode: res.exitCode
|
|
669
|
+
exitCode: res.exitCode,
|
|
670
|
+
timedOut,
|
|
671
|
+
deadlineMs,
|
|
672
|
+
...timedOut ? { reason: `command exceeded the ${deadlineMs} ms execution deadline` } : !hasTerminalExit ? { reason: "machine returned no terminal exit code" } : {}
|
|
599
673
|
};
|
|
600
674
|
}
|
|
601
675
|
if (op.kind === "read") {
|
|
@@ -606,8 +680,51 @@ async function runOnSandbox(services, ctx, target, op) {
|
|
|
606
680
|
return { target, kind: "write", ok: true, bytesWritten };
|
|
607
681
|
} catch (error) {
|
|
608
682
|
const reason = error instanceof Error ? error.message : String(error);
|
|
609
|
-
return {
|
|
683
|
+
return {
|
|
684
|
+
target,
|
|
685
|
+
kind: op.kind,
|
|
686
|
+
ok: false,
|
|
687
|
+
reason,
|
|
688
|
+
// A transport failure is not evidence that the process itself timed out,
|
|
689
|
+
// so leave `timedOut` absent while still reporting the enforced deadline.
|
|
690
|
+
...op.kind === "exec" ? { deadlineMs: session.effectiveExecDeadlineMs } : {}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
async function runOnSandbox(services, ctx, target, op) {
|
|
695
|
+
const sandbox = await getSandbox2(services.db, ctx.workspaceId, target);
|
|
696
|
+
if (!sandbox) {
|
|
697
|
+
return {
|
|
698
|
+
target,
|
|
699
|
+
kind: op.kind,
|
|
700
|
+
ok: false,
|
|
701
|
+
reason: `sandbox ${target} not found in this workspace`
|
|
702
|
+
};
|
|
610
703
|
}
|
|
704
|
+
if (sandbox.kind !== "selfhosted" || !sandbox.enrollmentId) {
|
|
705
|
+
return {
|
|
706
|
+
target,
|
|
707
|
+
kind: op.kind,
|
|
708
|
+
ok: false,
|
|
709
|
+
reason: `run_on routes one-off ops to enrolled selfhosted machines; ${sandbox.kind} targets are reached via the active sandbox (swap to it first)`
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
const enrollment = await getEnrollment(services.db, ctx.workspaceId, sandbox.enrollmentId);
|
|
713
|
+
if (!enrollment || enrollment.status !== "active") {
|
|
714
|
+
return { target, kind: op.kind, ok: false, reason: `sandbox ${target} is not enrolled/active` };
|
|
715
|
+
}
|
|
716
|
+
return executeRunOnSelfhostedMachine(
|
|
717
|
+
{
|
|
718
|
+
workspaceId: ctx.workspaceId,
|
|
719
|
+
agentId: sandbox.enrollmentId,
|
|
720
|
+
controlRpc: controlRpc(services.bus),
|
|
721
|
+
relay: relayConfigFromSettings(services.settings),
|
|
722
|
+
controlTimeoutMs: services.settings.sandboxSelfhostedControlTimeoutMs,
|
|
723
|
+
execTimeoutMs: services.settings.sandboxSelfhostedExecTimeoutMs
|
|
724
|
+
},
|
|
725
|
+
target,
|
|
726
|
+
op
|
|
727
|
+
);
|
|
611
728
|
}
|
|
612
729
|
async function provisionSandbox(services, ctx, input) {
|
|
613
730
|
if (input.kind === "selfhosted") {
|
|
@@ -660,8 +777,34 @@ async function requireAccessContext(c, deps) {
|
|
|
660
777
|
return context;
|
|
661
778
|
}
|
|
662
779
|
async function requireAccessGrant(c, deps, workspaceId, permission) {
|
|
780
|
+
return (await requireAccessGrantAuthorization(c, deps, workspaceId, permission)).grant;
|
|
781
|
+
}
|
|
782
|
+
function accessGrantAuthorizationFromContext(context, grant) {
|
|
783
|
+
const matchingAccountGrants = context.accountGrants.filter(
|
|
784
|
+
(candidate) => candidate.accountId === grant.accountId
|
|
785
|
+
);
|
|
786
|
+
const delegated = grant.metadata?.delegated === true;
|
|
787
|
+
const contextIntegrity = context.subjectId === grant.subjectId && context.accountGrants.every((candidate) => candidate.subjectId === context.subjectId) && context.workspaceGrants.every(
|
|
788
|
+
(candidate) => candidate.subjectId === context.subjectId && candidate.principalKind === grant.principalKind && candidate.metadata?.delegated === true === delegated && Boolean(candidate.serviceInitiator) === Boolean(grant.serviceInitiator) && Boolean(candidate.serviceInitiatorContext) === Boolean(grant.serviceInitiatorContext) && context.accountGrants.filter(
|
|
789
|
+
(accountGrant) => accountGrant.accountId === candidate.accountId
|
|
790
|
+
).length === 1
|
|
791
|
+
) && matchingAccountGrants.length === 1 && matchingAccountGrants[0]?.subjectId === context.subjectId;
|
|
792
|
+
return {
|
|
793
|
+
grant,
|
|
794
|
+
accountGrant: contextIntegrity ? matchingAccountGrants[0] : null,
|
|
795
|
+
authenticatedSubjectId: context.subjectId,
|
|
796
|
+
contextIntegrity
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
async function requireAccessGrantAuthorization(c, deps, workspaceId, permission) {
|
|
663
800
|
const context = await requireAccessContext(c, deps);
|
|
664
|
-
const
|
|
801
|
+
const principalKind = hostedHumanSessionPrincipalKind(context);
|
|
802
|
+
const grant = context.workspaceGrants.find((candidate) => candidate.workspaceId === workspaceId) ?? await getWorkspaceGrant(
|
|
803
|
+
deps.db,
|
|
804
|
+
context.subjectId,
|
|
805
|
+
workspaceId,
|
|
806
|
+
principalKind ? { principalKind } : void 0
|
|
807
|
+
);
|
|
665
808
|
if (!grant) {
|
|
666
809
|
const workspace = await requireWorkspace(deps.db, workspaceId).catch(() => null);
|
|
667
810
|
if (!workspace) {
|
|
@@ -672,7 +815,15 @@ async function requireAccessGrant(c, deps, workspaceId, permission) {
|
|
|
672
815
|
if (permission) {
|
|
673
816
|
requirePermission(grant, permission);
|
|
674
817
|
}
|
|
675
|
-
return grant;
|
|
818
|
+
return accessGrantAuthorizationFromContext(context, grant);
|
|
819
|
+
}
|
|
820
|
+
function hostedHumanSessionPrincipalKind(context) {
|
|
821
|
+
if (context.mode !== "managed" || context.workspaceGrants.length === 0) {
|
|
822
|
+
return void 0;
|
|
823
|
+
}
|
|
824
|
+
return context.workspaceGrants.every(
|
|
825
|
+
(grant) => grant.principalKind === "human_session" && grant.metadata?.delegated !== true && !grant.serviceInitiator
|
|
826
|
+
) ? "human_session" : void 0;
|
|
676
827
|
}
|
|
677
828
|
function requirePermission(grant, permission) {
|
|
678
829
|
if (!hasPermission(grant.permissions, permission)) {
|
|
@@ -790,7 +941,8 @@ async function apiKeyAccessContext(c, deps, mode) {
|
|
|
790
941
|
accountId: apiKey.accountId,
|
|
791
942
|
subjectId,
|
|
792
943
|
subjectLabel: apiKey.name,
|
|
793
|
-
permissions: apiKey.permissions
|
|
944
|
+
permissions: apiKey.permissions,
|
|
945
|
+
principalKind: "api_key"
|
|
794
946
|
}
|
|
795
947
|
] : [],
|
|
796
948
|
defaultAccountId: apiKey.accountId,
|
|
@@ -824,6 +976,7 @@ async function delegatedAccessContext(c, deps, mode, token = bearerToken(c)) {
|
|
|
824
976
|
subjectId: payload.subjectId,
|
|
825
977
|
...payload.subjectLabel ? { subjectLabel: payload.subjectLabel } : {},
|
|
826
978
|
permissions: payload.permissions,
|
|
979
|
+
principalKind: payload.principalKind,
|
|
827
980
|
// sessionId is worker-asserted (HMAC-signed token claim), not agent
|
|
828
981
|
// controlled; it scopes session-bound MCP tools such as goal management.
|
|
829
982
|
metadata: {
|
|
@@ -3241,6 +3394,10 @@ var PROJECTABLE_REGISTRY_ID = /^[A-Za-z0-9_-]+$/;
|
|
|
3241
3394
|
function sortedIds(ids) {
|
|
3242
3395
|
return [...new Set(ids)].sort();
|
|
3243
3396
|
}
|
|
3397
|
+
function defaultSessionMcpServerIds(servers) {
|
|
3398
|
+
const mandatory = new Set(MANDATORY_SESSION_MCP_SERVER_IDS);
|
|
3399
|
+
return sortedIds([...servers].map((server) => server.id).filter((id) => !mandatory.has(id)));
|
|
3400
|
+
}
|
|
3244
3401
|
function projectIds(ids) {
|
|
3245
3402
|
const projectable = ids.filter(
|
|
3246
3403
|
(id) => id.length <= SESSION_EFFECTIVE_TOOL_POLICY_ID_MAX_LENGTH && PROJECTABLE_REGISTRY_ID.test(id)
|
|
@@ -3251,16 +3408,16 @@ function projectIds(ids) {
|
|
|
3251
3408
|
};
|
|
3252
3409
|
}
|
|
3253
3410
|
function resolveSessionToolPolicy(input) {
|
|
3254
|
-
const policy = input.toolPolicy
|
|
3411
|
+
const policy = input.toolPolicy;
|
|
3255
3412
|
const availableIds = new Set(input.availableMcpServerIds);
|
|
3256
3413
|
const defaultIds = new Set(input.defaultMcpServerIds ?? []);
|
|
3257
3414
|
const mandatoryIds = MANDATORY_SESSION_MCP_SERVER_IDS.filter(
|
|
3258
3415
|
(id) => availableIds.has(id)
|
|
3259
3416
|
);
|
|
3260
3417
|
const mandatoryIdSet = new Set(mandatoryIds);
|
|
3261
|
-
const selectedRefs =
|
|
3262
|
-
const tracksWorkspaceDefaults = policy.mode === "workspace_default"
|
|
3263
|
-
let toolRefs = selectedRefs.filter((tool) =>
|
|
3418
|
+
const selectedRefs = mergeToolRefs2([], input.sessionTools);
|
|
3419
|
+
const tracksWorkspaceDefaults = policy.mode === "workspace_default";
|
|
3420
|
+
let toolRefs = selectedRefs.filter((tool) => availableIds.has(tool.id));
|
|
3264
3421
|
if (tracksWorkspaceDefaults) {
|
|
3265
3422
|
toolRefs = mergeToolRefs2(
|
|
3266
3423
|
toolRefs,
|
|
@@ -3326,16 +3483,13 @@ function resolveSessionToolPolicy(input) {
|
|
|
3326
3483
|
}
|
|
3327
3484
|
};
|
|
3328
3485
|
}
|
|
3329
|
-
function sessionToolPolicyAllowsDefaultNativeTools(policy) {
|
|
3330
|
-
return policy.mode === "workspace_default" && policy.lazyRouter.state === "required";
|
|
3331
|
-
}
|
|
3332
3486
|
async function workspaceSessionToolPolicyServerIds(db, workspaceId, settings) {
|
|
3333
3487
|
const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
|
|
3334
3488
|
return sortedIds(runtimeSettings.mcpServers.map((server) => server.id));
|
|
3335
3489
|
}
|
|
3336
3490
|
async function workspaceSessionToolPolicyDefaultServerIds(db, workspaceId, settings) {
|
|
3337
3491
|
const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
|
|
3338
|
-
return
|
|
3492
|
+
return defaultSessionMcpServerIds(runtimeSettings.mcpServers);
|
|
3339
3493
|
}
|
|
3340
3494
|
function sessionWithEffectiveToolPolicy(session, workspaceServerIds, workspaceDefaultServerIds = []) {
|
|
3341
3495
|
const availableIds = new Set(workspaceServerIds);
|
|
@@ -3345,7 +3499,7 @@ function sessionWithEffectiveToolPolicy(session, workspaceServerIds, workspaceDe
|
|
|
3345
3499
|
return {
|
|
3346
3500
|
...session,
|
|
3347
3501
|
effectiveToolPolicy: resolveSessionToolPolicy({
|
|
3348
|
-
|
|
3502
|
+
toolPolicy: session.toolPolicy,
|
|
3349
3503
|
sessionTools: session.tools,
|
|
3350
3504
|
availableMcpServerIds: availableIds,
|
|
3351
3505
|
defaultMcpServerIds: workspaceDefaultServerIds
|
|
@@ -3367,7 +3521,7 @@ import {
|
|
|
3367
3521
|
import { HTTPException as HTTPException11 } from "hono/http-exception";
|
|
3368
3522
|
|
|
3369
3523
|
// src/domain/sessions.ts
|
|
3370
|
-
import { CODEX_MODEL_ID_PREFIX } from "@opengeni/codex";
|
|
3524
|
+
import { CODEX_MODEL_ID_PREFIX, isCodexBilledModel } from "@opengeni/codex";
|
|
3371
3525
|
import {
|
|
3372
3526
|
canonicalizeConfiguredModelId,
|
|
3373
3527
|
configuredAllowedModels,
|
|
@@ -3378,11 +3532,13 @@ import {
|
|
|
3378
3532
|
CreateSessionRequest,
|
|
3379
3533
|
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
3380
3534
|
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
3535
|
+
FIRST_PARTY_MCP_TOOL_NAMES,
|
|
3381
3536
|
OPENGENI_SLACK_BOT_SESSION_METADATA_KEY as OPENGENI_SLACK_BOT_SESSION_METADATA_KEY2,
|
|
3382
3537
|
SessionSpawnDenial,
|
|
3383
3538
|
ServiceTurnInitiator,
|
|
3384
3539
|
ServiceTurnInitiatorContext,
|
|
3385
3540
|
evaluateWorkspaceModelPolicy,
|
|
3541
|
+
latencyModeForMetadata,
|
|
3386
3542
|
reasoningEffortForMetadata,
|
|
3387
3543
|
stableJson as stableJson2,
|
|
3388
3544
|
SessionMcpApprovalPolicy
|
|
@@ -3430,10 +3586,10 @@ import { HTTPException as HTTPException10 } from "hono/http-exception";
|
|
|
3430
3586
|
// src/domain/slack-bot.ts
|
|
3431
3587
|
import {
|
|
3432
3588
|
OPENGENI_SLACK_BOT_CREDENTIAL_LABEL,
|
|
3433
|
-
OPENGENI_SLACK_BOT_REQUIRED_SCOPES,
|
|
3434
3589
|
OPENGENI_SLACK_BOT_CREDENTIAL_ROLE,
|
|
3435
3590
|
OPENGENI_SLACK_BOT_SESSION_METADATA_KEY,
|
|
3436
|
-
OpenGeniSlackBotConnectionMetadata
|
|
3591
|
+
OpenGeniSlackBotConnectionMetadata,
|
|
3592
|
+
areOpenGeniSlackBotScopesAccepted
|
|
3437
3593
|
} from "@opengeni/contracts";
|
|
3438
3594
|
import {
|
|
3439
3595
|
getConnectionMetadata as getConnectionMetadata2
|
|
@@ -3444,8 +3600,7 @@ function openGeniSlackBotMetadata(metadata) {
|
|
|
3444
3600
|
return parsed.success ? parsed.data : null;
|
|
3445
3601
|
}
|
|
3446
3602
|
function isOpenGeniSlackBotConnection(connection) {
|
|
3447
|
-
|
|
3448
|
-
return connection.verifiedInstallAt != null && connection.verifiedInstallVersion === connection.version && connection.subjectId === null && connection.providerDomain === "slack.com" && connection.kind === "app_install" && granted.size === OPENGENI_SLACK_BOT_REQUIRED_SCOPES.length && OPENGENI_SLACK_BOT_REQUIRED_SCOPES.every((scope) => granted.has(scope)) && openGeniSlackBotMetadata(connection.metadata)?.credentialRole === OPENGENI_SLACK_BOT_CREDENTIAL_ROLE;
|
|
3603
|
+
return connection.verifiedInstallAt != null && connection.verifiedInstallVersion === connection.version && connection.subjectId === null && connection.providerDomain === "slack.com" && connection.kind === "app_install" && areOpenGeniSlackBotScopesAccepted(connection.grantedScopes) && openGeniSlackBotMetadata(connection.metadata)?.credentialRole === OPENGENI_SLACK_BOT_CREDENTIAL_ROLE;
|
|
3449
3604
|
}
|
|
3450
3605
|
function hasReservedOpenGeniSlackBotMetadata(metadata) {
|
|
3451
3606
|
return metadata?.credentialRole === OPENGENI_SLACK_BOT_CREDENTIAL_ROLE || metadata?.credentialLabel === OPENGENI_SLACK_BOT_CREDENTIAL_LABEL;
|
|
@@ -3502,7 +3657,7 @@ var SessionSpawnDeniedError = class extends Error {
|
|
|
3502
3657
|
};
|
|
3503
3658
|
function resolveFirstPartyMcpToolsForCreate(requested, parentStored) {
|
|
3504
3659
|
if (requested !== void 0) return [...requested];
|
|
3505
|
-
if (parentStored === void 0) return
|
|
3660
|
+
if (parentStored === void 0) return [...DEFAULT_FIRST_PARTY_MCP_TOOLS];
|
|
3506
3661
|
return [...parentStored ?? DEFAULT_FIRST_PARTY_MCP_TOOLS];
|
|
3507
3662
|
}
|
|
3508
3663
|
function sessionSpawnDeniedMessage(denial) {
|
|
@@ -3786,7 +3941,8 @@ async function createAndStartSession(input) {
|
|
|
3786
3941
|
const sessionMetadata = {
|
|
3787
3942
|
...input.metadata,
|
|
3788
3943
|
model: input.model,
|
|
3789
|
-
reasoningEffort: input.reasoningEffort
|
|
3944
|
+
reasoningEffort: input.reasoningEffort,
|
|
3945
|
+
...input.latencyMode !== void 0 ? { latencyMode: input.latencyMode } : {}
|
|
3790
3946
|
};
|
|
3791
3947
|
if (input.createIdempotencyKey) {
|
|
3792
3948
|
const keyedResult = await createSessionWithIdempotencyKeyResult(input.db, {
|
|
@@ -3798,7 +3954,7 @@ async function createAndStartSession(input) {
|
|
|
3798
3954
|
resources: input.resources,
|
|
3799
3955
|
skills: input.skills ?? [],
|
|
3800
3956
|
tools: input.tools,
|
|
3801
|
-
|
|
3957
|
+
toolPolicy: input.toolPolicy,
|
|
3802
3958
|
metadata: sessionMetadata,
|
|
3803
3959
|
...input.createdBy ? { createdBy: input.createdBy } : {},
|
|
3804
3960
|
...input.createdByContext ? { createdByContext: input.createdByContext } : {},
|
|
@@ -3809,7 +3965,7 @@ async function createAndStartSession(input) {
|
|
|
3809
3965
|
rigId: input.rigId ?? null,
|
|
3810
3966
|
rigVersionId: input.rigVersionId ?? null,
|
|
3811
3967
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
3812
|
-
firstPartyMcpTools: input.firstPartyMcpTools
|
|
3968
|
+
firstPartyMcpTools: input.firstPartyMcpTools,
|
|
3813
3969
|
instructions: input.instructions ?? null,
|
|
3814
3970
|
parentSessionId: input.parentSessionId ?? null,
|
|
3815
3971
|
createIdempotencyKey: input.createIdempotencyKey,
|
|
@@ -3843,7 +3999,7 @@ async function createAndStartSession(input) {
|
|
|
3843
3999
|
resources: input.resources,
|
|
3844
4000
|
skills: input.skills ?? [],
|
|
3845
4001
|
tools: input.tools,
|
|
3846
|
-
|
|
4002
|
+
toolPolicy: input.toolPolicy,
|
|
3847
4003
|
metadata: sessionMetadata,
|
|
3848
4004
|
...input.createdBy ? { createdBy: input.createdBy } : {},
|
|
3849
4005
|
...input.createdByContext ? { createdByContext: input.createdByContext } : {},
|
|
@@ -3854,7 +4010,7 @@ async function createAndStartSession(input) {
|
|
|
3854
4010
|
rigId: input.rigId ?? null,
|
|
3855
4011
|
rigVersionId: input.rigVersionId ?? null,
|
|
3856
4012
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
3857
|
-
firstPartyMcpTools: input.firstPartyMcpTools
|
|
4013
|
+
firstPartyMcpTools: input.firstPartyMcpTools,
|
|
3858
4014
|
instructions: input.instructions ?? null,
|
|
3859
4015
|
parentSessionId: input.parentSessionId ?? null,
|
|
3860
4016
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
@@ -3908,7 +4064,7 @@ async function finishStartSession(input, session) {
|
|
|
3908
4064
|
reasoningEffortFallback: input.reasoningEffort,
|
|
3909
4065
|
turnExecutionPolicy: input.turnExecutionPolicy,
|
|
3910
4066
|
createdEventPayload: {
|
|
3911
|
-
|
|
4067
|
+
toolPolicy: input.toolPolicy,
|
|
3912
4068
|
...input.variableSet ? { variableSetId: input.variableSet.id, variableSetName: input.variableSet.name } : {},
|
|
3913
4069
|
...input.sessionMcpServers?.length ? { mcpServers: input.sessionMcpServers } : {}
|
|
3914
4070
|
},
|
|
@@ -3952,6 +4108,24 @@ function canonicalConfiguredModel(settings, model) {
|
|
|
3952
4108
|
function assertConfiguredModel(settings, model) {
|
|
3953
4109
|
canonicalConfiguredModel(settings, model);
|
|
3954
4110
|
}
|
|
4111
|
+
var CODEX_COMPACTION_V2_PROVIDER_LOCKED = "codex_compaction_v2_provider_locked";
|
|
4112
|
+
var CodexCompactionV2ProviderLockedError = class extends Error {
|
|
4113
|
+
code = CODEX_COMPACTION_V2_PROVIDER_LOCKED;
|
|
4114
|
+
productModelId;
|
|
4115
|
+
constructor(productModelId) {
|
|
4116
|
+
super(
|
|
4117
|
+
`session is locked to Codex remote compaction v2; model "${productModelId}" is not a Codex subscription model`
|
|
4118
|
+
);
|
|
4119
|
+
this.name = "CodexCompactionV2ProviderLockedError";
|
|
4120
|
+
this.productModelId = productModelId;
|
|
4121
|
+
}
|
|
4122
|
+
};
|
|
4123
|
+
function assertSessionAllowsProductModel(session, productModelId) {
|
|
4124
|
+
if (productModelId === null || productModelId === void 0) return;
|
|
4125
|
+
if (session.codexCompactionMode !== "remote_v2") return;
|
|
4126
|
+
if (isCodexBilledModel(productModelId)) return;
|
|
4127
|
+
throw new CodexCompactionV2ProviderLockedError(productModelId);
|
|
4128
|
+
}
|
|
3955
4129
|
async function assertWorkspaceModelPolicyAllows(db, settings, workspaceId, model) {
|
|
3956
4130
|
if (model === null || model === void 0) {
|
|
3957
4131
|
return;
|
|
@@ -3990,12 +4164,25 @@ async function requireQueuedTurnForApi(db, workspaceId, sessionId, turnId) {
|
|
|
3990
4164
|
function reasoningEffortForSession(metadata, fallback) {
|
|
3991
4165
|
return reasoningEffortForMetadata(metadata, fallback);
|
|
3992
4166
|
}
|
|
4167
|
+
function latencyModeForSession(metadata, fallback = "standard") {
|
|
4168
|
+
return latencyModeForMetadata(metadata, fallback);
|
|
4169
|
+
}
|
|
3993
4170
|
async function postUserMessageTurn(input) {
|
|
3994
4171
|
const { db, bus, workflowClient, settings, accountId, workspaceId, sessionId } = input;
|
|
3995
4172
|
const requestedModel = canonicalConfiguredModel(settings, input.model ?? null) ?? null;
|
|
3996
4173
|
const requestedReasoningEffort = input.reasoningEffort ?? null;
|
|
3997
4174
|
assertConfiguredModel(settings, requestedModel);
|
|
3998
4175
|
await assertWorkspaceModelPolicyAllows(db, settings, workspaceId, requestedModel);
|
|
4176
|
+
const sessionForModelGate = await requireSession2(db, workspaceId, sessionId);
|
|
4177
|
+
const effectiveModelForGate = requestedModel ?? sessionForModelGate.model;
|
|
4178
|
+
try {
|
|
4179
|
+
assertSessionAllowsProductModel(sessionForModelGate, effectiveModelForGate);
|
|
4180
|
+
} catch (error) {
|
|
4181
|
+
if (error instanceof CodexCompactionV2ProviderLockedError) {
|
|
4182
|
+
throw new HTTPException10(422, { message: error.message, cause: error });
|
|
4183
|
+
}
|
|
4184
|
+
throw error;
|
|
4185
|
+
}
|
|
3999
4186
|
const operationKey = input.clientEventId ?? crypto.randomUUID();
|
|
4000
4187
|
let result;
|
|
4001
4188
|
try {
|
|
@@ -4021,10 +4208,9 @@ async function postUserMessageTurn(input) {
|
|
|
4021
4208
|
text: input.text,
|
|
4022
4209
|
turnInstructions: input.turnInstructions ?? null,
|
|
4023
4210
|
resources: input.resources,
|
|
4024
|
-
tools: input.tools,
|
|
4025
|
-
toolsProvided: input.toolsProvided,
|
|
4026
4211
|
model: requestedModel,
|
|
4027
4212
|
reasoningEffort: requestedReasoningEffort,
|
|
4213
|
+
latencyMode: input.latencyMode ?? null,
|
|
4028
4214
|
reasoningEffortFallback: input.reasoningEffortFallback ?? settings.openaiReasoningEffort,
|
|
4029
4215
|
turnExecutionPolicy: input.turnExecutionPolicy,
|
|
4030
4216
|
source: input.origin === "operator" ? "api" : "user",
|
|
@@ -4215,12 +4401,15 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
4215
4401
|
}
|
|
4216
4402
|
await assertWorkspaceModelPolicyAllows(db, settings, workspaceId, model);
|
|
4217
4403
|
const reasoningEffort = payload.reasoningEffort ?? settings.openaiReasoningEffort;
|
|
4404
|
+
const latencyMode = payload.latencyMode ?? "standard";
|
|
4218
4405
|
const turnExecutionPolicy = resolveTurnExecutionPolicyV1(settings, {
|
|
4219
4406
|
modelId: model,
|
|
4220
4407
|
requestedModelId: payload.model ?? null,
|
|
4221
4408
|
modelSource: payload.model === void 0 ? "deployment" : "explicit",
|
|
4222
4409
|
reasoningEffort,
|
|
4223
|
-
reasoningSource: payload.reasoningEffort === void 0 ? "deployment" : "explicit"
|
|
4410
|
+
reasoningSource: payload.reasoningEffort === void 0 ? "deployment" : "explicit",
|
|
4411
|
+
latencyMode,
|
|
4412
|
+
latencyModeSource: payload.latencyMode === void 0 ? "deployment" : "explicit"
|
|
4224
4413
|
});
|
|
4225
4414
|
const parentFirstPartyMcpPermissions = parentSession ? [...parentSession.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS] : null;
|
|
4226
4415
|
if (parentFirstPartyMcpPermissions && payload.firstPartyMcpPermissions?.some(
|
|
@@ -4255,9 +4444,8 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
4255
4444
|
parentSession ? parentSession.firstPartyMcpTools : void 0
|
|
4256
4445
|
);
|
|
4257
4446
|
if (payload.goal) {
|
|
4258
|
-
const effectiveTools = firstPartyMcpTools ?? [...DEFAULT_FIRST_PARTY_MCP_TOOLS];
|
|
4259
4447
|
const missingGoalTools = ["goal_update", "goal_complete", "goal_pause"].filter(
|
|
4260
|
-
(name) => !
|
|
4448
|
+
(name) => !firstPartyMcpTools.includes(name)
|
|
4261
4449
|
);
|
|
4262
4450
|
if (missingGoalTools.length > 0) {
|
|
4263
4451
|
throw new HTTPException10(422, {
|
|
@@ -4385,6 +4573,7 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
4385
4573
|
...payload.clientEventId ? { clientEventId: payload.clientEventId } : {},
|
|
4386
4574
|
model,
|
|
4387
4575
|
reasoningEffort,
|
|
4576
|
+
latencyMode,
|
|
4388
4577
|
turnExecutionPolicy,
|
|
4389
4578
|
// A shared spawn inherits the box's backend; a caller-supplied
|
|
4390
4579
|
// sandboxBackend on a shared spawn is ignored (it is the same box). A
|
|
@@ -4458,61 +4647,43 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
4458
4647
|
return session;
|
|
4459
4648
|
}
|
|
4460
4649
|
async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, input) {
|
|
4461
|
-
if (input.toolsProvided && !deps.settings.sessionTurnToolReplacementEnabled) {
|
|
4462
|
-
throw new HTTPException10(503, {
|
|
4463
|
-
message: "explicit follow-up tool replacement is temporarily unavailable until provenance-aware turn workers finish rolling out; omit tools to inherit the session policy and retry"
|
|
4464
|
-
});
|
|
4465
|
-
}
|
|
4466
4650
|
const { settings, db, bus, workflowClient, objectStorage } = deps;
|
|
4467
4651
|
await requireSessionAuthorization(deps, grant, {
|
|
4468
4652
|
sessionId,
|
|
4469
4653
|
operation: input.delivery === "steer" ? "session.steer" : "session.append",
|
|
4470
4654
|
surface: "core"
|
|
4471
4655
|
});
|
|
4472
|
-
const capabilityRuntimeSettings = await settingsWithEnabledCapabilityMcpServers(
|
|
4473
|
-
db,
|
|
4474
|
-
workspaceId,
|
|
4475
|
-
settings
|
|
4476
|
-
);
|
|
4477
4656
|
const existingSession = await requireSession2(db, workspaceId, sessionId);
|
|
4478
4657
|
const requestedModel = canonicalConfiguredModel(settings, input.model ?? null) ?? null;
|
|
4479
4658
|
const effectiveModel = canonicalConfiguredModel(settings, requestedModel ?? existingSession.model) ?? null;
|
|
4480
4659
|
if (effectiveModel === null) {
|
|
4481
4660
|
throw new Error("effective follow-up model unexpectedly resolved to null");
|
|
4482
4661
|
}
|
|
4662
|
+
try {
|
|
4663
|
+
assertSessionAllowsProductModel(existingSession, effectiveModel);
|
|
4664
|
+
} catch (error) {
|
|
4665
|
+
if (error instanceof CodexCompactionV2ProviderLockedError) {
|
|
4666
|
+
throw new HTTPException10(422, { message: error.message, cause: error });
|
|
4667
|
+
}
|
|
4668
|
+
throw error;
|
|
4669
|
+
}
|
|
4483
4670
|
const sessionReasoningEffort = reasoningEffortForSession(
|
|
4484
4671
|
existingSession.metadata,
|
|
4485
4672
|
settings.openaiReasoningEffort
|
|
4486
4673
|
);
|
|
4487
4674
|
const effectiveReasoningEffort = input.reasoningEffort ?? sessionReasoningEffort;
|
|
4675
|
+
const sessionLatencyMode = latencyModeForSession(existingSession.metadata, "standard");
|
|
4676
|
+
const effectiveLatencyMode = input.latencyMode ?? sessionLatencyMode;
|
|
4488
4677
|
const turnExecutionPolicy = resolveTurnExecutionPolicyV1(settings, {
|
|
4489
4678
|
modelId: effectiveModel,
|
|
4490
4679
|
requestedModelId: input.model ?? null,
|
|
4491
4680
|
modelSource: input.model == null ? "session" : "explicit",
|
|
4492
4681
|
reasoningEffort: effectiveReasoningEffort,
|
|
4493
|
-
reasoningSource: input.reasoningEffort == null ? "session" : "explicit"
|
|
4682
|
+
reasoningSource: input.reasoningEffort == null ? "session" : "explicit",
|
|
4683
|
+
latencyMode: effectiveLatencyMode,
|
|
4684
|
+
latencyModeSource: input.latencyMode == null ? "session" : "explicit"
|
|
4494
4685
|
});
|
|
4495
|
-
const runtimeSettings = settingsWithSessionMcpServerMetadata(
|
|
4496
|
-
capabilityRuntimeSettings,
|
|
4497
|
-
existingSession.mcpServers
|
|
4498
|
-
);
|
|
4499
4686
|
const requestedResources = normalizeResources(input.resources ?? []);
|
|
4500
|
-
const tracksWorkspaceDefaults = existingSession.toolPolicy?.mode === "workspace_default";
|
|
4501
|
-
const sessionPolicyTools = withFirstPartyTools(
|
|
4502
|
-
tracksWorkspaceDefaults ? withDefaultEnabledCapabilityMcpTools(
|
|
4503
|
-
availableToolRefs(existingSession.tools, runtimeSettings),
|
|
4504
|
-
settings,
|
|
4505
|
-
capabilityRuntimeSettings
|
|
4506
|
-
) : existingSession.tools,
|
|
4507
|
-
runtimeSettings
|
|
4508
|
-
);
|
|
4509
|
-
const validatedTools = input.toolsProvided ? validateToolRefsForSessionPolicy({
|
|
4510
|
-
requested: input.tools ?? [],
|
|
4511
|
-
settings: runtimeSettings,
|
|
4512
|
-
allowedTools: sessionPolicyTools,
|
|
4513
|
-
message: "message tools may only narrow the session tool policy"
|
|
4514
|
-
}) : [];
|
|
4515
|
-
const requestedTools = input.toolsProvided ? validatedTools : [];
|
|
4516
4687
|
await requireLimit(deps, {
|
|
4517
4688
|
accountId: grant.accountId,
|
|
4518
4689
|
workspaceId,
|
|
@@ -4546,10 +4717,9 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
|
|
|
4546
4717
|
text: input.text,
|
|
4547
4718
|
turnInstructions: input.turnInstructions ?? null,
|
|
4548
4719
|
resources: requestedResources,
|
|
4549
|
-
tools: requestedTools,
|
|
4550
|
-
toolsProvided: input.toolsProvided,
|
|
4551
4720
|
model: input.model ?? null,
|
|
4552
4721
|
reasoningEffort: input.reasoningEffort ?? null,
|
|
4722
|
+
latencyMode: input.latencyMode ?? null,
|
|
4553
4723
|
reasoningEffortFallback: sessionReasoningEffort,
|
|
4554
4724
|
turnExecutionPolicy,
|
|
4555
4725
|
mcpCredentialUpdates,
|
|
@@ -4654,7 +4824,7 @@ async function updateSessionMcpApprovalPolicy(deps, grant, sessionId, serverId,
|
|
|
4654
4824
|
effectiveFrom: "next_attempt"
|
|
4655
4825
|
};
|
|
4656
4826
|
}
|
|
4657
|
-
function toolPolicyAuditSnapshot(session, tools, policy = session.toolPolicy
|
|
4827
|
+
function toolPolicyAuditSnapshot(session, tools, firstPartyMcpTools, policy = session.toolPolicy) {
|
|
4658
4828
|
const allToolRefs = mergeToolRefs([], tools).sort((left, right) => {
|
|
4659
4829
|
const leftMandatory = left.kind === "mcp" && left.id === "opengeni";
|
|
4660
4830
|
const rightMandatory = right.kind === "mcp" && right.id === "opengeni";
|
|
@@ -4673,6 +4843,8 @@ function toolPolicyAuditSnapshot(session, tools, policy = session.toolPolicy ??
|
|
|
4673
4843
|
toolIds: [...toolRefs].sort((left, right) => `${left.kind}:${left.id}`.localeCompare(`${right.kind}:${right.id}`)).map((tool) => tool.id),
|
|
4674
4844
|
toolRefs,
|
|
4675
4845
|
toolCount: allToolRefs.length,
|
|
4846
|
+
firstPartyMcpTools: [...firstPartyMcpTools].sort(),
|
|
4847
|
+
firstPartyMcpToolCount: firstPartyMcpTools.length,
|
|
4676
4848
|
truncated: allToolRefs.length > toolRefs.length
|
|
4677
4849
|
};
|
|
4678
4850
|
}
|
|
@@ -4706,10 +4878,12 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4706
4878
|
}
|
|
4707
4879
|
return withFirstPartyTools(validatedTools, runtimeSettings);
|
|
4708
4880
|
})() : null;
|
|
4881
|
+
const explicitRequestedFirstPartyTools = explicitRequest ? [...explicitRequest.firstPartyMcpTools] : null;
|
|
4709
4882
|
const workspaceDefaultTools = withFirstPartyTools(
|
|
4710
4883
|
withDefaultEnabledCapabilityMcpTools([], deps.settings, capabilityRuntimeSettings),
|
|
4711
4884
|
runtimeSettings
|
|
4712
4885
|
);
|
|
4886
|
+
const workspaceDefaultFirstPartyTools = [...FIRST_PARTY_MCP_TOOL_NAMES];
|
|
4713
4887
|
const events = await appendSessionEventsWithLockedSessionUpdate(
|
|
4714
4888
|
deps.db,
|
|
4715
4889
|
grant.workspaceId,
|
|
@@ -4720,6 +4894,7 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4720
4894
|
throw new SessionToolPolicyVersionConflictError(currentVersion);
|
|
4721
4895
|
}
|
|
4722
4896
|
let nextTools;
|
|
4897
|
+
let nextFirstPartyMcpTools;
|
|
4723
4898
|
let nextPolicy;
|
|
4724
4899
|
if (session.parentSessionId) {
|
|
4725
4900
|
const parent = await context.getLockedSession(session.parentSessionId);
|
|
@@ -4735,6 +4910,9 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4735
4910
|
) : parent.tools,
|
|
4736
4911
|
runtimeSettings
|
|
4737
4912
|
);
|
|
4913
|
+
const parentFirstPartyMcpTools = [
|
|
4914
|
+
...parent.firstPartyMcpTools ?? DEFAULT_FIRST_PARTY_MCP_TOOLS
|
|
4915
|
+
];
|
|
4738
4916
|
if (requestedMode === "workspace_default") {
|
|
4739
4917
|
if (!parentTracksWorkspaceDefaults) {
|
|
4740
4918
|
throw new HTTPException10(403, {
|
|
@@ -4742,6 +4920,7 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4742
4920
|
});
|
|
4743
4921
|
}
|
|
4744
4922
|
nextTools = parentEffective;
|
|
4923
|
+
nextFirstPartyMcpTools = parentFirstPartyMcpTools;
|
|
4745
4924
|
nextPolicy = {
|
|
4746
4925
|
mode: "workspace_default",
|
|
4747
4926
|
inheritedFromSessionId: parent.id
|
|
@@ -4753,6 +4932,16 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4753
4932
|
parentEffective,
|
|
4754
4933
|
"session tools may only narrow the parent session tool policy"
|
|
4755
4934
|
);
|
|
4935
|
+
const parentFirstPartySet = new Set(parentFirstPartyMcpTools);
|
|
4936
|
+
const widenedFirstPartyTool = explicitRequestedFirstPartyTools.find(
|
|
4937
|
+
(tool) => !parentFirstPartySet.has(tool)
|
|
4938
|
+
);
|
|
4939
|
+
if (widenedFirstPartyTool) {
|
|
4940
|
+
throw new HTTPException10(403, {
|
|
4941
|
+
message: `session OpenGeni tools may only narrow the parent policy: ${widenedFirstPartyTool}`
|
|
4942
|
+
});
|
|
4943
|
+
}
|
|
4944
|
+
nextFirstPartyMcpTools = explicitRequestedFirstPartyTools;
|
|
4756
4945
|
nextPolicy = {
|
|
4757
4946
|
mode: "explicit",
|
|
4758
4947
|
inheritedFromSessionId: parent.id
|
|
@@ -4760,13 +4949,19 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4760
4949
|
}
|
|
4761
4950
|
} else {
|
|
4762
4951
|
nextTools = requestedMode === "workspace_default" ? workspaceDefaultTools : explicitRequestedTools;
|
|
4952
|
+
nextFirstPartyMcpTools = requestedMode === "workspace_default" ? workspaceDefaultFirstPartyTools : explicitRequestedFirstPartyTools;
|
|
4763
4953
|
nextPolicy = { mode: requestedMode, inheritedFromSessionId: null };
|
|
4764
4954
|
}
|
|
4765
|
-
const currentPolicy = session.toolPolicy
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4955
|
+
const currentPolicy = session.toolPolicy;
|
|
4956
|
+
const unchanged = stableJson2({
|
|
4957
|
+
tools: session.tools,
|
|
4958
|
+
firstPartyMcpTools: session.firstPartyMcpTools ?? DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
4959
|
+
policy: currentPolicy
|
|
4960
|
+
}) === stableJson2({
|
|
4961
|
+
tools: nextTools,
|
|
4962
|
+
firstPartyMcpTools: nextFirstPartyMcpTools,
|
|
4963
|
+
policy: nextPolicy
|
|
4964
|
+
});
|
|
4770
4965
|
if (unchanged) {
|
|
4771
4966
|
return { events: [] };
|
|
4772
4967
|
}
|
|
@@ -4776,8 +4971,18 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4776
4971
|
{
|
|
4777
4972
|
type: "session.tool_policy.updated",
|
|
4778
4973
|
payload: {
|
|
4779
|
-
before: toolPolicyAuditSnapshot(
|
|
4780
|
-
|
|
4974
|
+
before: toolPolicyAuditSnapshot(
|
|
4975
|
+
session,
|
|
4976
|
+
session.tools,
|
|
4977
|
+
[...session.firstPartyMcpTools ?? DEFAULT_FIRST_PARTY_MCP_TOOLS],
|
|
4978
|
+
currentPolicy
|
|
4979
|
+
),
|
|
4980
|
+
after: toolPolicyAuditSnapshot(
|
|
4981
|
+
session,
|
|
4982
|
+
nextTools,
|
|
4983
|
+
nextFirstPartyMcpTools,
|
|
4984
|
+
nextPolicy
|
|
4985
|
+
),
|
|
4781
4986
|
version: nextVersion,
|
|
4782
4987
|
effectiveFrom: "next_attempt"
|
|
4783
4988
|
}
|
|
@@ -4785,6 +4990,7 @@ async function updateSessionToolPolicy(deps, grant, sessionId, request) {
|
|
|
4785
4990
|
],
|
|
4786
4991
|
update: {
|
|
4787
4992
|
tools: nextTools,
|
|
4993
|
+
firstPartyMcpTools: nextFirstPartyMcpTools,
|
|
4788
4994
|
toolPolicy: nextPolicy,
|
|
4789
4995
|
toolPolicyVersion: nextVersion,
|
|
4790
4996
|
expectedToolPolicyVersion: request.expectedVersion
|
|
@@ -5076,6 +5282,424 @@ function trimmedScheduledTaskName(name) {
|
|
|
5076
5282
|
return trimmed;
|
|
5077
5283
|
}
|
|
5078
5284
|
|
|
5285
|
+
// src/domain/insights.ts
|
|
5286
|
+
import { configuredStaticUsageLimits as configuredStaticUsageLimits2 } from "@opengeni/config";
|
|
5287
|
+
import {
|
|
5288
|
+
WorkspaceInsightsSnapshot
|
|
5289
|
+
} from "@opengeni/contracts";
|
|
5290
|
+
import {
|
|
5291
|
+
aggregateModelCallFacts,
|
|
5292
|
+
aggregateModelCallFactsByDay,
|
|
5293
|
+
aggregateRootSessionDrivers,
|
|
5294
|
+
aggregateScheduleFacts,
|
|
5295
|
+
aggregateSessionDepth,
|
|
5296
|
+
aggregateWarmSecondsByGroup,
|
|
5297
|
+
countOnlineMachines,
|
|
5298
|
+
countScheduledTaskFires,
|
|
5299
|
+
countSessionsAttachedToGroups,
|
|
5300
|
+
enumerateUtcDays,
|
|
5301
|
+
listFloorSessions,
|
|
5302
|
+
listLiveWarmLeases,
|
|
5303
|
+
listModelCallFacets,
|
|
5304
|
+
listScheduledTasks,
|
|
5305
|
+
requireWorkspace as requireWorkspace3,
|
|
5306
|
+
sumUsageQuantity as sumUsageQuantity2,
|
|
5307
|
+
sumUsageQuantityByDay,
|
|
5308
|
+
sumUsageQuantityInRange
|
|
5309
|
+
} from "@opengeni/db";
|
|
5310
|
+
var MACHINE_HEARTBEAT_FRESH_MS = 12e4;
|
|
5311
|
+
function microsToUsd(micros) {
|
|
5312
|
+
return Math.round(micros / 1e6 * 100) / 100;
|
|
5313
|
+
}
|
|
5314
|
+
function cacheHitPct(cached, input) {
|
|
5315
|
+
if (input <= 0) return 0;
|
|
5316
|
+
return Math.min(100, Math.max(0, Math.round(cached / input * 100)));
|
|
5317
|
+
}
|
|
5318
|
+
function startOfUtcDay(date) {
|
|
5319
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
5320
|
+
}
|
|
5321
|
+
function startOfUtcMonth2(date) {
|
|
5322
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));
|
|
5323
|
+
}
|
|
5324
|
+
function startOfUtcYear(date) {
|
|
5325
|
+
return new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
|
|
5326
|
+
}
|
|
5327
|
+
function resolveRangeWindow(range, now) {
|
|
5328
|
+
const until = now;
|
|
5329
|
+
let since;
|
|
5330
|
+
let rangeLabel;
|
|
5331
|
+
let priorLabel;
|
|
5332
|
+
let seriesLabel;
|
|
5333
|
+
let cacheSeriesLabel;
|
|
5334
|
+
switch (range) {
|
|
5335
|
+
case "today":
|
|
5336
|
+
since = startOfUtcDay(now);
|
|
5337
|
+
rangeLabel = "Today (UTC)";
|
|
5338
|
+
priorLabel = "Prior equal window";
|
|
5339
|
+
seriesLabel = "Credit $ (UTC day)";
|
|
5340
|
+
cacheSeriesLabel = "Cache hit %";
|
|
5341
|
+
break;
|
|
5342
|
+
case "week":
|
|
5343
|
+
since = new Date(startOfUtcDay(now).getTime() - 6 * 24 * 60 * 60 * 1e3);
|
|
5344
|
+
rangeLabel = "Last 7 days (UTC)";
|
|
5345
|
+
priorLabel = "Prior 7 days";
|
|
5346
|
+
seriesLabel = "Credit $ / day";
|
|
5347
|
+
cacheSeriesLabel = "Cache hit % / day";
|
|
5348
|
+
break;
|
|
5349
|
+
case "month":
|
|
5350
|
+
since = startOfUtcMonth2(now);
|
|
5351
|
+
rangeLabel = "This month (UTC)";
|
|
5352
|
+
priorLabel = "Prior equal window";
|
|
5353
|
+
seriesLabel = "Credit $ / day";
|
|
5354
|
+
cacheSeriesLabel = "Cache hit % / day";
|
|
5355
|
+
break;
|
|
5356
|
+
case "ytd":
|
|
5357
|
+
since = startOfUtcYear(now);
|
|
5358
|
+
rangeLabel = "Year to date (UTC)";
|
|
5359
|
+
priorLabel = "Prior equal window";
|
|
5360
|
+
seriesLabel = "Credit $ / day";
|
|
5361
|
+
cacheSeriesLabel = "Cache hit % / day";
|
|
5362
|
+
break;
|
|
5363
|
+
default: {
|
|
5364
|
+
const _exhaustive = range;
|
|
5365
|
+
throw new Error(`Unknown insights range: ${_exhaustive}`);
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
const durationMs = until.getTime() - since.getTime();
|
|
5369
|
+
const priorUntil = since;
|
|
5370
|
+
const priorSince = new Date(priorUntil.getTime() - Math.max(durationMs, 1));
|
|
5371
|
+
return {
|
|
5372
|
+
since,
|
|
5373
|
+
until,
|
|
5374
|
+
priorSince,
|
|
5375
|
+
priorUntil,
|
|
5376
|
+
rangeLabel,
|
|
5377
|
+
priorLabel,
|
|
5378
|
+
seriesLabel,
|
|
5379
|
+
cacheSeriesLabel
|
|
5380
|
+
};
|
|
5381
|
+
}
|
|
5382
|
+
function ageLabel(updatedAt, now) {
|
|
5383
|
+
const ms = Math.max(0, now.getTime() - updatedAt.getTime());
|
|
5384
|
+
const minutes = Math.floor(ms / 6e4);
|
|
5385
|
+
if (minutes < 1) return "just now";
|
|
5386
|
+
if (minutes < 60) return `${minutes}m`;
|
|
5387
|
+
const hours = Math.floor(minutes / 60);
|
|
5388
|
+
if (hours < 48) return `${hours}h`;
|
|
5389
|
+
return `${Math.floor(hours / 24)}d`;
|
|
5390
|
+
}
|
|
5391
|
+
function floorState(input) {
|
|
5392
|
+
if (input.directControlState === "paused") return "paused";
|
|
5393
|
+
switch (input.status) {
|
|
5394
|
+
case "running":
|
|
5395
|
+
return "running";
|
|
5396
|
+
case "failed":
|
|
5397
|
+
return "failed";
|
|
5398
|
+
case "requires_action":
|
|
5399
|
+
case "waiting":
|
|
5400
|
+
return "waiting";
|
|
5401
|
+
case "compacting":
|
|
5402
|
+
return "compacting";
|
|
5403
|
+
case "completed":
|
|
5404
|
+
case "idle":
|
|
5405
|
+
case "queued":
|
|
5406
|
+
return "idle";
|
|
5407
|
+
default:
|
|
5408
|
+
return "idle";
|
|
5409
|
+
}
|
|
5410
|
+
}
|
|
5411
|
+
function billingPathOf(value) {
|
|
5412
|
+
return value === "external" ? "external" : "opengeni_credits";
|
|
5413
|
+
}
|
|
5414
|
+
async function getWorkspaceInsights(db, settings, input) {
|
|
5415
|
+
await requireWorkspace3(db, input.workspaceId);
|
|
5416
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
5417
|
+
const window = resolveRangeWindow(input.range, now);
|
|
5418
|
+
const provider = input.provider?.trim() || null;
|
|
5419
|
+
const model = input.model?.trim() || null;
|
|
5420
|
+
const modelFilterActive = Boolean(provider || model);
|
|
5421
|
+
const filter = { provider, model };
|
|
5422
|
+
const [
|
|
5423
|
+
workspaceCreditMicros,
|
|
5424
|
+
priorWorkspaceCreditMicros,
|
|
5425
|
+
warmSeconds,
|
|
5426
|
+
priorWarmSeconds,
|
|
5427
|
+
modelRows,
|
|
5428
|
+
priorModelRows,
|
|
5429
|
+
factDays,
|
|
5430
|
+
warmDays,
|
|
5431
|
+
costDays,
|
|
5432
|
+
warmGroups,
|
|
5433
|
+
liveWarm,
|
|
5434
|
+
rootDrivers,
|
|
5435
|
+
scheduleFacts,
|
|
5436
|
+
tasks,
|
|
5437
|
+
depth,
|
|
5438
|
+
floorRows,
|
|
5439
|
+
machinesOnline,
|
|
5440
|
+
billableTokensUsed,
|
|
5441
|
+
agentRunsUsed,
|
|
5442
|
+
facets
|
|
5443
|
+
] = await Promise.all([
|
|
5444
|
+
sumUsageQuantityInRange(db, {
|
|
5445
|
+
workspaceId: input.workspaceId,
|
|
5446
|
+
eventType: "model.cost",
|
|
5447
|
+
since: window.since,
|
|
5448
|
+
until: window.until
|
|
5449
|
+
}),
|
|
5450
|
+
sumUsageQuantityInRange(db, {
|
|
5451
|
+
workspaceId: input.workspaceId,
|
|
5452
|
+
eventType: "model.cost",
|
|
5453
|
+
since: window.priorSince,
|
|
5454
|
+
until: window.priorUntil
|
|
5455
|
+
}),
|
|
5456
|
+
sumUsageQuantityInRange(db, {
|
|
5457
|
+
workspaceId: input.workspaceId,
|
|
5458
|
+
eventType: "sandbox.warm_seconds",
|
|
5459
|
+
since: window.since,
|
|
5460
|
+
until: window.until
|
|
5461
|
+
}),
|
|
5462
|
+
sumUsageQuantityInRange(db, {
|
|
5463
|
+
workspaceId: input.workspaceId,
|
|
5464
|
+
eventType: "sandbox.warm_seconds",
|
|
5465
|
+
since: window.priorSince,
|
|
5466
|
+
until: window.priorUntil
|
|
5467
|
+
}),
|
|
5468
|
+
aggregateModelCallFacts(db, {
|
|
5469
|
+
workspaceId: input.workspaceId,
|
|
5470
|
+
since: window.since,
|
|
5471
|
+
until: window.until,
|
|
5472
|
+
...filter
|
|
5473
|
+
}),
|
|
5474
|
+
aggregateModelCallFacts(db, {
|
|
5475
|
+
workspaceId: input.workspaceId,
|
|
5476
|
+
since: window.priorSince,
|
|
5477
|
+
until: window.priorUntil,
|
|
5478
|
+
...filter
|
|
5479
|
+
}),
|
|
5480
|
+
aggregateModelCallFactsByDay(db, {
|
|
5481
|
+
workspaceId: input.workspaceId,
|
|
5482
|
+
since: window.since,
|
|
5483
|
+
until: window.until,
|
|
5484
|
+
...filter
|
|
5485
|
+
}),
|
|
5486
|
+
sumUsageQuantityByDay(db, {
|
|
5487
|
+
workspaceId: input.workspaceId,
|
|
5488
|
+
eventType: "sandbox.warm_seconds",
|
|
5489
|
+
since: window.since,
|
|
5490
|
+
until: window.until
|
|
5491
|
+
}),
|
|
5492
|
+
sumUsageQuantityByDay(db, {
|
|
5493
|
+
workspaceId: input.workspaceId,
|
|
5494
|
+
eventType: "model.cost",
|
|
5495
|
+
since: window.since,
|
|
5496
|
+
until: window.until
|
|
5497
|
+
}),
|
|
5498
|
+
aggregateWarmSecondsByGroup(db, {
|
|
5499
|
+
workspaceId: input.workspaceId,
|
|
5500
|
+
since: window.since,
|
|
5501
|
+
until: window.until,
|
|
5502
|
+
limit: 24
|
|
5503
|
+
}),
|
|
5504
|
+
listLiveWarmLeases(db, input.workspaceId),
|
|
5505
|
+
aggregateRootSessionDrivers(db, {
|
|
5506
|
+
workspaceId: input.workspaceId,
|
|
5507
|
+
since: window.since,
|
|
5508
|
+
until: window.until,
|
|
5509
|
+
...filter,
|
|
5510
|
+
limit: 8
|
|
5511
|
+
}),
|
|
5512
|
+
aggregateScheduleFacts(db, {
|
|
5513
|
+
workspaceId: input.workspaceId,
|
|
5514
|
+
since: window.since,
|
|
5515
|
+
until: window.until,
|
|
5516
|
+
...filter
|
|
5517
|
+
}),
|
|
5518
|
+
listScheduledTasks(db, input.workspaceId, 100),
|
|
5519
|
+
aggregateSessionDepth(db, input.workspaceId),
|
|
5520
|
+
listFloorSessions(db, input.workspaceId, 24),
|
|
5521
|
+
settings.sandboxSelfhostedEnabled ? countOnlineMachines(db, input.workspaceId, MACHINE_HEARTBEAT_FRESH_MS) : Promise.resolve(0),
|
|
5522
|
+
sumUsageQuantity2(db, {
|
|
5523
|
+
workspaceId: input.workspaceId,
|
|
5524
|
+
eventType: "model.tokens",
|
|
5525
|
+
since: startOfUtcMonth2(now)
|
|
5526
|
+
}),
|
|
5527
|
+
sumUsageQuantity2(db, {
|
|
5528
|
+
workspaceId: input.workspaceId,
|
|
5529
|
+
eventType: "agent_run.created",
|
|
5530
|
+
since: startOfUtcMonth2(now)
|
|
5531
|
+
}),
|
|
5532
|
+
listModelCallFacets(db, {
|
|
5533
|
+
workspaceId: input.workspaceId,
|
|
5534
|
+
since: window.since,
|
|
5535
|
+
until: window.until
|
|
5536
|
+
})
|
|
5537
|
+
]);
|
|
5538
|
+
const priorRootDrivers = await aggregateRootSessionDrivers(db, {
|
|
5539
|
+
workspaceId: input.workspaceId,
|
|
5540
|
+
since: window.priorSince,
|
|
5541
|
+
until: window.priorUntil,
|
|
5542
|
+
...filter,
|
|
5543
|
+
rootSessionIds: rootDrivers.map((row) => row.rootSessionId)
|
|
5544
|
+
});
|
|
5545
|
+
const attached = await countSessionsAttachedToGroups(
|
|
5546
|
+
db,
|
|
5547
|
+
input.workspaceId,
|
|
5548
|
+
warmGroups.map((group) => group.groupId)
|
|
5549
|
+
);
|
|
5550
|
+
const backendByGroup = new Map(liveWarm.map((lease) => [lease.groupId, lease.backend]));
|
|
5551
|
+
const warmSecondsByGroup = new Map(warmGroups.map((group) => [group.groupId, group.warmSeconds]));
|
|
5552
|
+
const models = modelRows.map((row) => ({
|
|
5553
|
+
id: `${row.provider}:${row.model}:${row.billingPath}`,
|
|
5554
|
+
model: row.model,
|
|
5555
|
+
provider: row.provider,
|
|
5556
|
+
billing: billingPathOf(row.billingPath),
|
|
5557
|
+
calls: row.calls,
|
|
5558
|
+
inputTokens: row.inputTokens,
|
|
5559
|
+
outputTokens: row.outputTokens,
|
|
5560
|
+
cachedTokens: row.cachedTokens,
|
|
5561
|
+
cacheWriteTokens: row.cacheWriteTokens,
|
|
5562
|
+
reasoningTokens: row.reasoningTokens,
|
|
5563
|
+
creditUsd: microsToUsd(row.pricedCostMicros)
|
|
5564
|
+
})).sort((a, b) => b.inputTokens - a.inputTokens);
|
|
5565
|
+
const creditMicros = modelRows.reduce((sum, row) => sum + row.pricedCostMicros, 0);
|
|
5566
|
+
const priorCreditMicros = priorModelRows.reduce((sum, row) => sum + row.pricedCostMicros, 0);
|
|
5567
|
+
const priorInputTokens = priorModelRows.reduce((sum, row) => sum + row.inputTokens, 0);
|
|
5568
|
+
const priorCachedTokens = priorModelRows.reduce((sum, row) => sum + row.cachedTokens, 0);
|
|
5569
|
+
const priorCalls = priorModelRows.reduce((sum, row) => sum + row.calls, 0);
|
|
5570
|
+
const days = enumerateUtcDays(window.since, window.until);
|
|
5571
|
+
const series = days.map((day) => {
|
|
5572
|
+
const facts = factDays.get(day) ?? {
|
|
5573
|
+
costMicros: 0,
|
|
5574
|
+
inputTokens: 0,
|
|
5575
|
+
cachedTokens: 0,
|
|
5576
|
+
calls: 0
|
|
5577
|
+
};
|
|
5578
|
+
const modelCostMicros = modelFilterActive ? facts.costMicros : costDays.get(day) ?? facts.costMicros;
|
|
5579
|
+
return {
|
|
5580
|
+
label: day.slice(5),
|
|
5581
|
+
modelCostUsd: microsToUsd(modelCostMicros),
|
|
5582
|
+
warmSeconds: warmDays.get(day) ?? 0,
|
|
5583
|
+
inputTokens: facts.inputTokens,
|
|
5584
|
+
cachedTokens: facts.cachedTokens,
|
|
5585
|
+
cacheHitPct: cacheHitPct(facts.cachedTokens, facts.inputTokens),
|
|
5586
|
+
calls: facts.calls
|
|
5587
|
+
};
|
|
5588
|
+
});
|
|
5589
|
+
const priorDriverByRoot = new Map(
|
|
5590
|
+
priorRootDrivers.map((row) => [row.rootSessionId, row.pricedCostMicros])
|
|
5591
|
+
);
|
|
5592
|
+
const creditUsdForPct = Math.max(microsToUsd(creditMicros), 0.01);
|
|
5593
|
+
const drivers = rootDrivers.map((row) => {
|
|
5594
|
+
const creditUsd = microsToUsd(row.pricedCostMicros);
|
|
5595
|
+
const priorUsd = microsToUsd(priorDriverByRoot.get(row.rootSessionId) ?? 0);
|
|
5596
|
+
return {
|
|
5597
|
+
id: `root:${row.rootSessionId}`,
|
|
5598
|
+
groupBy: "root_session",
|
|
5599
|
+
label: row.title?.trim() || row.rootSessionId.slice(0, 8),
|
|
5600
|
+
creditUsd,
|
|
5601
|
+
tokens: row.inputTokens,
|
|
5602
|
+
cacheHitPct: cacheHitPct(row.cachedTokens, row.inputTokens),
|
|
5603
|
+
pctOfCreditUsd: Math.min(100, Math.round(creditUsd / creditUsdForPct * 100)),
|
|
5604
|
+
deltaUsdVsPrior: Math.round((creditUsd - priorUsd) * 100) / 100
|
|
5605
|
+
};
|
|
5606
|
+
});
|
|
5607
|
+
const fireCounts = await countScheduledTaskFires(db, {
|
|
5608
|
+
workspaceId: input.workspaceId,
|
|
5609
|
+
since: window.since,
|
|
5610
|
+
until: window.until,
|
|
5611
|
+
taskIds: tasks.map((task) => task.id)
|
|
5612
|
+
});
|
|
5613
|
+
const scheduleFactById = new Map(scheduleFacts.map((row) => [row.scheduledTaskId, row]));
|
|
5614
|
+
const schedules = tasks.map((task) => {
|
|
5615
|
+
const fact = scheduleFactById.get(task.id);
|
|
5616
|
+
return {
|
|
5617
|
+
id: task.id,
|
|
5618
|
+
name: task.name,
|
|
5619
|
+
fires: fireCounts.get(task.id) ?? 0,
|
|
5620
|
+
creditUsd: fact ? microsToUsd(fact.pricedCostMicros) : null,
|
|
5621
|
+
tokens: fact ? fact.inputTokens : null,
|
|
5622
|
+
cacheHitPct: fact ? cacheHitPct(fact.cachedTokens, fact.inputTokens) : null,
|
|
5623
|
+
billing: fact ? billingPathOf(fact.billingPath) : null
|
|
5624
|
+
};
|
|
5625
|
+
});
|
|
5626
|
+
const limits = configuredStaticUsageLimits2(settings);
|
|
5627
|
+
const floor = floorRows.filter((row) => {
|
|
5628
|
+
if (!model) return true;
|
|
5629
|
+
return row.model === model;
|
|
5630
|
+
}).map((row) => ({
|
|
5631
|
+
id: row.id,
|
|
5632
|
+
title: row.title?.trim() || "Untitled session",
|
|
5633
|
+
state: floorState(row),
|
|
5634
|
+
depth: row.nestedAgentDepth,
|
|
5635
|
+
model: row.model,
|
|
5636
|
+
provider: null,
|
|
5637
|
+
ageLabel: ageLabel(row.updatedAt, now),
|
|
5638
|
+
cacheHitPct: null,
|
|
5639
|
+
route: row.sandboxBackend
|
|
5640
|
+
}));
|
|
5641
|
+
const snapshot = WorkspaceInsightsSnapshot.parse({
|
|
5642
|
+
range: input.range,
|
|
5643
|
+
rangeLabel: window.rangeLabel,
|
|
5644
|
+
priorLabel: window.priorLabel,
|
|
5645
|
+
seriesLabel: window.seriesLabel,
|
|
5646
|
+
cacheSeriesLabel: window.cacheSeriesLabel,
|
|
5647
|
+
timezone: "UTC",
|
|
5648
|
+
models,
|
|
5649
|
+
facets,
|
|
5650
|
+
series,
|
|
5651
|
+
depth: depth.buckets.map((bucket) => ({
|
|
5652
|
+
depth: bucket.depth,
|
|
5653
|
+
sessions: bucket.sessions
|
|
5654
|
+
})),
|
|
5655
|
+
drivers,
|
|
5656
|
+
schedules,
|
|
5657
|
+
warmSeconds,
|
|
5658
|
+
priorWarmSeconds,
|
|
5659
|
+
warmGroups: warmGroups.map((group) => ({
|
|
5660
|
+
id: group.groupId,
|
|
5661
|
+
groupId: group.groupId,
|
|
5662
|
+
label: group.groupId.slice(0, 8),
|
|
5663
|
+
backend: backendByGroup.get(group.groupId) ?? null,
|
|
5664
|
+
warmSeconds: group.warmSeconds,
|
|
5665
|
+
sessionsAttached: attached.get(group.groupId) ?? 0
|
|
5666
|
+
})),
|
|
5667
|
+
liveWarm: liveWarm.map((lease) => ({
|
|
5668
|
+
id: lease.id,
|
|
5669
|
+
groupId: lease.groupId,
|
|
5670
|
+
backend: lease.backend,
|
|
5671
|
+
turnHolders: lease.turnHolders,
|
|
5672
|
+
viewerHolders: lease.viewerHolders,
|
|
5673
|
+
warmForLabel: lease.turnHolders > 0 ? "in use" : "idle warm",
|
|
5674
|
+
warmSeconds: warmSecondsByGroup.get(lease.groupId) ?? 0
|
|
5675
|
+
})),
|
|
5676
|
+
floor,
|
|
5677
|
+
selfhostedEnabled: settings.sandboxSelfhostedEnabled,
|
|
5678
|
+
machinesOnline,
|
|
5679
|
+
workspaceCreditUsd: microsToUsd(workspaceCreditMicros),
|
|
5680
|
+
priorWorkspaceCreditUsd: microsToUsd(priorWorkspaceCreditMicros),
|
|
5681
|
+
creditUsd: microsToUsd(creditMicros),
|
|
5682
|
+
priorCreditUsd: microsToUsd(priorCreditMicros),
|
|
5683
|
+
priorInputTokens,
|
|
5684
|
+
priorCacheHitPct: cacheHitPct(priorCachedTokens, priorInputTokens),
|
|
5685
|
+
priorCalls,
|
|
5686
|
+
goalsActive: depth.goalsActive,
|
|
5687
|
+
goalsCompleted: depth.goalsCompleted,
|
|
5688
|
+
sessionsTouched: depth.sessionsTouched,
|
|
5689
|
+
rootSessions: depth.rootSessions,
|
|
5690
|
+
deepestDepth: depth.deepestDepth,
|
|
5691
|
+
deepestSessionTitle: depth.deepestSessionTitle || "",
|
|
5692
|
+
avgDepth: Math.round(depth.avgDepth * 10) / 10,
|
|
5693
|
+
warmIdleNow: liveWarm.filter((lease) => lease.turnHolders === 0).length,
|
|
5694
|
+
billableTokensUsed,
|
|
5695
|
+
billableTokenCap: limits.maxMonthlyTokensPerWorkspace ?? null,
|
|
5696
|
+
agentRunsUsed,
|
|
5697
|
+
agentRunCap: limits.maxMonthlyAgentRunsPerWorkspace ?? null,
|
|
5698
|
+
modelFilterActive
|
|
5699
|
+
});
|
|
5700
|
+
return { snapshot };
|
|
5701
|
+
}
|
|
5702
|
+
|
|
5079
5703
|
// src/domain/workspace-members.ts
|
|
5080
5704
|
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
5081
5705
|
var MEMBER_ADMIN_PERMISSIONS = ["workspace:admin", "members:manage"];
|
|
@@ -5154,6 +5778,7 @@ function mapNewSessionDraft(row) {
|
|
|
5154
5778
|
toolsProvided: newSessionDraftToolsProvided(row),
|
|
5155
5779
|
model: row.model,
|
|
5156
5780
|
reasoningEffort: row.reasoningEffort,
|
|
5781
|
+
latencyMode: row.latencyMode,
|
|
5157
5782
|
options: publicNewSessionDraftOptions(row),
|
|
5158
5783
|
updatedAt: row.updatedAt.toISOString()
|
|
5159
5784
|
});
|
|
@@ -5246,6 +5871,7 @@ async function getActorNewSessionDraft(deps, grant, workspaceId) {
|
|
|
5246
5871
|
toolsProvided: false,
|
|
5247
5872
|
model: deps.settings.openaiModel,
|
|
5248
5873
|
reasoningEffort: deps.settings.openaiReasoningEffort,
|
|
5874
|
+
latencyMode: "standard",
|
|
5249
5875
|
options: {},
|
|
5250
5876
|
updatedAt: null
|
|
5251
5877
|
};
|
|
@@ -5284,6 +5910,7 @@ async function saveActorNewSessionDraft(deps, grant, workspaceId, rawInput) {
|
|
|
5284
5910
|
toolsProvided,
|
|
5285
5911
|
model: input.model,
|
|
5286
5912
|
reasoningEffort: input.reasoningEffort,
|
|
5913
|
+
latencyMode: input.latencyMode,
|
|
5287
5914
|
options: input.options,
|
|
5288
5915
|
// Only managed people are removed through removeWorkspaceMember().
|
|
5289
5916
|
// API keys and delegated service actors (for example the first-party
|
|
@@ -5303,7 +5930,7 @@ async function saveActorNewSessionDraft(deps, grant, workspaceId, rawInput) {
|
|
|
5303
5930
|
}
|
|
5304
5931
|
|
|
5305
5932
|
// src/application/session-commands.ts
|
|
5306
|
-
import { reasoningEffortForMetadata as reasoningEffortForMetadata2 } from "@opengeni/contracts";
|
|
5933
|
+
import { latencyModeForMetadata as latencyModeForMetadata2, reasoningEffortForMetadata as reasoningEffortForMetadata2 } from "@opengeni/contracts";
|
|
5307
5934
|
import {
|
|
5308
5935
|
deleteSessionQueueItemInTransaction,
|
|
5309
5936
|
editQueuedTurnInTransaction,
|
|
@@ -5355,14 +5982,14 @@ async function authorizeHumanSessionCommand(deps, context, operation) {
|
|
|
5355
5982
|
return await requireSessionAuthorization(deps, humanAccessGrant(context), {
|
|
5356
5983
|
sessionId: context.sessionId,
|
|
5357
5984
|
operation,
|
|
5358
|
-
surface: "core"
|
|
5985
|
+
surface: context.authorizationSurface ?? "core"
|
|
5359
5986
|
});
|
|
5360
5987
|
}
|
|
5361
5988
|
async function authorizeAgentSessionCommand(deps, context, targetSessionId, operation) {
|
|
5362
5989
|
return await requireSessionAuthorization(deps, agentAccessGrant(context), {
|
|
5363
5990
|
sessionId: targetSessionId,
|
|
5364
5991
|
operation,
|
|
5365
|
-
surface: "core"
|
|
5992
|
+
surface: context.authorizationSurface ?? "core"
|
|
5366
5993
|
});
|
|
5367
5994
|
}
|
|
5368
5995
|
function agentActor(context) {
|
|
@@ -5493,7 +6120,12 @@ async function steerAgentSession(deps, context, input) {
|
|
|
5493
6120
|
return result;
|
|
5494
6121
|
}
|
|
5495
6122
|
async function controlAgentSessionWorkstream(deps, context, input) {
|
|
5496
|
-
await authorizeAgentSessionCommand(
|
|
6123
|
+
const authorization = await authorizeAgentSessionCommand(
|
|
6124
|
+
deps,
|
|
6125
|
+
context,
|
|
6126
|
+
input.targetSessionId,
|
|
6127
|
+
"session.control"
|
|
6128
|
+
);
|
|
5497
6129
|
const result = await withWorkspaceRls(
|
|
5498
6130
|
deps.db,
|
|
5499
6131
|
context.workspaceId,
|
|
@@ -5514,7 +6146,7 @@ async function controlAgentSessionWorkstream(deps, context, input) {
|
|
|
5514
6146
|
]);
|
|
5515
6147
|
await publishWorkspaceControlEvent(deps, context.workspaceId, result.workspaceControlEventId);
|
|
5516
6148
|
await requestControlWakeDispatch(deps, result.wakeCount);
|
|
5517
|
-
return result;
|
|
6149
|
+
return { ...result, authorization };
|
|
5518
6150
|
}
|
|
5519
6151
|
function receipt(row) {
|
|
5520
6152
|
return {
|
|
@@ -5536,10 +6168,9 @@ function composerDraft(row) {
|
|
|
5536
6168
|
revision: row.revision,
|
|
5537
6169
|
text: row.text,
|
|
5538
6170
|
resources: row.resources,
|
|
5539
|
-
tools: row.tools,
|
|
5540
|
-
toolsProvided: row.toolsProvided,
|
|
5541
6171
|
model: row.model,
|
|
5542
6172
|
reasoningEffort: row.reasoningEffort,
|
|
6173
|
+
latencyMode: row.latencyMode,
|
|
5543
6174
|
sourceTurnId: row.sourceTurnId,
|
|
5544
6175
|
sourceTurnVersion: row.sourceTurnVersion,
|
|
5545
6176
|
updatedAt: row.updatedAt.toISOString()
|
|
@@ -5755,10 +6386,9 @@ async function getHumanComposerDraft(deps, context) {
|
|
|
5755
6386
|
revision: 0,
|
|
5756
6387
|
text: "",
|
|
5757
6388
|
resources: [],
|
|
5758
|
-
tools: [],
|
|
5759
|
-
toolsProvided: false,
|
|
5760
6389
|
model: session.model,
|
|
5761
6390
|
reasoningEffort: reasoningEffortForMetadata2(session.metadata, "medium"),
|
|
6391
|
+
latencyMode: latencyModeForMetadata2(session.metadata, "standard"),
|
|
5762
6392
|
sourceTurnId: null,
|
|
5763
6393
|
sourceTurnVersion: null,
|
|
5764
6394
|
updatedAt: null
|
|
@@ -5781,6 +6411,8 @@ async function saveHumanComposerDraft(deps, context, input) {
|
|
|
5781
6411
|
return composerDraft(row);
|
|
5782
6412
|
}
|
|
5783
6413
|
export {
|
|
6414
|
+
CODEX_COMPACTION_V2_PROVIDER_LOCKED,
|
|
6415
|
+
CodexCompactionV2ProviderLockedError,
|
|
5784
6416
|
MARKETING_SOCIAL_PACK_ID,
|
|
5785
6417
|
MAX_CHECKS_PER_RIG,
|
|
5786
6418
|
MAX_CREDENTIAL_HOOKS_PER_RIG,
|
|
@@ -5795,7 +6427,9 @@ export {
|
|
|
5795
6427
|
SessionAuthorizationDeniedError,
|
|
5796
6428
|
SessionAuthorizationUnavailableError,
|
|
5797
6429
|
SessionSpawnDeniedError,
|
|
6430
|
+
TranscriptionServiceError,
|
|
5798
6431
|
acceptSessionUserMessage,
|
|
6432
|
+
accessGrantAuthorizationFromContext,
|
|
5799
6433
|
activateRigVersionForApi,
|
|
5800
6434
|
appendRigSetupCommand,
|
|
5801
6435
|
applyCapabilityEnablement,
|
|
@@ -5803,6 +6437,7 @@ export {
|
|
|
5803
6437
|
assertAllowedVariableSetVariableName,
|
|
5804
6438
|
assertConfiguredModel,
|
|
5805
6439
|
assertPackSandboxImageCompatible,
|
|
6440
|
+
assertSessionAllowsProductModel,
|
|
5806
6441
|
assertToolRefsSubset,
|
|
5807
6442
|
assertWorkspaceDeletable,
|
|
5808
6443
|
assertWorkspaceMemberRemovable,
|
|
@@ -5823,6 +6458,7 @@ export {
|
|
|
5823
6458
|
createRigVersionForApi,
|
|
5824
6459
|
createSessionForRequest,
|
|
5825
6460
|
createValidatedScheduledTask,
|
|
6461
|
+
defaultSessionMcpServerIds,
|
|
5826
6462
|
deleteHumanQueuePrompt,
|
|
5827
6463
|
deleteRigForApi,
|
|
5828
6464
|
disableCapability,
|
|
@@ -5830,17 +6466,22 @@ export {
|
|
|
5830
6466
|
editHumanQueuePrompt,
|
|
5831
6467
|
enableCapability,
|
|
5832
6468
|
enabledCapabilityMcpToolRefs,
|
|
6469
|
+
executeRunOnSelfhostedMachine,
|
|
6470
|
+
filenameForMimeType,
|
|
5833
6471
|
getActorNewSessionDraft,
|
|
5834
6472
|
getCapabilityPack,
|
|
5835
6473
|
getHumanComposerDraft,
|
|
6474
|
+
getWorkspaceInsights,
|
|
5836
6475
|
hasPermission,
|
|
5837
6476
|
hasReservedOpenGeniSlackBotMetadata,
|
|
5838
6477
|
hasReservedOpenGeniSlackBotSessionMetadata,
|
|
6478
|
+
isAcceptedMimeType,
|
|
5839
6479
|
isAuthoritativeGitHubRepositorySelectionError,
|
|
5840
6480
|
isBuiltInCapabilityPack,
|
|
5841
6481
|
isOpenGeniSlackBotConnection,
|
|
5842
6482
|
isTrustedScheduledSlackBotSession,
|
|
5843
6483
|
isUserMember,
|
|
6484
|
+
latencyModeForSession,
|
|
5844
6485
|
listCapabilityPacks,
|
|
5845
6486
|
listFleet,
|
|
5846
6487
|
listRigChangesForApi,
|
|
@@ -5852,6 +6493,7 @@ export {
|
|
|
5852
6493
|
mergeResourceRefs,
|
|
5853
6494
|
mergeToolRefs,
|
|
5854
6495
|
moveHumanQueuePrompt,
|
|
6496
|
+
normalizeMimeType,
|
|
5855
6497
|
normalizeResources,
|
|
5856
6498
|
officialMcpRegistryUrl,
|
|
5857
6499
|
openGeniSlackBotMetadata,
|
|
@@ -5869,6 +6511,7 @@ export {
|
|
|
5869
6511
|
relayDialBaseFromSettings,
|
|
5870
6512
|
requireAccessContext,
|
|
5871
6513
|
requireAccessGrant,
|
|
6514
|
+
requireAccessGrantAuthorization,
|
|
5872
6515
|
requireEnvironmentEncryption,
|
|
5873
6516
|
requireLimit,
|
|
5874
6517
|
requireOpenGeniSlackBotConnection,
|
|
@@ -5897,13 +6540,13 @@ export {
|
|
|
5897
6540
|
scheduledTaskTriggerToken,
|
|
5898
6541
|
sendAgentSessionMessage,
|
|
5899
6542
|
sessionSpawnDenialEnvelope,
|
|
5900
|
-
sessionToolPolicyAllowsDefaultNativeTools,
|
|
5901
6543
|
sessionWithEffectiveToolPolicy,
|
|
5902
6544
|
settingsWithCodexAppsMcpServer,
|
|
5903
6545
|
settingsWithEnabledCapabilityMcpServers,
|
|
5904
6546
|
settingsWithMcpCapabilityServers,
|
|
5905
6547
|
settingsWithSessionMcpServerMetadata,
|
|
5906
6548
|
stableJson,
|
|
6549
|
+
statusForVoiceInputError,
|
|
5907
6550
|
steerAgentSession,
|
|
5908
6551
|
steerHumanQueuePrompt,
|
|
5909
6552
|
swapActiveSandbox,
|