@opengeni/api-router 5.4.1 → 5.5.0-canary.37090756480001
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-2QCRFD6U.js → chunk-ZQ7PIFGF.js} +719 -356
- package/dist/{chunk-2QCRFD6U.js.map → chunk-ZQ7PIFGF.js.map} +1 -1
- package/dist/claude-subscription-usage.d.ts +21 -0
- package/dist/http/api-error.d.ts +7 -0
- package/dist/index.js +1 -1
- package/dist/integrations/github-lens-connect.d.ts +2 -2
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/first-party-tool-permissions.d.ts +8 -0
- package/dist/routes/billing.d.ts +4 -1
- package/dist/routes/client-errors.d.ts +104 -0
- package/dist/routes/insights.d.ts +2 -0
- package/dist/routes/sessions.d.ts +1 -0
- package/package.json +20 -20
- package/src/app.ts +28 -0
- package/src/http/api-error.ts +29 -1
- package/src/http/sse.ts +10 -4
- package/src/mcp/first-party-tool-permissions.ts +5 -0
- package/src/mcp/knowledge-entries.ts +3 -3
- package/src/mcp/server.ts +3 -1
- package/src/model-catalog.ts +5 -0
- package/src/routes/api-integrations.ts +6 -0
- package/src/routes/automations.ts +2 -4
- package/src/routes/billing.ts +118 -21
- package/src/routes/browser-sessions.ts +15 -1
- package/src/routes/client-errors.ts +201 -4
- package/src/routes/computer-sessions.ts +15 -1
- package/src/routes/connections.ts +55 -4
- package/src/routes/insights.ts +19 -1
- package/src/routes/pr-review.ts +2 -3
- package/src/routes/sessions.ts +97 -41
- package/src/routes/workspaces.ts +45 -74
- package/src/workspace-deletion.ts +9 -0
|
@@ -3894,7 +3894,15 @@ import {
|
|
|
3894
3894
|
CLIENT_ERROR_REPORT_MAX_BYTES,
|
|
3895
3895
|
CLIENT_ERROR_REVISION_PATTERN,
|
|
3896
3896
|
CLIENT_ERROR_ROUTE_PATTERN,
|
|
3897
|
-
CLIENT_ERRORS_PATH
|
|
3897
|
+
CLIENT_ERRORS_PATH,
|
|
3898
|
+
CLIENT_PAGES,
|
|
3899
|
+
CLIENT_REQUEST_ACTIONS,
|
|
3900
|
+
CLIENT_REQUEST_FAILURE_REASONS,
|
|
3901
|
+
CLIENT_SIGNALS,
|
|
3902
|
+
CLIENT_STREAM_EVENTS,
|
|
3903
|
+
CLIENT_STREAMS,
|
|
3904
|
+
CLIENT_WEB_VITAL_MAX_VALUE,
|
|
3905
|
+
CLIENT_WEB_VITAL_METRICS
|
|
3898
3906
|
} from "@opengeni/contracts/client-error-report";
|
|
3899
3907
|
import { bodyLimit } from "hono/body-limit";
|
|
3900
3908
|
import { z as z9 } from "zod";
|
|
@@ -3968,6 +3976,31 @@ var ClientErrorReport = z9.object({
|
|
|
3968
3976
|
route: z9.string().regex(CLIENT_ERROR_ROUTE_PATTERN),
|
|
3969
3977
|
revision: z9.string().regex(CLIENT_ERROR_REVISION_PATTERN)
|
|
3970
3978
|
}).strict();
|
|
3979
|
+
var route = z9.string().regex(CLIENT_ERROR_ROUTE_PATTERN);
|
|
3980
|
+
var revision = z9.string().regex(CLIENT_ERROR_REVISION_PATTERN);
|
|
3981
|
+
var ClientSignalReport = z9.discriminatedUnion("signal", [
|
|
3982
|
+
z9.object({
|
|
3983
|
+
signal: z9.literal("request_failure"),
|
|
3984
|
+
action: z9.enum(CLIENT_REQUEST_ACTIONS),
|
|
3985
|
+
reason: z9.enum(CLIENT_REQUEST_FAILURE_REASONS),
|
|
3986
|
+
route,
|
|
3987
|
+
revision
|
|
3988
|
+
}).strict(),
|
|
3989
|
+
z9.object({
|
|
3990
|
+
signal: z9.literal("stream"),
|
|
3991
|
+
stream: z9.enum(CLIENT_STREAMS),
|
|
3992
|
+
event: z9.enum(CLIENT_STREAM_EVENTS),
|
|
3993
|
+
route,
|
|
3994
|
+
revision
|
|
3995
|
+
}).strict(),
|
|
3996
|
+
z9.object({
|
|
3997
|
+
signal: z9.literal("web_vital"),
|
|
3998
|
+
metric: z9.enum(CLIENT_WEB_VITAL_METRICS),
|
|
3999
|
+
page: z9.enum(CLIENT_PAGES),
|
|
4000
|
+
value: z9.number().finite().nonnegative(),
|
|
4001
|
+
revision
|
|
4002
|
+
}).strict().refine((report) => report.value <= CLIENT_WEB_VITAL_MAX_VALUE[report.metric])
|
|
4003
|
+
]);
|
|
3971
4004
|
var CLIENT_ERRORS_METRIC = {
|
|
3972
4005
|
name: "opengeni_client_errors_total",
|
|
3973
4006
|
help: "Web client errors reported by browsers, by closed kind. Admission is bounded per API process, so this is a lower bound."
|
|
@@ -3976,10 +4009,56 @@ var CLIENT_ERROR_REJECTIONS_METRIC = {
|
|
|
3976
4009
|
name: "opengeni_client_error_reports_rejected_total",
|
|
3977
4010
|
help: 'Web client error reports the API refused, by closed reason and kind ("unknown" when the body was not read or not valid).'
|
|
3978
4011
|
};
|
|
4012
|
+
var CLIENT_REQUEST_FAILURES_METRIC = {
|
|
4013
|
+
name: "opengeni_client_request_failures_total",
|
|
4014
|
+
help: "Key web client requests that failed before any HTTP response, by closed action and reason (network, timeout, offline). Admission is bounded per API process, so this is a lower bound."
|
|
4015
|
+
};
|
|
4016
|
+
var CLIENT_STREAM_EVENTS_METRIC = {
|
|
4017
|
+
name: "opengeni_client_stream_events_total",
|
|
4018
|
+
help: "Web client live-stream health events, by stream (session, workspace) and closed event (reconnect, reconnect_exhausted, long_disconnect). Admission is bounded per API process, so this is a lower bound."
|
|
4019
|
+
};
|
|
4020
|
+
var CLIENT_WEB_VITAL_METRIC = {
|
|
4021
|
+
name: "opengeni_client_web_vital",
|
|
4022
|
+
help: "Web vitals reported by browsers, by metric and closed page label. lcp, inp and ttfb are seconds; cls is the unitless layout-shift score."
|
|
4023
|
+
};
|
|
4024
|
+
var CLIENT_WEB_VITAL_BUCKETS = [
|
|
4025
|
+
0.01,
|
|
4026
|
+
0.025,
|
|
4027
|
+
0.05,
|
|
4028
|
+
0.1,
|
|
4029
|
+
0.2,
|
|
4030
|
+
0.25,
|
|
4031
|
+
0.5,
|
|
4032
|
+
0.8,
|
|
4033
|
+
1,
|
|
4034
|
+
1.8,
|
|
4035
|
+
2.5,
|
|
4036
|
+
4,
|
|
4037
|
+
6,
|
|
4038
|
+
10,
|
|
4039
|
+
20,
|
|
4040
|
+
60
|
|
4041
|
+
];
|
|
4042
|
+
function createClientSignalAdmission(options = {}) {
|
|
4043
|
+
return createKeyedAdmission(options);
|
|
4044
|
+
}
|
|
4045
|
+
function createClientWebVitalAdmission(options = {}) {
|
|
4046
|
+
return createKeyedAdmission({ capacity: 1200, refillPerSecond: 20, ...options });
|
|
4047
|
+
}
|
|
4048
|
+
function signalAdmissionKey(report) {
|
|
4049
|
+
switch (report.signal) {
|
|
4050
|
+
case "request_failure":
|
|
4051
|
+
return `request_failure:${report.action}`;
|
|
4052
|
+
case "stream":
|
|
4053
|
+
return `stream:${report.stream}:${report.event}`;
|
|
4054
|
+
case "web_vital":
|
|
4055
|
+
return `web_vital:${report.metric}`;
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
3979
4058
|
function createClientErrorAdmission(options = {}) {
|
|
3980
4059
|
return createKeyedAdmission(options);
|
|
3981
4060
|
}
|
|
3982
|
-
function
|
|
4061
|
+
function parseClientBeaconReport(body3) {
|
|
3983
4062
|
if (body3 === null || new TextEncoder().encode(body3).byteLength > CLIENT_ERROR_REPORT_MAX_BYTES) {
|
|
3984
4063
|
return null;
|
|
3985
4064
|
}
|
|
@@ -3989,8 +4068,13 @@ function parseClientErrorReport(body3) {
|
|
|
3989
4068
|
} catch {
|
|
3990
4069
|
return null;
|
|
3991
4070
|
}
|
|
3992
|
-
const
|
|
3993
|
-
|
|
4071
|
+
const error = ClientErrorReport.safeParse(value);
|
|
4072
|
+
if (error.success) return error.data;
|
|
4073
|
+
const signal = ClientSignalReport.safeParse(value);
|
|
4074
|
+
return signal.success ? signal.data : null;
|
|
4075
|
+
}
|
|
4076
|
+
function isClientSignalReport(report) {
|
|
4077
|
+
return "signal" in report;
|
|
3994
4078
|
}
|
|
3995
4079
|
function isClientErrorReportRequest(method, pathname) {
|
|
3996
4080
|
return method === "POST" && pathname === CLIENT_ERRORS_PATH;
|
|
@@ -3998,6 +4082,8 @@ function isClientErrorReportRequest(method, pathname) {
|
|
|
3998
4082
|
function registerClientErrorRoutes(app, deps) {
|
|
3999
4083
|
const { observability, settings } = deps;
|
|
4000
4084
|
const admission = deps.admission ?? createClientErrorAdmission();
|
|
4085
|
+
const signalAdmission = deps.signalAdmission ?? createClientSignalAdmission();
|
|
4086
|
+
const webVitalAdmission = deps.webVitalAdmission ?? createClientWebVitalAdmission();
|
|
4001
4087
|
for (const kind of CLIENT_ERROR_KINDS) {
|
|
4002
4088
|
observability.incrementCounter({ ...CLIENT_ERRORS_METRIC, labels: { kind }, amount: 0 });
|
|
4003
4089
|
observability.incrementCounter({
|
|
@@ -4006,6 +4092,31 @@ function registerClientErrorRoutes(app, deps) {
|
|
|
4006
4092
|
amount: 0
|
|
4007
4093
|
});
|
|
4008
4094
|
}
|
|
4095
|
+
for (const action of CLIENT_REQUEST_ACTIONS) {
|
|
4096
|
+
for (const reason of CLIENT_REQUEST_FAILURE_REASONS) {
|
|
4097
|
+
observability.incrementCounter({
|
|
4098
|
+
...CLIENT_REQUEST_FAILURES_METRIC,
|
|
4099
|
+
labels: { action, reason },
|
|
4100
|
+
amount: 0
|
|
4101
|
+
});
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
for (const stream of CLIENT_STREAMS) {
|
|
4105
|
+
for (const event of CLIENT_STREAM_EVENTS) {
|
|
4106
|
+
observability.incrementCounter({
|
|
4107
|
+
...CLIENT_STREAM_EVENTS_METRIC,
|
|
4108
|
+
labels: { stream, event },
|
|
4109
|
+
amount: 0
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
for (const signal of CLIENT_SIGNALS) {
|
|
4114
|
+
observability.incrementCounter({
|
|
4115
|
+
...CLIENT_ERROR_REJECTIONS_METRIC,
|
|
4116
|
+
labels: { reason: "rate_limited", kind: signal },
|
|
4117
|
+
amount: 0
|
|
4118
|
+
});
|
|
4119
|
+
}
|
|
4009
4120
|
for (const reason of CLIENT_ERROR_REJECTION_REASONS) {
|
|
4010
4121
|
if (reason === "rate_limited") continue;
|
|
4011
4122
|
observability.incrementCounter({
|
|
@@ -4033,8 +4144,16 @@ function registerClientErrorRoutes(app, deps) {
|
|
|
4033
4144
|
if (origin !== void 0 && !isAllowedBrowserOrigin(origin, settings)) {
|
|
4034
4145
|
return reject(c, "origin", 403);
|
|
4035
4146
|
}
|
|
4036
|
-
const report =
|
|
4147
|
+
const report = parseClientBeaconReport(await c.req.text().catch(() => null));
|
|
4037
4148
|
if (!report) return reject(c, "invalid", 400);
|
|
4149
|
+
if (isClientSignalReport(report)) {
|
|
4150
|
+
const bucket = report.signal === "web_vital" ? webVitalAdmission : signalAdmission;
|
|
4151
|
+
if (!bucket.admit(signalAdmissionKey(report))) {
|
|
4152
|
+
return reject(c, "rate_limited", 429, report.signal);
|
|
4153
|
+
}
|
|
4154
|
+
recordClientSignal(observability, report);
|
|
4155
|
+
return c.body(null, 204);
|
|
4156
|
+
}
|
|
4038
4157
|
if (!admission.admit(report.kind)) return reject(c, "rate_limited", 429, report.kind);
|
|
4039
4158
|
observability.incrementCounter({ ...CLIENT_ERRORS_METRIC, labels: { kind: report.kind } });
|
|
4040
4159
|
observability.warn("Web client error reported", {
|
|
@@ -4047,6 +4166,46 @@ function registerClientErrorRoutes(app, deps) {
|
|
|
4047
4166
|
}
|
|
4048
4167
|
);
|
|
4049
4168
|
}
|
|
4169
|
+
function recordClientSignal(observability, report) {
|
|
4170
|
+
switch (report.signal) {
|
|
4171
|
+
case "request_failure":
|
|
4172
|
+
observability.incrementCounter({
|
|
4173
|
+
...CLIENT_REQUEST_FAILURES_METRIC,
|
|
4174
|
+
labels: { action: report.action, reason: report.reason }
|
|
4175
|
+
});
|
|
4176
|
+
observability.warn("Web client request failed before a response", {
|
|
4177
|
+
surface: "web",
|
|
4178
|
+
op: report.action,
|
|
4179
|
+
reason: report.reason,
|
|
4180
|
+
clientRoute: report.route,
|
|
4181
|
+
clientRevision: report.revision
|
|
4182
|
+
});
|
|
4183
|
+
return;
|
|
4184
|
+
case "stream":
|
|
4185
|
+
observability.incrementCounter({
|
|
4186
|
+
...CLIENT_STREAM_EVENTS_METRIC,
|
|
4187
|
+
labels: { stream: report.stream, event: report.event }
|
|
4188
|
+
});
|
|
4189
|
+
if (report.event !== "reconnect") {
|
|
4190
|
+
observability.warn("Web client live stream degraded", {
|
|
4191
|
+
surface: "web",
|
|
4192
|
+
op: report.stream,
|
|
4193
|
+
reason: report.event,
|
|
4194
|
+
clientRoute: report.route,
|
|
4195
|
+
clientRevision: report.revision
|
|
4196
|
+
});
|
|
4197
|
+
}
|
|
4198
|
+
return;
|
|
4199
|
+
case "web_vital":
|
|
4200
|
+
observability.observeHistogram({
|
|
4201
|
+
...CLIENT_WEB_VITAL_METRIC,
|
|
4202
|
+
labels: { metric: report.metric, page: report.page },
|
|
4203
|
+
value: report.value,
|
|
4204
|
+
buckets: CLIENT_WEB_VITAL_BUCKETS
|
|
4205
|
+
});
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4050
4209
|
|
|
4051
4210
|
// src/routes/analytics-consent.ts
|
|
4052
4211
|
import {
|
|
@@ -4263,6 +4422,11 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
4263
4422
|
browser_act: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
4264
4423
|
browser_clipboard: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
4265
4424
|
browser_debug: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
4425
|
+
browser_downloads: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
4426
|
+
browser_download_save: {
|
|
4427
|
+
sessionRequired: true,
|
|
4428
|
+
allOf: ["sessions:control", "files:upload"]
|
|
4429
|
+
},
|
|
4266
4430
|
browser_auth: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
4267
4431
|
interaction_request_human: {
|
|
4268
4432
|
sessionRequired: true,
|
|
@@ -4726,9 +4890,10 @@ import {
|
|
|
4726
4890
|
} from "@opengeni/core";
|
|
4727
4891
|
function projectClientModel(model) {
|
|
4728
4892
|
const anonymousProvider = model.credentialSource.kind === "deployment" && model.credentialSource.mechanism === "none";
|
|
4893
|
+
const directProvider = model.providerId.startsWith("workspace-openai-") || model.providerId.startsWith("workspace-azure-openai-");
|
|
4729
4894
|
const organizationProvider = model.credentialSource.kind === "organization_connection";
|
|
4730
|
-
const source = organizationProvider || model.providerId === "workspace-anthropic" || model.providerId === "workspace-claude-subscription" || model.providerId === OPENROUTER_PROVIDER_ID || model.providerId === WORKSPACE_OPENROUTER_PROVIDER_ID ? void 0 : model.credentialSource.kind === "connected_subscription" ? model.credentialSource.provider === "xai" ? "supergrok" : "codex" : model.credentialSource.kind === "workspace_connection" ? "workspace_gateway" : anonymousProvider ? void 0 : "opengeni";
|
|
4731
|
-
const publicProvider = anonymousProvider || organizationProvider || model.providerId === "workspace-anthropic" || model.providerId === "workspace-claude-subscription" ? { provider: model.providerId, providerLabel: model.providerLabel } : model.providerId === OPENROUTER_PROVIDER_ID ? { provider: "openrouter", providerLabel: "OpenRouter" } : model.providerId === WORKSPACE_OPENROUTER_PROVIDER_ID ? { provider: "workspace-openrouter", providerLabel: "Your OpenRouter" } : source === "codex" ? { provider: "codex", providerLabel: "Codex" } : source === "supergrok" ? { provider: "supergrok", providerLabel: "SuperGrok" } : source === "workspace_gateway" ? { provider: "workspace-gateway", providerLabel: "Your Gateway" } : { provider: "opengeni", providerLabel: "OpenGeni" };
|
|
4895
|
+
const source = directProvider || organizationProvider || model.providerId === "workspace-anthropic" || model.providerId === "workspace-claude-subscription" || model.providerId === OPENROUTER_PROVIDER_ID || model.providerId === WORKSPACE_OPENROUTER_PROVIDER_ID ? void 0 : model.credentialSource.kind === "connected_subscription" ? model.credentialSource.provider === "xai" ? "supergrok" : "codex" : model.credentialSource.kind === "workspace_connection" ? "workspace_gateway" : anonymousProvider ? void 0 : "opengeni";
|
|
4896
|
+
const publicProvider = directProvider || anonymousProvider || organizationProvider || model.providerId === "workspace-anthropic" || model.providerId === "workspace-claude-subscription" ? { provider: model.providerId, providerLabel: model.providerLabel } : model.providerId === OPENROUTER_PROVIDER_ID ? { provider: "openrouter", providerLabel: "OpenRouter" } : model.providerId === WORKSPACE_OPENROUTER_PROVIDER_ID ? { provider: "workspace-openrouter", providerLabel: "Your OpenRouter" } : source === "codex" ? { provider: "codex", providerLabel: "Codex" } : source === "supergrok" ? { provider: "supergrok", providerLabel: "SuperGrok" } : source === "workspace_gateway" ? { provider: "workspace-gateway", providerLabel: "Your Gateway" } : { provider: "opengeni", providerLabel: "OpenGeni" };
|
|
4732
4897
|
return ClientModel.parse({
|
|
4733
4898
|
id: model.id,
|
|
4734
4899
|
label: model.label,
|
|
@@ -5704,7 +5869,8 @@ import {
|
|
|
5704
5869
|
agentConfigDeploymentPolicy as agentConfigDeploymentPolicy3,
|
|
5705
5870
|
configuredAllowedReasoningEfforts,
|
|
5706
5871
|
resolveFirstPartyMcpToolPolicy as resolveFirstPartyMcpToolPolicy2,
|
|
5707
|
-
resolveVoiceInputProviderRegistry as resolveVoiceInputProviderRegistry2
|
|
5872
|
+
resolveVoiceInputProviderRegistry as resolveVoiceInputProviderRegistry2,
|
|
5873
|
+
UnsupportedLatencyModeError as UnsupportedLatencyModeError2
|
|
5708
5874
|
} from "@opengeni/config";
|
|
5709
5875
|
import {
|
|
5710
5876
|
AGENT_CAPABILITY_IDS,
|
|
@@ -5784,7 +5950,11 @@ import { getCookie as getCookie3 } from "hono/cookie";
|
|
|
5784
5950
|
import { HTTPException as HTTPException107 } from "hono/http-exception";
|
|
5785
5951
|
|
|
5786
5952
|
// src/http/api-error.ts
|
|
5787
|
-
import {
|
|
5953
|
+
import {
|
|
5954
|
+
AgentConfigError,
|
|
5955
|
+
AllowanceExhaustedRefusal,
|
|
5956
|
+
ModelUnavailableError
|
|
5957
|
+
} from "@opengeni/contracts";
|
|
5788
5958
|
import { WorkspaceControlBusyError } from "@opengeni/db";
|
|
5789
5959
|
import { HTTPException as HTTPException14 } from "hono/http-exception";
|
|
5790
5960
|
var ApiHttpError = class extends HTTPException14 {
|
|
@@ -5840,6 +6010,17 @@ function agentConfigHttpError(error) {
|
|
|
5840
6010
|
}
|
|
5841
6011
|
});
|
|
5842
6012
|
}
|
|
6013
|
+
function modelUnavailableHttpError(error) {
|
|
6014
|
+
const cause = error instanceof ModelUnavailableError ? error : error instanceof HTTPException14 && error.cause instanceof ModelUnavailableError ? error.cause : null;
|
|
6015
|
+
if (!cause) return null;
|
|
6016
|
+
return new ApiHttpError(422, {
|
|
6017
|
+
code: "validation_failed",
|
|
6018
|
+
message: cause.message,
|
|
6019
|
+
retryable: false,
|
|
6020
|
+
outcomeUnknown: false,
|
|
6021
|
+
details: { code: cause.code, modelId: cause.modelId }
|
|
6022
|
+
});
|
|
6023
|
+
}
|
|
5843
6024
|
|
|
5844
6025
|
// src/http/request-body.ts
|
|
5845
6026
|
import { ZodError } from "zod";
|
|
@@ -6056,19 +6237,19 @@ function ipv6Groups(address) {
|
|
|
6056
6237
|
// src/http/unmatched-route.ts
|
|
6057
6238
|
import { matchedRoutes } from "hono/route";
|
|
6058
6239
|
var PROBED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
6059
|
-
function isTerminalRoute(
|
|
6060
|
-
if (
|
|
6061
|
-
return typeof
|
|
6240
|
+
function isTerminalRoute(route2) {
|
|
6241
|
+
if (route2.method.toUpperCase() !== "ALL") return true;
|
|
6242
|
+
return typeof route2.handler === "function" && route2.handler.length < 2;
|
|
6062
6243
|
}
|
|
6063
6244
|
function routesFor(app, method, path) {
|
|
6064
6245
|
const result = app.router.match(method, path);
|
|
6065
|
-
return result[0].map(([[,
|
|
6246
|
+
return result[0].map(([[, route2]]) => route2);
|
|
6066
6247
|
}
|
|
6067
6248
|
function unmatchedRoute(app, c) {
|
|
6068
6249
|
const method = c.req.method.toUpperCase();
|
|
6069
6250
|
if (method === "OPTIONS") return null;
|
|
6070
6251
|
try {
|
|
6071
|
-
if (matchedRoutes(c).some((
|
|
6252
|
+
if (matchedRoutes(c).some((route2) => isTerminalRoute(route2))) {
|
|
6072
6253
|
return null;
|
|
6073
6254
|
}
|
|
6074
6255
|
const effectiveMethod = method === "HEAD" ? "GET" : method;
|
|
@@ -6114,9 +6295,9 @@ async function isContractRefusal(response) {
|
|
|
6114
6295
|
import { matchedRoutes as matchedRoutes2 } from "hono/route";
|
|
6115
6296
|
function registeredHandlerRoutePath(context) {
|
|
6116
6297
|
try {
|
|
6117
|
-
for (const
|
|
6118
|
-
if (typeof
|
|
6119
|
-
const label = boundedRegisteredRouteLabel(
|
|
6298
|
+
for (const route2 of matchedRoutes2(context)) {
|
|
6299
|
+
if (typeof route2.handler !== "function" || route2.handler.length >= 2) continue;
|
|
6300
|
+
const label = boundedRegisteredRouteLabel(route2.path);
|
|
6120
6301
|
if (label) return label;
|
|
6121
6302
|
}
|
|
6122
6303
|
} catch {
|
|
@@ -10684,6 +10865,7 @@ function ticketBodyTooLarge() {
|
|
|
10684
10865
|
// src/mcp/knowledge-entries.ts
|
|
10685
10866
|
import {
|
|
10686
10867
|
AgentInstructionSaveRequest,
|
|
10868
|
+
WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS,
|
|
10687
10869
|
WorkspaceInstructionPolicyTarget,
|
|
10688
10870
|
KnowledgeEntryListRequest,
|
|
10689
10871
|
KnowledgeSavePreparationRequest,
|
|
@@ -10750,7 +10932,7 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
10750
10932
|
};
|
|
10751
10933
|
}
|
|
10752
10934
|
const state = nestedPostgresSqlState3(error);
|
|
10753
|
-
const message = surface === "instruction" ? state === "40001" ? "This instruction changed. Read its current content and baseline, then retry the same intended edit against that exact state." : state === "23505" ? "This instruction operation ID was already used with different input. Reuse it only for an exact retry." : state === "42501" ? "The instruction change is unavailable in this task's scope or Agent learning policy. Off disables authoring, not the task. Do not ask for approval to continue." : state === "22023" || state === "23514" ?
|
|
10935
|
+
const message = surface === "instruction" ? state === "40001" ? "This instruction changed. Read its current content and baseline, then retry the same intended edit against that exact state." : state === "23505" ? "This instruction operation ID was already used with different input. Reuse it only for an exact retry." : state === "42501" ? "The instruction change is unavailable in this task's scope or Agent learning policy. Off disables authoring, not the task. Do not ask for approval to continue." : state === "22023" || state === "23514" ? `Invalid instruction change. Read the current instruction, use append for a new rule, or edit with one localized exact oldText match to update or remove text. Agents cannot replace the complete instruction. Each supplied text and the resulting instruction must stay within ${WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS} characters, the same limit as the human editor.` : "Workspace instructions are temporarily unavailable. Retry the same operation ID only if the prior change may have succeeded." : state === "40001" ? "This entry changed. Read its current revision and retry your correction with the current version." : state === "23505" ? "This operation ID was already used with different input. Reuse it only for an exact retry." : state === "42501" ? "The entry, reference, or write is unavailable in this task's scope and Agent learning policy. Off disables saving, not your task. Do not ask for an approval to continue." : state === "22023" || state === "23514" ? "Invalid Knowledge entry or relationship. Check the referenced IDs and revision before retrying." : "Knowledge is temporarily unavailable. Your task can continue; retry the same operation ID if saving may have succeeded.";
|
|
10754
10936
|
return {
|
|
10755
10937
|
isError: true,
|
|
10756
10938
|
content: [
|
|
@@ -10935,7 +11117,7 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
10935
11117
|
server.registerTool(
|
|
10936
11118
|
"instruction_policy_save",
|
|
10937
11119
|
{
|
|
10938
|
-
description:
|
|
11120
|
+
description: `Change a concise standing workspace instruction through this task's Agent learning policy. Use for short always-on behavior such as 'Keep replies concise; expand when asked', within the intended workspace scope; active instructions enter applicable prompts without Knowledge retrieval. Read the current policy first and submit its exact baseline. Use editMode=append by default for a new rule; it preserves the current content and adds one blank-line separator. Use edit with a localized oldText that occurs exactly once and newText to update or remove only that passage. Agents cannot replace the complete instruction; direct the user to the manual workspace-instruction editor for a whole-policy rewrite. Each supplied text and the resulting instruction are limited to ${WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS} characters, the same limit as the human editor. Facts and incidents belong in knowledge_save and reusable procedures or context-specific preferences in skill_save. Preserve personal scope rather than creating a workspace-wide rule. Review first saves an inactive revision and returns pending; continue the task without an approval question. Report the actual receipt; Knowledge is not a workaround for Off, pending review, unavailable scope or size limits.`,
|
|
10939
11121
|
inputSchema: AgentInstructionSaveRequest.shape
|
|
10940
11122
|
},
|
|
10941
11123
|
(input) => run((context) => saveAgentInstruction(deps.db, context, input), "instruction")
|
|
@@ -33915,7 +34097,9 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
33915
34097
|
"Model for the worker. Omit to inherit the exact calling turn's model, including its Codex subscription billing path."
|
|
33916
34098
|
),
|
|
33917
34099
|
reasoningEffort: z43.string().optional().describe("Omit to inherit the exact calling turn's reasoning effort."),
|
|
33918
|
-
latencyMode: z43.enum(["standard", "priority", "fast"]).optional().describe(
|
|
34100
|
+
latencyMode: z43.enum(["standard", "priority", "fast"]).optional().describe(
|
|
34101
|
+
"Omit for standard latency, even when model and reasoning are inherited. Fast or priority must be selected explicitly and supported by the model."
|
|
34102
|
+
),
|
|
33919
34103
|
sandboxBackend: z43.string().optional(),
|
|
33920
34104
|
// Model-only structural coupling: workingDir cannot exist without a
|
|
33921
34105
|
// targetSandboxId because both live inside one optional object. The
|
|
@@ -35249,11 +35433,11 @@ function normalizeSessionDiscoveryRevision(value, label) {
|
|
|
35249
35433
|
if (!SESSION_DISCOVERY_REVISION.test(value)) {
|
|
35250
35434
|
throw new Error(`sessions_list ${label} must be a decimal activity revision`);
|
|
35251
35435
|
}
|
|
35252
|
-
const
|
|
35253
|
-
if (
|
|
35436
|
+
const revision2 = BigInt(value);
|
|
35437
|
+
if (revision2 > SESSION_DISCOVERY_REVISION_MAX) {
|
|
35254
35438
|
throw new Error(`sessions_list ${label} exceeds the database activity revision range`);
|
|
35255
35439
|
}
|
|
35256
|
-
return
|
|
35440
|
+
return revision2.toString();
|
|
35257
35441
|
}
|
|
35258
35442
|
function decodeSessionDiscoveryCursor(value) {
|
|
35259
35443
|
try {
|
|
@@ -65662,6 +65846,7 @@ function registerOrganizationIntegrationPolicyRoutes(app, deps) {
|
|
|
65662
65846
|
|
|
65663
65847
|
// src/routes/connections.ts
|
|
65664
65848
|
import { createHash as createHash18, createHmac as createHmac6 } from "crypto";
|
|
65849
|
+
import { verifyDirectModelAccess } from "@opengeni/core";
|
|
65665
65850
|
import {
|
|
65666
65851
|
createConnectionIdempotently,
|
|
65667
65852
|
upsertWorkspaceProviderApiKeyConnection as upsertWorkspaceProviderApiKeyConnection2,
|
|
@@ -65755,6 +65940,7 @@ import {
|
|
|
65755
65940
|
import {
|
|
65756
65941
|
API_INTEGRATION_OAUTH_CREDENTIAL_ROLE as API_INTEGRATION_OAUTH_CREDENTIAL_ROLE3,
|
|
65757
65942
|
ApiIntegrationOAuthStartRequest,
|
|
65943
|
+
DirectModelProviderMetadata,
|
|
65758
65944
|
ConnectionResponse,
|
|
65759
65945
|
CreateConnectionRequest,
|
|
65760
65946
|
FikenInstallRequest as FikenInstallRequest2,
|
|
@@ -67213,6 +67399,28 @@ function registerConnectionRoutes(app, deps) {
|
|
|
67213
67399
|
const grant = access.grant;
|
|
67214
67400
|
const beforeCommit = externalContinuationCommitAuthorizer2(access);
|
|
67215
67401
|
const payload = await parseRequestJson(c, CreateConnectionRequest);
|
|
67402
|
+
if (payload.metadata?.directModelProvider !== void 0 || String(payload.metadata?.credentialRole ?? "").startsWith("direct_")) {
|
|
67403
|
+
const config = DirectModelProviderMetadata.safeParse(payload.metadata?.directModelProvider);
|
|
67404
|
+
const domain = config.success ? new URL(config.data.endpoint ?? "https://api.openai.com/v1").hostname : null;
|
|
67405
|
+
if (!config.success || payload.subjectId !== null || payload.kind !== "api_key" || canonicalProviderDomain(payload.providerDomain) !== domain || payload.metadata?.credentialRole !== `direct_${config.data.provider}` || typeof payload.credential.apiKey !== "string" || !payload.credential.apiKey.trim() || !payload.operationId || payload.expiresAt) {
|
|
67406
|
+
throw new HTTPException44(422, {
|
|
67407
|
+
message: "Invalid OpenAI or Azure OpenAI connection: provide a key, model, and official provider endpoint"
|
|
67408
|
+
});
|
|
67409
|
+
}
|
|
67410
|
+
payload.metadata = { ...payload.metadata, directModelProvider: config.data };
|
|
67411
|
+
if (payload.verifyModelAccess) {
|
|
67412
|
+
await verifyDirectModelAccess(
|
|
67413
|
+
config.data,
|
|
67414
|
+
payload.credential.apiKey,
|
|
67415
|
+
deps.directModelFetch
|
|
67416
|
+
);
|
|
67417
|
+
}
|
|
67418
|
+
} else if (payload.verifyModelAccess) {
|
|
67419
|
+
throw new HTTPException44(422, {
|
|
67420
|
+
message: "Model checks require an OpenAI or Azure OpenAI connection"
|
|
67421
|
+
});
|
|
67422
|
+
}
|
|
67423
|
+
const directModelKey = payload.metadata?.directModelProvider !== void 0;
|
|
67216
67424
|
const persist = async (db2) => {
|
|
67217
67425
|
assertNotReservedSlackBotMetadata(payload.metadata);
|
|
67218
67426
|
assertNotReservedFikenMetadata(payload.metadata);
|
|
@@ -67248,7 +67456,8 @@ function registerConnectionRoutes(app, deps) {
|
|
|
67248
67456
|
kind: payload.kind,
|
|
67249
67457
|
metadata: payload.metadata
|
|
67250
67458
|
});
|
|
67251
|
-
if (!workspaceProviderKind
|
|
67459
|
+
if (!workspaceProviderKind && !directModelKey)
|
|
67460
|
+
assertBrokeredApiKeyCredential(payload.kind, payload.credential);
|
|
67252
67461
|
const connection = workspaceProviderKind ? await (async () => {
|
|
67253
67462
|
const provider = workspaceProviderApiKeyConnectionSpec(workspaceProviderKind);
|
|
67254
67463
|
if (!payload.operationId) {
|
|
@@ -67336,7 +67545,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
67336
67545
|
kind: payload.kind,
|
|
67337
67546
|
metadata: payload.metadata
|
|
67338
67547
|
});
|
|
67339
|
-
return modelKey ? commit(db) : withOrganizationIntegrationAcquisition8(
|
|
67548
|
+
return modelKey || directModelKey ? commit(db) : withOrganizationIntegrationAcquisition8(
|
|
67340
67549
|
db,
|
|
67341
67550
|
{ accountId: grant.accountId, workspaceId },
|
|
67342
67551
|
[null],
|
|
@@ -67857,6 +68066,11 @@ function registerConnectionRoutes(app, deps) {
|
|
|
67857
68066
|
c.req.param("connectionId"),
|
|
67858
68067
|
grant.subjectId
|
|
67859
68068
|
);
|
|
68069
|
+
if (initial?.metadata.directModelProvider !== void 0 || payload.metadata?.directModelProvider !== void 0 || String(payload.metadata?.credentialRole ?? "").startsWith("direct_")) {
|
|
68070
|
+
throw new HTTPException44(422, {
|
|
68071
|
+
message: "Disconnect and reconnect OpenAI or Azure OpenAI to replace its key or deployment"
|
|
68072
|
+
});
|
|
68073
|
+
}
|
|
67860
68074
|
if (!initial || !workspaceProviderApiKeyConnectionKind(initial)) {
|
|
67861
68075
|
await db2.execute(
|
|
67862
68076
|
sql`select id from connections where workspace_id = ${workspaceId}::uuid and id = ${c.req.param("connectionId")}::uuid and (subject_id is null or subject_id = ${grant.subjectId}) for update`
|
|
@@ -69219,6 +69433,7 @@ import {
|
|
|
69219
69433
|
} from "@opengeni/core";
|
|
69220
69434
|
import { withOrganizationIntegrationPolicyFence as withOrganizationIntegrationPolicyFence5 } from "@opengeni/db/organization-integration-policy";
|
|
69221
69435
|
import {
|
|
69436
|
+
ApiIntegrationConnectionReferenceError,
|
|
69222
69437
|
ApiIntegrationInstallationVersionConflictError,
|
|
69223
69438
|
buildConnectionTokenResolver as buildConnectionTokenResolver6,
|
|
69224
69439
|
getApiIntegrationUninstallPreview,
|
|
@@ -69304,14 +69519,14 @@ async function resolveDefinition(input) {
|
|
|
69304
69519
|
);
|
|
69305
69520
|
}
|
|
69306
69521
|
const identity2 = integrationInstallationIdentity("openapi", definition.id, definition.source.url);
|
|
69307
|
-
const
|
|
69522
|
+
const revision2 = compileOpenApiRevision(document, {
|
|
69308
69523
|
definitionId: definition.id,
|
|
69309
69524
|
sourceUrl: definition.source.url,
|
|
69310
69525
|
baseUrl: definition.baseUrl,
|
|
69311
69526
|
provider: definition.provider.id,
|
|
69312
69527
|
...definition.source.kind === "openapi" && definition.source.schemaMode ? { schemaMode: definition.source.schemaMode } : {}
|
|
69313
69528
|
});
|
|
69314
|
-
const baseUrl = firstOpenApiServerUrl(
|
|
69529
|
+
const baseUrl = firstOpenApiServerUrl(revision2);
|
|
69315
69530
|
const providerDomain = definition.provider.domain;
|
|
69316
69531
|
const auth = {
|
|
69317
69532
|
kind: "oauth2",
|
|
@@ -69323,7 +69538,7 @@ async function resolveDefinition(input) {
|
|
|
69323
69538
|
definitionId: definition.id,
|
|
69324
69539
|
definitionProvenance: "curated",
|
|
69325
69540
|
identity: identity2,
|
|
69326
|
-
revision,
|
|
69541
|
+
revision: revision2,
|
|
69327
69542
|
provider: definition.provider.id,
|
|
69328
69543
|
providerDomain,
|
|
69329
69544
|
baseUrl,
|
|
@@ -69348,12 +69563,12 @@ async function resolveOpenApi(input, sourceUrl, baseUrl) {
|
|
|
69348
69563
|
new URL(sourceUrl).hostname,
|
|
69349
69564
|
sourceUrl
|
|
69350
69565
|
);
|
|
69351
|
-
const
|
|
69566
|
+
const revision2 = compileOpenApiRevision(document, {
|
|
69352
69567
|
definitionId: identity2.sourceDerivedDefinitionId,
|
|
69353
69568
|
sourceUrl,
|
|
69354
69569
|
...baseUrl ? { baseUrl } : {}
|
|
69355
69570
|
});
|
|
69356
|
-
const resolvedBaseUrl = firstOpenApiServerUrl(
|
|
69571
|
+
const resolvedBaseUrl = firstOpenApiServerUrl(revision2);
|
|
69357
69572
|
const providerDomain = new URL(resolvedBaseUrl).hostname.toLowerCase();
|
|
69358
69573
|
const discovered = discoverOpenApiAuth(document);
|
|
69359
69574
|
const auth = authPreview(discovered, providerDomain, input.connection);
|
|
@@ -69362,13 +69577,13 @@ async function resolveOpenApi(input, sourceUrl, baseUrl) {
|
|
|
69362
69577
|
definitionId: identity2.sourceDerivedDefinitionId,
|
|
69363
69578
|
definitionProvenance: "workspace",
|
|
69364
69579
|
identity: identity2,
|
|
69365
|
-
revision,
|
|
69580
|
+
revision: revision2,
|
|
69366
69581
|
provider: null,
|
|
69367
69582
|
providerDomain,
|
|
69368
69583
|
baseUrl: resolvedBaseUrl,
|
|
69369
69584
|
sourceUrl,
|
|
69370
|
-
name:
|
|
69371
|
-
description:
|
|
69585
|
+
name: revision2.title,
|
|
69586
|
+
description: revision2.description ?? null,
|
|
69372
69587
|
auth,
|
|
69373
69588
|
connection: input.connection,
|
|
69374
69589
|
requiredScopes: auth.kind === "oauth2" ? auth.scopes : [],
|
|
@@ -69388,9 +69603,9 @@ function resolveInlineOpenApiDocument(input, source) {
|
|
|
69388
69603
|
source.sourceKey,
|
|
69389
69604
|
`document:${source.sourceKey}`
|
|
69390
69605
|
);
|
|
69391
|
-
let
|
|
69606
|
+
let revision2;
|
|
69392
69607
|
try {
|
|
69393
|
-
|
|
69608
|
+
revision2 = compileOpenApiRevision(document, {
|
|
69394
69609
|
definitionId: identity2.sourceDerivedDefinitionId,
|
|
69395
69610
|
...source.baseUrl ? { baseUrl: source.baseUrl } : {}
|
|
69396
69611
|
});
|
|
@@ -69404,7 +69619,7 @@ function resolveInlineOpenApiDocument(input, source) {
|
|
|
69404
69619
|
}
|
|
69405
69620
|
throw error;
|
|
69406
69621
|
}
|
|
69407
|
-
const resolvedBaseUrl = firstOpenApiServerUrl(
|
|
69622
|
+
const resolvedBaseUrl = firstOpenApiServerUrl(revision2);
|
|
69408
69623
|
const providerDomain = new URL(resolvedBaseUrl).hostname.toLowerCase();
|
|
69409
69624
|
const discovered = discoverOpenApiAuth(document);
|
|
69410
69625
|
const auth = authPreview(discovered, providerDomain, input.connection);
|
|
@@ -69418,13 +69633,13 @@ function resolveInlineOpenApiDocument(input, source) {
|
|
|
69418
69633
|
definitionId: identity2.sourceDerivedDefinitionId,
|
|
69419
69634
|
definitionProvenance: "workspace",
|
|
69420
69635
|
identity: identity2,
|
|
69421
|
-
revision,
|
|
69636
|
+
revision: revision2,
|
|
69422
69637
|
provider: null,
|
|
69423
69638
|
providerDomain,
|
|
69424
69639
|
baseUrl: resolvedBaseUrl,
|
|
69425
69640
|
sourceUrl: null,
|
|
69426
|
-
name:
|
|
69427
|
-
description:
|
|
69641
|
+
name: revision2.title,
|
|
69642
|
+
description: revision2.description ?? null,
|
|
69428
69643
|
auth,
|
|
69429
69644
|
connection: input.connection,
|
|
69430
69645
|
requiredScopes: auth.kind === "oauth2" ? auth.scopes : [],
|
|
@@ -69440,7 +69655,7 @@ async function resolveGraphql(input, endpoint, name) {
|
|
|
69440
69655
|
authority: input.authority,
|
|
69441
69656
|
...input.credentialResolver ? { credentialResolver: input.credentialResolver } : {}
|
|
69442
69657
|
});
|
|
69443
|
-
const
|
|
69658
|
+
const revision2 = compileGraphqlRevision(introspection, {
|
|
69444
69659
|
definitionId: identity2.sourceDerivedDefinitionId,
|
|
69445
69660
|
endpoint,
|
|
69446
69661
|
sourceUrl: endpoint,
|
|
@@ -69452,13 +69667,13 @@ async function resolveGraphql(input, endpoint, name) {
|
|
|
69452
69667
|
definitionId: identity2.sourceDerivedDefinitionId,
|
|
69453
69668
|
definitionProvenance: "workspace",
|
|
69454
69669
|
identity: identity2,
|
|
69455
|
-
revision,
|
|
69670
|
+
revision: revision2,
|
|
69456
69671
|
provider: null,
|
|
69457
69672
|
providerDomain,
|
|
69458
69673
|
baseUrl: endpoint,
|
|
69459
69674
|
sourceUrl: endpoint,
|
|
69460
|
-
name:
|
|
69461
|
-
description:
|
|
69675
|
+
name: revision2.title,
|
|
69676
|
+
description: revision2.description ?? null,
|
|
69462
69677
|
auth,
|
|
69463
69678
|
connection: input.connection,
|
|
69464
69679
|
requiredScopes: input.connection?.scopes ?? [],
|
|
@@ -69521,8 +69736,8 @@ function integrationInstallationIdentity(protocol, label, locator2) {
|
|
|
69521
69736
|
serverId: `api_${protocol}_${slug.replaceAll("-", "_").slice(0, 48)}_${hash}`
|
|
69522
69737
|
};
|
|
69523
69738
|
}
|
|
69524
|
-
function firstOpenApiServerUrl(
|
|
69525
|
-
const first = Object.values(
|
|
69739
|
+
function firstOpenApiServerUrl(revision2) {
|
|
69740
|
+
const first = Object.values(revision2.bindings)[0]?.serverUrl;
|
|
69526
69741
|
if (!first) throw new Error("OpenAPI revision has no executable server URL");
|
|
69527
69742
|
return first;
|
|
69528
69743
|
}
|
|
@@ -69780,6 +69995,11 @@ function registerApiIntegrationRoutes(app, deps, overrides = {}) {
|
|
|
69780
69995
|
payload.expectedInstanceVersion === void 0 ? 201 : 200
|
|
69781
69996
|
);
|
|
69782
69997
|
} catch (error) {
|
|
69998
|
+
if (error instanceof ApiIntegrationConnectionReferenceError) {
|
|
69999
|
+
throw new HTTPException47(error.reason === "not_found" ? 404 : 422, {
|
|
70000
|
+
message: error.reason === "not_found" ? "connection not found" : error.message
|
|
70001
|
+
});
|
|
70002
|
+
}
|
|
69783
70003
|
if (error instanceof IntegrationFacetBindingVersionConflictError || error instanceof IntegrationFacetBindingVersionRequiredError || error instanceof IntegrationFacetBindingOwnershipConflictError) {
|
|
69784
70004
|
throw new HTTPException47(409, {
|
|
69785
70005
|
message: "The Integration instance changed or is shared by another owner. Refresh its details before updating it."
|
|
@@ -74503,14 +74723,17 @@ import {
|
|
|
74503
74723
|
OrganizationUsageQuery,
|
|
74504
74724
|
OrganizationUsageWorkspacePageQuery
|
|
74505
74725
|
} from "@opengeni/contracts";
|
|
74726
|
+
import { OrganizationModelUsageQuery } from "@opengeni/contracts/organization-model-usage";
|
|
74506
74727
|
import { configuredEntitlements } from "@opengeni/config";
|
|
74507
74728
|
import {
|
|
74508
74729
|
applyCreditLedgerEntry,
|
|
74509
74730
|
getBillingBalance,
|
|
74510
74731
|
getBillingCustomer,
|
|
74732
|
+
getCreditLedgerEntry,
|
|
74511
74733
|
hasCreditLedgerEntry,
|
|
74512
74734
|
isStripeWebhookProcessed,
|
|
74513
74735
|
listUsageEvents,
|
|
74736
|
+
getOrganizationModelUsage,
|
|
74514
74737
|
getOrganizationUsageSummary,
|
|
74515
74738
|
getOrganizationUsageWorkspacePage,
|
|
74516
74739
|
withSessionRlsActorContext as withSessionRlsActorContext8,
|
|
@@ -74580,6 +74803,21 @@ function registerBillingRoutes(app, deps) {
|
|
|
74580
74803
|
async () => c.json(await getOrganizationUsageWorkspacePage(deps.db, { accountId, ...parsed.data }))
|
|
74581
74804
|
);
|
|
74582
74805
|
});
|
|
74806
|
+
app.get("/v1/billing/usage-models", async (c) => {
|
|
74807
|
+
const context = await requireAccessContext5(c, deps);
|
|
74808
|
+
const accountId = requireSelectedAccount(context, c.req.query("accountId"), "billing:read");
|
|
74809
|
+
const parsed = OrganizationModelUsageQuery.safeParse(c.req.query());
|
|
74810
|
+
if (!parsed.success)
|
|
74811
|
+
throw new HTTPException56(400, {
|
|
74812
|
+
message: parsed.error.issues[0]?.message ?? "invalid model usage query"
|
|
74813
|
+
});
|
|
74814
|
+
return await withBillingUsageActor(
|
|
74815
|
+
deps,
|
|
74816
|
+
context,
|
|
74817
|
+
accountId,
|
|
74818
|
+
async () => c.json(await getOrganizationModelUsage(deps.db, { accountId, ...parsed.data }))
|
|
74819
|
+
);
|
|
74820
|
+
});
|
|
74583
74821
|
app.get("/v1/billing/entitlements", async (c) => {
|
|
74584
74822
|
const context = await requireAccessContext5(c, deps);
|
|
74585
74823
|
const accountId = requireSelectedAccount(context, c.req.query("accountId"), "billing:read");
|
|
@@ -74615,6 +74853,7 @@ function registerBillingRoutes(app, deps) {
|
|
|
74615
74853
|
amountMicros,
|
|
74616
74854
|
creditsProductId: deps.settings.stripeCreditsProductId,
|
|
74617
74855
|
publicBaseUrl: deps.settings.publicBaseUrl,
|
|
74856
|
+
webBaseUrl: deps.settings.webBaseUrl,
|
|
74618
74857
|
successUrl: body3.successUrl,
|
|
74619
74858
|
cancelUrl: body3.cancelUrl,
|
|
74620
74859
|
idempotencyKey
|
|
@@ -74649,6 +74888,7 @@ function registerBillingRoutes(app, deps) {
|
|
|
74649
74888
|
stripeBillingPortalSessionCreateParams({
|
|
74650
74889
|
customerId,
|
|
74651
74890
|
publicBaseUrl: deps.settings.publicBaseUrl,
|
|
74891
|
+
webBaseUrl: deps.settings.webBaseUrl,
|
|
74652
74892
|
returnUrl: parsed.data.returnUrl
|
|
74653
74893
|
})
|
|
74654
74894
|
);
|
|
@@ -74708,18 +74948,21 @@ function registerBillingRoutes(app, deps) {
|
|
|
74708
74948
|
function stripeCheckoutSessionCreateParams(input) {
|
|
74709
74949
|
const successUrl = checkoutReturnUrl(
|
|
74710
74950
|
input.publicBaseUrl,
|
|
74951
|
+
input.webBaseUrl,
|
|
74711
74952
|
input.successUrl,
|
|
74712
74953
|
"/billing?checkout=success",
|
|
74713
74954
|
"successUrl"
|
|
74714
74955
|
);
|
|
74715
74956
|
const cancelUrl = checkoutReturnUrl(
|
|
74716
74957
|
input.publicBaseUrl,
|
|
74958
|
+
input.webBaseUrl,
|
|
74717
74959
|
input.cancelUrl,
|
|
74718
74960
|
"/billing?checkout=cancelled",
|
|
74719
74961
|
"cancelUrl"
|
|
74720
74962
|
);
|
|
74721
74963
|
return {
|
|
74722
74964
|
mode: "payment",
|
|
74965
|
+
allow_promotion_codes: true,
|
|
74723
74966
|
customer: input.customerId,
|
|
74724
74967
|
customer_update: {
|
|
74725
74968
|
address: "auto",
|
|
@@ -74751,14 +74994,16 @@ function stripeCheckoutSessionCreateParams(input) {
|
|
|
74751
74994
|
opengeni_account_id: input.accountId,
|
|
74752
74995
|
opengeni_credit_amount_usd: (input.amountCents / 100).toFixed(2),
|
|
74753
74996
|
opengeni_credit_micros: String(input.amountMicros),
|
|
74754
|
-
opengeni_credit_idempotency_key: input.idempotencyKey
|
|
74997
|
+
opengeni_credit_idempotency_key: input.idempotencyKey,
|
|
74998
|
+
opengeni_credit_coupon_v1: "1"
|
|
74755
74999
|
},
|
|
74756
75000
|
payment_intent_data: {
|
|
74757
75001
|
metadata: {
|
|
74758
75002
|
opengeni_account_id: input.accountId,
|
|
74759
75003
|
opengeni_credit_amount_usd: (input.amountCents / 100).toFixed(2),
|
|
74760
75004
|
opengeni_credit_micros: String(input.amountMicros),
|
|
74761
|
-
opengeni_credit_idempotency_key: input.idempotencyKey
|
|
75005
|
+
opengeni_credit_idempotency_key: input.idempotencyKey,
|
|
75006
|
+
opengeni_credit_coupon_v1: "1"
|
|
74762
75007
|
}
|
|
74763
75008
|
},
|
|
74764
75009
|
invoice_creation: {
|
|
@@ -74768,7 +75013,8 @@ function stripeCheckoutSessionCreateParams(input) {
|
|
|
74768
75013
|
opengeni_account_id: input.accountId,
|
|
74769
75014
|
opengeni_credit_amount_usd: (input.amountCents / 100).toFixed(2),
|
|
74770
75015
|
opengeni_credit_micros: String(input.amountMicros),
|
|
74771
|
-
opengeni_credit_idempotency_key: input.idempotencyKey
|
|
75016
|
+
opengeni_credit_idempotency_key: input.idempotencyKey,
|
|
75017
|
+
opengeni_credit_coupon_v1: "1"
|
|
74772
75018
|
}
|
|
74773
75019
|
}
|
|
74774
75020
|
}
|
|
@@ -74777,23 +75023,32 @@ function stripeCheckoutSessionCreateParams(input) {
|
|
|
74777
75023
|
function stripeBillingPortalSessionCreateParams(input) {
|
|
74778
75024
|
return {
|
|
74779
75025
|
customer: input.customerId,
|
|
74780
|
-
return_url: checkoutReturnUrl(
|
|
75026
|
+
return_url: checkoutReturnUrl(
|
|
75027
|
+
input.publicBaseUrl,
|
|
75028
|
+
input.webBaseUrl,
|
|
75029
|
+
input.returnUrl,
|
|
75030
|
+
"/billing",
|
|
75031
|
+
"returnUrl"
|
|
75032
|
+
)
|
|
74781
75033
|
};
|
|
74782
75034
|
}
|
|
74783
|
-
function checkoutReturnUrl(publicBaseUrl, candidate, fallbackPath, field) {
|
|
75035
|
+
function checkoutReturnUrl(publicBaseUrl, webBaseUrl, candidate, fallbackPath, field) {
|
|
74784
75036
|
if (!publicBaseUrl) {
|
|
74785
75037
|
throw new HTTPException56(500, {
|
|
74786
75038
|
message: "OPENGENI_PUBLIC_BASE_URL is required for Stripe redirects"
|
|
74787
75039
|
});
|
|
74788
75040
|
}
|
|
74789
|
-
const base = new URL(publicBaseUrl);
|
|
75041
|
+
const base = new URL(webBaseUrl ?? publicBaseUrl);
|
|
74790
75042
|
const fallback = new URL(fallbackPath, base).toString();
|
|
74791
75043
|
if (!candidate) {
|
|
74792
75044
|
return fallback;
|
|
74793
75045
|
}
|
|
74794
75046
|
const parsed = new URL(candidate);
|
|
74795
|
-
|
|
74796
|
-
|
|
75047
|
+
const allowedOrigins2 = /* @__PURE__ */ new Set([new URL(publicBaseUrl).origin, base.origin]);
|
|
75048
|
+
if (!allowedOrigins2.has(parsed.origin)) {
|
|
75049
|
+
throw new HTTPException56(400, {
|
|
75050
|
+
message: `${field} must use the OpenGeni public${allowedOrigins2.size > 1 ? " or web" : ""} origin`
|
|
75051
|
+
});
|
|
74797
75052
|
}
|
|
74798
75053
|
return parsed.toString();
|
|
74799
75054
|
}
|
|
@@ -74845,13 +75100,17 @@ function stripeCheckoutCreditDecision(session) {
|
|
|
74845
75100
|
if (session.mode !== "payment") {
|
|
74846
75101
|
return { action: "ignore", reason: "not_payment_mode" };
|
|
74847
75102
|
}
|
|
74848
|
-
if (session.payment_status !== "paid") {
|
|
75103
|
+
if (session.payment_status !== "paid" && !isFreeCouponCheckout(session)) {
|
|
74849
75104
|
return { action: "ignore", reason: "payment_not_paid" };
|
|
74850
75105
|
}
|
|
74851
|
-
|
|
74852
|
-
|
|
74853
|
-
|
|
74854
|
-
}
|
|
75106
|
+
const credit = creditMetadata(session.metadata, `Stripe checkout session ${session.id}`);
|
|
75107
|
+
if (session.metadata?.opengeni_credit_coupon_v1 === "1" && (session.currency !== "usd" || session.amount_subtotal !== credit.amountMicros / 1e4 || typeof session.amount_total !== "number" || !Number.isSafeInteger(session.amount_total) || session.amount_total < 0)) {
|
|
75108
|
+
throw new Error(`Stripe checkout session ${session.id} has invalid credit package totals`);
|
|
75109
|
+
}
|
|
75110
|
+
return { action: "grant", credit };
|
|
75111
|
+
}
|
|
75112
|
+
function isFreeCouponCheckout(session) {
|
|
75113
|
+
return (session.payment_status === "paid" || session.payment_status === "no_payment_required") && session.status === "complete" && session.amount_total === 0 && typeof session.amount_subtotal === "number" && session.amount_subtotal > 0 && (session.total_details?.amount_discount ?? 0) >= session.amount_subtotal;
|
|
74855
75114
|
}
|
|
74856
75115
|
async function handleCheckoutSessionPayment(deps, event) {
|
|
74857
75116
|
const session = event.data.object;
|
|
@@ -74866,6 +75125,7 @@ async function handleCheckoutSessionPayment(deps, event) {
|
|
|
74866
75125
|
return;
|
|
74867
75126
|
}
|
|
74868
75127
|
const credit = decision.credit;
|
|
75128
|
+
const freeCouponCheckout = isFreeCouponCheckout(session);
|
|
74869
75129
|
if (!await getManagedAccount2(deps.db, credit.accountId)) {
|
|
74870
75130
|
console.info(
|
|
74871
75131
|
"[api] stripe webhook ignored a checkout session for an account not in this deployment",
|
|
@@ -74887,19 +75147,23 @@ async function handleCheckoutSessionPayment(deps, event) {
|
|
|
74887
75147
|
}
|
|
74888
75148
|
await applyCreditLedgerEntry(deps.db, {
|
|
74889
75149
|
accountId: credit.accountId,
|
|
74890
|
-
type: "credit_topup",
|
|
75150
|
+
type: freeCouponCheckout ? "grant" : "credit_topup",
|
|
74891
75151
|
amountMicros: credit.amountMicros,
|
|
74892
|
-
sourceType: "stripe_checkout_session",
|
|
75152
|
+
sourceType: freeCouponCheckout ? "stripe_checkout_coupon" : "stripe_checkout_session",
|
|
74893
75153
|
sourceId: session.id,
|
|
74894
75154
|
idempotencyKey: credit.idempotencyKey,
|
|
74895
75155
|
metadata: {
|
|
74896
75156
|
stripeEventId: event.id,
|
|
74897
75157
|
stripePaymentIntentId: typeof session.payment_intent === "string" ? session.payment_intent : session.payment_intent?.id ?? null,
|
|
74898
75158
|
stripePackageId: credit.packageId,
|
|
74899
|
-
stripeCreditAmountUsd: credit.amountUsd
|
|
75159
|
+
stripeCreditAmountUsd: credit.amountUsd,
|
|
75160
|
+
...session.metadata?.opengeni_credit_coupon_v1 === "1" ? {
|
|
75161
|
+
stripeAmountTotalCents: session.amount_total,
|
|
75162
|
+
stripeDiscountCents: session.total_details?.amount_discount ?? 0
|
|
75163
|
+
} : {}
|
|
74900
75164
|
}
|
|
74901
75165
|
});
|
|
74902
|
-
recordCreditMicrosMetric(deps, "topup", credit.amountMicros);
|
|
75166
|
+
recordCreditMicrosMetric(deps, freeCouponCheckout ? "grant" : "topup", credit.amountMicros);
|
|
74903
75167
|
}
|
|
74904
75168
|
async function mirrorPaymentIntentCustomer(deps, event) {
|
|
74905
75169
|
const intent = event.data.object;
|
|
@@ -74936,19 +75200,21 @@ async function applyRefundDebit(deps, stripe, refund) {
|
|
|
74936
75200
|
if (await hasCreditLedgerEntry(deps.db, accountId, idempotencyKey)) {
|
|
74937
75201
|
return;
|
|
74938
75202
|
}
|
|
75203
|
+
const debitMicros = await creditAdjustmentMicros(deps, metadata, refund.amount);
|
|
74939
75204
|
await applyCreditLedgerEntry(deps.db, {
|
|
74940
75205
|
accountId,
|
|
74941
75206
|
type: "credit_refund",
|
|
74942
|
-
amountMicros: -
|
|
75207
|
+
amountMicros: -debitMicros,
|
|
74943
75208
|
sourceType: "stripe_refund",
|
|
74944
75209
|
sourceId: refund.id,
|
|
74945
75210
|
idempotencyKey,
|
|
74946
75211
|
metadata: {
|
|
74947
75212
|
stripeRefundId: refund.id,
|
|
74948
|
-
stripePaymentIntentId: paymentIntentId(refund.payment_intent)
|
|
75213
|
+
stripePaymentIntentId: paymentIntentId(refund.payment_intent),
|
|
75214
|
+
stripeRefundAmountCents: refund.amount
|
|
74949
75215
|
}
|
|
74950
75216
|
});
|
|
74951
|
-
recordCreditMicrosMetric(deps, "refund",
|
|
75217
|
+
recordCreditMicrosMetric(deps, "refund", debitMicros);
|
|
74952
75218
|
}
|
|
74953
75219
|
async function holdDisputedCredits(deps, stripe, event) {
|
|
74954
75220
|
const dispute = event.data.object;
|
|
@@ -74957,10 +75223,11 @@ async function holdDisputedCredits(deps, stripe, event) {
|
|
|
74957
75223
|
if (!accountId) {
|
|
74958
75224
|
return;
|
|
74959
75225
|
}
|
|
75226
|
+
const debitMicros = await creditAdjustmentMicros(deps, metadata, dispute.amount);
|
|
74960
75227
|
await applyCreditLedgerEntry(deps.db, {
|
|
74961
75228
|
accountId,
|
|
74962
75229
|
type: "credit_dispute_hold",
|
|
74963
|
-
amountMicros: -
|
|
75230
|
+
amountMicros: -debitMicros,
|
|
74964
75231
|
sourceType: "stripe_dispute",
|
|
74965
75232
|
sourceId: dispute.id,
|
|
74966
75233
|
idempotencyKey: `stripe:dispute_hold:${dispute.id}`,
|
|
@@ -74981,16 +75248,30 @@ async function releaseDisputedCredits(deps, stripe, event) {
|
|
|
74981
75248
|
if (!await hasCreditLedgerEntry(deps.db, accountId, holdIdempotencyKey)) {
|
|
74982
75249
|
return;
|
|
74983
75250
|
}
|
|
75251
|
+
const debitMicros = await creditAdjustmentMicros(deps, metadata, dispute.amount);
|
|
74984
75252
|
await applyCreditLedgerEntry(deps.db, {
|
|
74985
75253
|
accountId,
|
|
74986
75254
|
type: "credit_dispute_release",
|
|
74987
|
-
amountMicros:
|
|
75255
|
+
amountMicros: debitMicros,
|
|
74988
75256
|
sourceType: "stripe_dispute",
|
|
74989
75257
|
sourceId: dispute.id,
|
|
74990
75258
|
idempotencyKey: `stripe:dispute_release:${dispute.id}`,
|
|
74991
75259
|
metadata: { stripeDisputeId: dispute.id, stripeEventType: event.type }
|
|
74992
75260
|
});
|
|
74993
75261
|
}
|
|
75262
|
+
async function creditAdjustmentMicros(deps, metadata, amountCents) {
|
|
75263
|
+
if (metadata?.opengeni_credit_coupon_v1 !== "1") return centsToMicros(amountCents);
|
|
75264
|
+
const credit = creditMetadata(metadata, "Stripe adjustment");
|
|
75265
|
+
const entry2 = await getCreditLedgerEntry(deps.db, credit.accountId, credit.idempotencyKey);
|
|
75266
|
+
const paidCents = entry2?.metadata.stripeAmountTotalCents;
|
|
75267
|
+
if (entry2?.sourceType !== "stripe_checkout_session" || entry2.amountMicros !== credit.amountMicros || typeof paidCents !== "number" || !Number.isSafeInteger(paidCents) || paidCents <= 0 || !Number.isSafeInteger(amountCents) || amountCents <= 0) {
|
|
75268
|
+
throw new Error("Stripe credit adjustment is missing a settled checkout");
|
|
75269
|
+
}
|
|
75270
|
+
const proportionalMicros = (BigInt(entry2.amountMicros) * BigInt(amountCents) + BigInt(Math.floor(paidCents / 2))) / BigInt(paidCents);
|
|
75271
|
+
return Number(
|
|
75272
|
+
proportionalMicros > BigInt(entry2.amountMicros) ? entry2.amountMicros : proportionalMicros
|
|
75273
|
+
);
|
|
75274
|
+
}
|
|
74994
75275
|
async function mirrorCustomer(deps, event, customer) {
|
|
74995
75276
|
const accountId = customer.metadata?.opengeni_account_id;
|
|
74996
75277
|
if (!accountId || customer.deleted) {
|
|
@@ -75015,14 +75296,14 @@ function recordCreditMicrosMetric(deps, kind, amountMicros) {
|
|
|
75015
75296
|
});
|
|
75016
75297
|
}
|
|
75017
75298
|
async function metadataForRefund(stripe, refund) {
|
|
75018
|
-
if (
|
|
75299
|
+
if (refund.metadata?.opengeni_credit_idempotency_key) {
|
|
75019
75300
|
return refund.metadata;
|
|
75020
75301
|
}
|
|
75021
75302
|
const paymentIntent = paymentIntentId(refund.payment_intent);
|
|
75022
|
-
return paymentIntent ? (await stripe.paymentIntents.retrieve(paymentIntent)).metadata :
|
|
75303
|
+
return paymentIntent ? (await stripe.paymentIntents.retrieve(paymentIntent)).metadata : refund.metadata;
|
|
75023
75304
|
}
|
|
75024
75305
|
async function metadataForDispute(stripe, dispute) {
|
|
75025
|
-
if (
|
|
75306
|
+
if (dispute.metadata?.opengeni_credit_idempotency_key) {
|
|
75026
75307
|
return dispute.metadata;
|
|
75027
75308
|
}
|
|
75028
75309
|
const paymentIntent = paymentIntentId(
|
|
@@ -75033,7 +75314,7 @@ async function metadataForDispute(stripe, dispute) {
|
|
|
75033
75314
|
}
|
|
75034
75315
|
const chargeId = typeof dispute.charge === "string" ? dispute.charge : dispute.charge?.id;
|
|
75035
75316
|
if (!chargeId) {
|
|
75036
|
-
return
|
|
75317
|
+
return dispute.metadata;
|
|
75037
75318
|
}
|
|
75038
75319
|
const charge = await stripe.charges.retrieve(chargeId);
|
|
75039
75320
|
const chargePaymentIntent = paymentIntentId(charge.payment_intent);
|
|
@@ -76430,6 +76711,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
76430
76711
|
await authorizeSourceSession2(deps, grant, request.sessionId, "session.control");
|
|
76431
76712
|
const origin = requestOrigin(context, deps.settings);
|
|
76432
76713
|
const authority = browserAuthorityRoot(deps);
|
|
76714
|
+
let prepared = null;
|
|
76433
76715
|
try {
|
|
76434
76716
|
assertEphemeralBrowserCreateEnabled(
|
|
76435
76717
|
request,
|
|
@@ -76446,7 +76728,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
76446
76728
|
);
|
|
76447
76729
|
}
|
|
76448
76730
|
if (existing) assertCreateReplay(request, existing.session);
|
|
76449
|
-
|
|
76731
|
+
prepared = existing ? await prepareBrowserSessionCreate(
|
|
76450
76732
|
deps.db,
|
|
76451
76733
|
browserCreateInput(grant, workspaceId, request, existing.session.placement)
|
|
76452
76734
|
) : null;
|
|
@@ -76661,6 +76943,16 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
76661
76943
|
parsed.operation.state === "completed" && !parsed.operation.replayed ? 201 : 200
|
|
76662
76944
|
);
|
|
76663
76945
|
} catch (error) {
|
|
76946
|
+
if (prepared) {
|
|
76947
|
+
await failBrowserSessionOperation(deps.db, {
|
|
76948
|
+
accountId: grant.accountId,
|
|
76949
|
+
workspaceId,
|
|
76950
|
+
operationId: request.operationId,
|
|
76951
|
+
browserSessionId: prepared.session.id,
|
|
76952
|
+
onlyIfPreparedCreate: true,
|
|
76953
|
+
error: interactionFailure(error)
|
|
76954
|
+
}).catch(() => void 0);
|
|
76955
|
+
}
|
|
76664
76956
|
throw browserRouteError(error);
|
|
76665
76957
|
}
|
|
76666
76958
|
});
|
|
@@ -79662,6 +79954,7 @@ async function ensureInteractionHolder(deps, grant, sourceSession, browserSessio
|
|
|
79662
79954
|
},
|
|
79663
79955
|
os: placement.lease.os,
|
|
79664
79956
|
image: sandboxRuntime.image,
|
|
79957
|
+
imagePolicy: "new_creates_only",
|
|
79665
79958
|
rigVersionId: sourceSession.rigVersionId,
|
|
79666
79959
|
leaseTtlMs: deps.settings.sandboxLeaseTtlMs,
|
|
79667
79960
|
expectedEpoch: placement.lease.leaseEpoch,
|
|
@@ -80059,10 +80352,10 @@ async function resolveBrowserNetworkRouteLaunch(input) {
|
|
|
80059
80352
|
browserSessionId: input.browserSessionId,
|
|
80060
80353
|
operationId: input.operationId
|
|
80061
80354
|
});
|
|
80062
|
-
const
|
|
80063
|
-
if (!
|
|
80064
|
-
const kind =
|
|
80065
|
-
const providerRoute = kind === "managed" ? managedNetworkRouteForPlacement(
|
|
80355
|
+
const route2 = record6.networkRouteAuthority;
|
|
80356
|
+
if (!route2) return null;
|
|
80357
|
+
const kind = route2.configuration.kind;
|
|
80358
|
+
const providerRoute = kind === "managed" ? managedNetworkRouteForPlacement(route2.configuration, route2.consistency, input.placement) : void 0;
|
|
80066
80359
|
if (kind !== "managed" && input.placement.kind === "external_provider") {
|
|
80067
80360
|
throw new BrowserSessionStateError2(
|
|
80068
80361
|
"External browser providers require a provider-managed NetworkRoute"
|
|
@@ -80073,7 +80366,7 @@ async function resolveBrowserNetworkRouteLaunch(input) {
|
|
|
80073
80366
|
let proxyUrl;
|
|
80074
80367
|
const dispatched = record6.operation?.state === "dispatched";
|
|
80075
80368
|
if (kind === "proxy") {
|
|
80076
|
-
const reference =
|
|
80369
|
+
const reference = route2.configuration.credential;
|
|
80077
80370
|
if (reference) {
|
|
80078
80371
|
try {
|
|
80079
80372
|
const credential = await loadExactInteractionCredential(
|
|
@@ -80085,27 +80378,27 @@ async function resolveBrowserNetworkRouteLaunch(input) {
|
|
|
80085
80378
|
credentialVersion = credential.version;
|
|
80086
80379
|
proxyCredential = proxyCredentialFromBundle(credential.credential);
|
|
80087
80380
|
} catch (error) {
|
|
80088
|
-
if (
|
|
80089
|
-
return secretlessNetworkRouteReplay(
|
|
80381
|
+
if (route2.authorityDigest && dispatched) {
|
|
80382
|
+
return secretlessNetworkRouteReplay(route2, kind, providerRoute);
|
|
80090
80383
|
}
|
|
80091
80384
|
throw error;
|
|
80092
80385
|
}
|
|
80093
|
-
if (dispatched &&
|
|
80094
|
-
return secretlessNetworkRouteReplay(
|
|
80386
|
+
if (dispatched && route2.credentialVersion !== credentialVersion) {
|
|
80387
|
+
return secretlessNetworkRouteReplay(route2, kind, providerRoute);
|
|
80095
80388
|
}
|
|
80096
80389
|
}
|
|
80097
|
-
proxyUrl = browserProxyUrl(
|
|
80390
|
+
proxyUrl = browserProxyUrl(route2.configuration, proxyCredential);
|
|
80098
80391
|
}
|
|
80099
80392
|
if (dispatched) {
|
|
80100
|
-
if (!
|
|
80393
|
+
if (!route2.authorityDigest) {
|
|
80101
80394
|
throw new BrowserSessionStateError2("BrowserSession route authority is not bound");
|
|
80102
80395
|
}
|
|
80103
80396
|
return {
|
|
80104
|
-
routeId:
|
|
80105
|
-
routeVersion:
|
|
80106
|
-
authorityDigest:
|
|
80397
|
+
routeId: route2.routeId,
|
|
80398
|
+
routeVersion: route2.routeVersion,
|
|
80399
|
+
authorityDigest: route2.authorityDigest,
|
|
80107
80400
|
kind,
|
|
80108
|
-
consistency:
|
|
80401
|
+
consistency: route2.consistency,
|
|
80109
80402
|
...proxyUrl === void 0 ? {} : { proxyUrl },
|
|
80110
80403
|
...providerRoute === void 0 ? {} : { providerRoute }
|
|
80111
80404
|
};
|
|
@@ -80115,11 +80408,11 @@ async function resolveBrowserNetworkRouteLaunch(input) {
|
|
|
80115
80408
|
accountId: input.grant.accountId,
|
|
80116
80409
|
workspaceId: input.workspaceId,
|
|
80117
80410
|
browserSessionId: input.browserSessionId,
|
|
80118
|
-
routeId:
|
|
80119
|
-
routeVersion:
|
|
80411
|
+
routeId: route2.routeId,
|
|
80412
|
+
routeVersion: route2.routeVersion,
|
|
80120
80413
|
credentialVersion,
|
|
80121
|
-
configuration:
|
|
80122
|
-
consistency:
|
|
80414
|
+
configuration: route2.configuration,
|
|
80415
|
+
consistency: route2.consistency,
|
|
80123
80416
|
proxyCredential
|
|
80124
80417
|
});
|
|
80125
80418
|
const bound = await bindBrowserSessionNetworkRouteAuthority(input.deps.db, {
|
|
@@ -80127,7 +80420,7 @@ async function resolveBrowserNetworkRouteLaunch(input) {
|
|
|
80127
80420
|
workspaceId: input.workspaceId,
|
|
80128
80421
|
browserSessionId: input.browserSessionId,
|
|
80129
80422
|
operationId: input.operationId,
|
|
80130
|
-
routeVersion:
|
|
80423
|
+
routeVersion: route2.routeVersion,
|
|
80131
80424
|
credentialVersion,
|
|
80132
80425
|
authorityDigest
|
|
80133
80426
|
});
|
|
@@ -80135,23 +80428,23 @@ async function resolveBrowserNetworkRouteLaunch(input) {
|
|
|
80135
80428
|
throw new BrowserSessionOperationConflictError("BrowserSession route launch authority changed");
|
|
80136
80429
|
}
|
|
80137
80430
|
return {
|
|
80138
|
-
routeId:
|
|
80139
|
-
routeVersion:
|
|
80431
|
+
routeId: route2.routeId,
|
|
80432
|
+
routeVersion: route2.routeVersion,
|
|
80140
80433
|
authorityDigest,
|
|
80141
80434
|
kind,
|
|
80142
|
-
consistency:
|
|
80435
|
+
consistency: route2.consistency,
|
|
80143
80436
|
...proxyUrl === void 0 ? {} : { proxyUrl },
|
|
80144
80437
|
...providerRoute === void 0 ? {} : { providerRoute }
|
|
80145
80438
|
};
|
|
80146
80439
|
}
|
|
80147
80440
|
async function resolveActiveBrowserNetworkRouteLaunch(input) {
|
|
80148
|
-
const
|
|
80149
|
-
if (!
|
|
80150
|
-
if (!
|
|
80441
|
+
const route2 = input.record.networkRouteAuthority;
|
|
80442
|
+
if (!route2) return null;
|
|
80443
|
+
if (!route2.authorityDigest) {
|
|
80151
80444
|
throw new BrowserSessionStateError2("BrowserSession route authority is not bound");
|
|
80152
80445
|
}
|
|
80153
|
-
const kind =
|
|
80154
|
-
const providerRoute = kind === "managed" ? managedNetworkRouteForPlacement(
|
|
80446
|
+
const kind = route2.configuration.kind;
|
|
80447
|
+
const providerRoute = kind === "managed" ? managedNetworkRouteForPlacement(route2.configuration, route2.consistency, input.placement) : void 0;
|
|
80155
80448
|
if (kind !== "managed" && input.placement.kind === "external_provider") {
|
|
80156
80449
|
throw new BrowserSessionStateError2(
|
|
80157
80450
|
"External browser providers require a provider-managed NetworkRoute"
|
|
@@ -80159,7 +80452,7 @@ async function resolveActiveBrowserNetworkRouteLaunch(input) {
|
|
|
80159
80452
|
}
|
|
80160
80453
|
let proxyUrl;
|
|
80161
80454
|
if (kind === "proxy") {
|
|
80162
|
-
const reference =
|
|
80455
|
+
const reference = route2.configuration.credential;
|
|
80163
80456
|
let proxyCredential = null;
|
|
80164
80457
|
if (reference) {
|
|
80165
80458
|
const credential = await loadExactInteractionCredential(
|
|
@@ -80168,35 +80461,35 @@ async function resolveActiveBrowserNetworkRouteLaunch(input) {
|
|
|
80168
80461
|
input.record.session.workspaceId,
|
|
80169
80462
|
reference
|
|
80170
80463
|
);
|
|
80171
|
-
if (credential.version !==
|
|
80464
|
+
if (credential.version !== route2.credentialVersion) {
|
|
80172
80465
|
throw new BrowserSessionStateError2(
|
|
80173
80466
|
"BrowserSession proxy credential changed; resume the browser to reconnect safely"
|
|
80174
80467
|
);
|
|
80175
80468
|
}
|
|
80176
80469
|
proxyCredential = proxyCredentialFromBundle(credential.credential);
|
|
80177
80470
|
}
|
|
80178
|
-
proxyUrl = browserProxyUrl(
|
|
80471
|
+
proxyUrl = browserProxyUrl(route2.configuration, proxyCredential);
|
|
80179
80472
|
}
|
|
80180
80473
|
return {
|
|
80181
|
-
routeId:
|
|
80182
|
-
routeVersion:
|
|
80183
|
-
authorityDigest:
|
|
80474
|
+
routeId: route2.routeId,
|
|
80475
|
+
routeVersion: route2.routeVersion,
|
|
80476
|
+
authorityDigest: route2.authorityDigest,
|
|
80184
80477
|
kind,
|
|
80185
|
-
consistency:
|
|
80478
|
+
consistency: route2.consistency,
|
|
80186
80479
|
...proxyUrl === void 0 ? {} : { proxyUrl },
|
|
80187
80480
|
...providerRoute === void 0 ? {} : { providerRoute }
|
|
80188
80481
|
};
|
|
80189
80482
|
}
|
|
80190
|
-
function secretlessNetworkRouteReplay(
|
|
80191
|
-
if (!
|
|
80483
|
+
function secretlessNetworkRouteReplay(route2, kind, providerRoute) {
|
|
80484
|
+
if (!route2.authorityDigest) {
|
|
80192
80485
|
throw new BrowserSessionStateError2("BrowserSession route authority is not bound");
|
|
80193
80486
|
}
|
|
80194
80487
|
return {
|
|
80195
|
-
routeId:
|
|
80196
|
-
routeVersion:
|
|
80197
|
-
authorityDigest:
|
|
80488
|
+
routeId: route2.routeId,
|
|
80489
|
+
routeVersion: route2.routeVersion,
|
|
80490
|
+
authorityDigest: route2.authorityDigest,
|
|
80198
80491
|
kind,
|
|
80199
|
-
consistency:
|
|
80492
|
+
consistency: route2.consistency,
|
|
80200
80493
|
...providerRoute === void 0 ? {} : { providerRoute }
|
|
80201
80494
|
};
|
|
80202
80495
|
}
|
|
@@ -80633,6 +80926,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
80633
80926
|
await authorizeSourceSession3(deps, grant, request.sessionId, "session.control");
|
|
80634
80927
|
const origin = requestOrigin2(context, deps.settings);
|
|
80635
80928
|
const authority = controllerAuthorityRoot(deps);
|
|
80929
|
+
let prepared = null;
|
|
80636
80930
|
try {
|
|
80637
80931
|
const existing = await findComputerSessionControlRecordByOperation(deps.db, {
|
|
80638
80932
|
accountId: grant.accountId,
|
|
@@ -80645,7 +80939,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
80645
80939
|
);
|
|
80646
80940
|
}
|
|
80647
80941
|
if (existing) assertCreateReplay2(request, existing.session);
|
|
80648
|
-
|
|
80942
|
+
prepared = existing ? await prepareComputerSessionCreate(
|
|
80649
80943
|
deps.db,
|
|
80650
80944
|
computerCreateInput(grant, workspaceId, request, existing.session.placement)
|
|
80651
80945
|
) : null;
|
|
@@ -80791,6 +81085,16 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
80791
81085
|
parsed.operation.state === "completed" && !parsed.operation.replayed ? 201 : 200
|
|
80792
81086
|
);
|
|
80793
81087
|
} catch (error) {
|
|
81088
|
+
if (prepared) {
|
|
81089
|
+
await failComputerSessionOperation(deps.db, {
|
|
81090
|
+
accountId: grant.accountId,
|
|
81091
|
+
workspaceId,
|
|
81092
|
+
operationId: request.operationId,
|
|
81093
|
+
computerSessionId: prepared.session.id,
|
|
81094
|
+
onlyIfPreparedCreate: true,
|
|
81095
|
+
error: interactionFailure2(error)
|
|
81096
|
+
}).catch(() => void 0);
|
|
81097
|
+
}
|
|
80794
81098
|
throw computerRouteError(error);
|
|
80795
81099
|
}
|
|
80796
81100
|
});
|
|
@@ -81669,6 +81973,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
81669
81973
|
},
|
|
81670
81974
|
os: placement.lease.os,
|
|
81671
81975
|
image: sandboxRuntime.image,
|
|
81976
|
+
imagePolicy: "new_creates_only",
|
|
81672
81977
|
rigVersionId: sourceSession.rigVersionId,
|
|
81673
81978
|
leaseTtlMs: deps.settings.sandboxLeaseTtlMs,
|
|
81674
81979
|
expectedEpoch: placement.lease.leaseEpoch,
|
|
@@ -84707,7 +85012,7 @@ import {
|
|
|
84707
85012
|
} from "@opengeni/contracts";
|
|
84708
85013
|
import {
|
|
84709
85014
|
getWorkspaceInteractionRevisionState,
|
|
84710
|
-
|
|
85015
|
+
listSessionEventPage as listSessionEventPage2,
|
|
84711
85016
|
listWorkspaceControlEvents
|
|
84712
85017
|
} from "@opengeni/db";
|
|
84713
85018
|
import {
|
|
@@ -84719,6 +85024,7 @@ import {
|
|
|
84719
85024
|
} from "@opengeni/events";
|
|
84720
85025
|
import { MANAGED_AUTH_ACTOR_EPOCH_HEADER } from "@opengeni/core/managed-auth-session-sets";
|
|
84721
85026
|
var SESSION_REPLAY_PAGE_SIZE = 100;
|
|
85027
|
+
var SESSION_REPLAY_PAGE_MAX_BYTES = 8 * 1024 * 1024;
|
|
84722
85028
|
var WORKSPACE_CONTROL_REPLAY_PAGE_SIZE = 100;
|
|
84723
85029
|
var SSE_QUEUED_FRAME_MAX_COUNT = 1;
|
|
84724
85030
|
var SSE_WRITE_STALL_TIMEOUT_MS = 3e4;
|
|
@@ -84894,9 +85200,10 @@ function createLatestWinsDelivery(send, onError) {
|
|
|
84894
85200
|
}
|
|
84895
85201
|
async function sseSessionStream(db, bus, workspaceId, sessionId, after, signal, options = {}) {
|
|
84896
85202
|
if (isHttp1BrowserBatch(options)) {
|
|
84897
|
-
const events = await
|
|
85203
|
+
const { events } = await listSessionEventPage2(db, workspaceId, sessionId, {
|
|
84898
85204
|
after,
|
|
84899
|
-
limit: SESSION_REPLAY_PAGE_SIZE
|
|
85205
|
+
limit: SESSION_REPLAY_PAGE_SIZE,
|
|
85206
|
+
maxBytes: options.finiteResponseMaxBytes ?? HTTP1_BROWSER_SSE_BATCH_MAX_BYTES
|
|
84900
85207
|
});
|
|
84901
85208
|
await options.reauthorize?.();
|
|
84902
85209
|
const compactProjection = coalesceSessionEventDeltasWithCoverage(events);
|
|
@@ -84969,10 +85276,12 @@ async function sseSessionStream(db, bus, workspaceId, sessionId, after, signal,
|
|
|
84969
85276
|
if (targetSequence !== void 0 && lastSent >= targetSequence) return;
|
|
84970
85277
|
const previousLastSent = lastSent;
|
|
84971
85278
|
const limit = targetSequence === void 0 ? SESSION_REPLAY_PAGE_SIZE : Math.min(SESSION_REPLAY_PAGE_SIZE, targetSequence - lastSent);
|
|
84972
|
-
const
|
|
85279
|
+
const replayPage = await listSessionEventPage2(db, workspaceId, sessionId, {
|
|
84973
85280
|
after: lastSent,
|
|
84974
|
-
limit
|
|
85281
|
+
limit,
|
|
85282
|
+
maxBytes: SESSION_REPLAY_PAGE_MAX_BYTES
|
|
84975
85283
|
});
|
|
85284
|
+
const page2 = replayPage.events;
|
|
84976
85285
|
const eligible = targetSequence === void 0 ? page2 : page2.filter((event) => event.sequence <= targetSequence);
|
|
84977
85286
|
if (eligible.length === 0) {
|
|
84978
85287
|
if (targetSequence === void 0) return;
|
|
@@ -84990,6 +85299,7 @@ async function sseSessionStream(db, bus, workspaceId, sessionId, after, signal,
|
|
|
84990
85299
|
throw new Error(`Session event replay made no progress after sequence ${lastSent}`);
|
|
84991
85300
|
}
|
|
84992
85301
|
if (targetSequence !== void 0 && lastSent >= targetSequence) return;
|
|
85302
|
+
if (targetSequence === void 0 && !replayPage.hasMore) return;
|
|
84993
85303
|
}
|
|
84994
85304
|
};
|
|
84995
85305
|
let durableDeliveryTail = Promise.resolve();
|
|
@@ -86212,6 +86522,7 @@ import {
|
|
|
86212
86522
|
defaultPrReviewProviderBaseUrl,
|
|
86213
86523
|
workspaceCustomModelReference as workspaceCustomModelReference2,
|
|
86214
86524
|
lockActiveCustomModelForAdmission as lockActiveCustomModelForAdmission2,
|
|
86525
|
+
modelUnavailableHttpException as modelUnavailableHttpException2,
|
|
86215
86526
|
prReviewWebhookAuthKind,
|
|
86216
86527
|
normalizePrReviewProviderBaseUrl,
|
|
86217
86528
|
requireAccessGrant as requireAccessGrant26,
|
|
@@ -86470,7 +86781,7 @@ import { HTTPException as HTTPException68 } from "hono/http-exception";
|
|
|
86470
86781
|
|
|
86471
86782
|
// src/routes/automations.ts
|
|
86472
86783
|
import { environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes7 } from "@opengeni/config";
|
|
86473
|
-
import { requireAgentConfigAdmission as requireAgentConfigAdmission2 } from "@opengeni/core";
|
|
86784
|
+
import { modelUnavailableHttpException, requireAgentConfigAdmission as requireAgentConfigAdmission2 } from "@opengeni/core";
|
|
86474
86785
|
import {
|
|
86475
86786
|
AUTOMATION_WEBHOOK_MAX_BYTES,
|
|
86476
86787
|
AUTOMATION_MAX_MATCHED_TRIGGERS,
|
|
@@ -87076,9 +87387,7 @@ function workspaceCustomModelCommitGuard(input) {
|
|
|
87076
87387
|
reference
|
|
87077
87388
|
});
|
|
87078
87389
|
if (!active) {
|
|
87079
|
-
throw
|
|
87080
|
-
message: `model is not available: ${input.modelId}`
|
|
87081
|
-
});
|
|
87390
|
+
throw modelUnavailableHttpException(input.modelId);
|
|
87082
87391
|
}
|
|
87083
87392
|
};
|
|
87084
87393
|
}
|
|
@@ -87174,12 +87483,12 @@ function registerPrReviewGitHubRoutes(app, deps) {
|
|
|
87174
87483
|
if (installationId === null || repositoryId === null) {
|
|
87175
87484
|
return c.json(ignoredWebhook("unsupported_event"), 202);
|
|
87176
87485
|
}
|
|
87177
|
-
const
|
|
87486
|
+
const route2 = await resolveManagedGitHubPrReviewRoute(deps.db, {
|
|
87178
87487
|
installationId: String(installationId),
|
|
87179
87488
|
providerRepositoryId: String(repositoryId)
|
|
87180
87489
|
});
|
|
87181
|
-
if (!
|
|
87182
|
-
const source = await getAutomationSourceSecret2(deps.db,
|
|
87490
|
+
if (!route2) return c.json(ignoredWebhook("repository_not_connected"), 202);
|
|
87491
|
+
const source = await getAutomationSourceSecret2(deps.db, route2);
|
|
87183
87492
|
if (!source || source.status !== "active") {
|
|
87184
87493
|
return c.json(ignoredWebhook("source_disabled"), 202);
|
|
87185
87494
|
}
|
|
@@ -88212,9 +88521,7 @@ function prReviewCustomModelCommitGuard(input) {
|
|
|
88212
88521
|
reference
|
|
88213
88522
|
});
|
|
88214
88523
|
if (!active) {
|
|
88215
|
-
throw
|
|
88216
|
-
message: `model is not available: ${input.modelId}`
|
|
88217
|
-
});
|
|
88524
|
+
throw modelUnavailableHttpException2(input.modelId);
|
|
88218
88525
|
}
|
|
88219
88526
|
};
|
|
88220
88527
|
}
|
|
@@ -89653,8 +89960,8 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
89653
89960
|
const workspaceId = c.req.param("workspaceId");
|
|
89654
89961
|
const grant = await requireAccessGrant29(c, deps, workspaceId, "workspace:read");
|
|
89655
89962
|
const skillId = skillIdentifier(c.req.param("skillId"));
|
|
89656
|
-
const
|
|
89657
|
-
const revisionId2 =
|
|
89963
|
+
const revision2 = c.req.query("revisionId");
|
|
89964
|
+
const revisionId2 = revision2 === void 0 ? void 0 : skillIdentifier(revision2);
|
|
89658
89965
|
const skill = await readSkill(
|
|
89659
89966
|
deps.db,
|
|
89660
89967
|
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
@@ -90906,6 +91213,7 @@ function registerScheduledTaskRoutes(app, deps) {
|
|
|
90906
91213
|
|
|
90907
91214
|
// src/routes/sessions.ts
|
|
90908
91215
|
import { getRetainedProviderCommand } from "@opengeni/db/retained-provider-commands";
|
|
91216
|
+
import { UnsupportedLatencyModeError } from "@opengeni/config";
|
|
90909
91217
|
import { searchSessionMessagesForSubject, SessionMessageSearchCursorError } from "@opengeni/db";
|
|
90910
91218
|
import { listSessionEventSlices } from "@opengeni/db/session-event-slices";
|
|
90911
91219
|
import * as sessionPreviewSchema from "@opengeni/db/schema";
|
|
@@ -91027,7 +91335,7 @@ import {
|
|
|
91027
91335
|
getSessionQueueSnapshot as getSessionQueueSnapshot2,
|
|
91028
91336
|
getStreamAcknowledgment,
|
|
91029
91337
|
insertPtySession,
|
|
91030
|
-
listSessionEventPage as
|
|
91338
|
+
listSessionEventPage as listSessionEventPage3,
|
|
91031
91339
|
listSessionHumanInputRequests,
|
|
91032
91340
|
listSessionGoalRevisionPage,
|
|
91033
91341
|
listSessionGoalRevisions,
|
|
@@ -91036,6 +91344,7 @@ import {
|
|
|
91036
91344
|
listSessionDiscoverySummaries as listSessionDiscoverySummaries2,
|
|
91037
91345
|
listSessionDiscoveryAncestorPaths,
|
|
91038
91346
|
listSessionsForSubject,
|
|
91347
|
+
listSessionEntriesForSubject,
|
|
91039
91348
|
getLatestStartedSessionTurn,
|
|
91040
91349
|
listSessionTurns,
|
|
91041
91350
|
projectEffectiveControlForRelatedAccess as projectEffectiveControlForRelatedAccess2,
|
|
@@ -91905,8 +92214,7 @@ import {
|
|
|
91905
92214
|
workflowIdForSession as workflowIdForSession3,
|
|
91906
92215
|
sessionWithEffectiveToolPolicy as sessionWithEffectiveToolPolicy2,
|
|
91907
92216
|
workspaceSessionEffectiveToolsContext as workspaceSessionEffectiveToolsContext2,
|
|
91908
|
-
|
|
91909
|
-
workspaceSessionToolPolicyServerIds as workspaceSessionToolPolicyServerIds2,
|
|
92217
|
+
workspaceSessionToolPolicyContext,
|
|
91910
92218
|
relayConfigFromSettings as relayConfigFromSettings5,
|
|
91911
92219
|
validateVariableSetAttachment
|
|
91912
92220
|
} from "@opengeni/core";
|
|
@@ -92517,33 +92825,44 @@ function registerSessionRoutes(app, deps) {
|
|
|
92517
92825
|
}
|
|
92518
92826
|
const pageView = c.req.query("view") === "page";
|
|
92519
92827
|
const query = sessionListQuery(c.req.query(), pageView);
|
|
92828
|
+
const projection = c.req.query("projection");
|
|
92829
|
+
if (projection !== void 0 && projection !== "summary")
|
|
92830
|
+
throw new HTTPException80(400, { message: 'projection must be "summary"' });
|
|
92831
|
+
if (projection && !pageView)
|
|
92832
|
+
throw new HTTPException80(400, { message: 'summary projection requires view="page"' });
|
|
92833
|
+
const summary = projection === "summary";
|
|
92520
92834
|
let page2;
|
|
92521
92835
|
try {
|
|
92522
|
-
page2 = await
|
|
92523
|
-
|
|
92524
|
-
|
|
92525
|
-
|
|
92526
|
-
|
|
92527
|
-
|
|
92528
|
-
|
|
92529
|
-
|
|
92530
|
-
|
|
92531
|
-
|
|
92532
|
-
|
|
92533
|
-
|
|
92534
|
-
|
|
92535
|
-
|
|
92536
|
-
|
|
92537
|
-
|
|
92538
|
-
|
|
92539
|
-
|
|
92540
|
-
|
|
92541
|
-
|
|
92542
|
-
|
|
92543
|
-
|
|
92544
|
-
|
|
92545
|
-
|
|
92546
|
-
|
|
92836
|
+
page2 = await (summary ? listSessionEntriesForSubject : listSessionsForSubject)(
|
|
92837
|
+
db,
|
|
92838
|
+
workspaceId,
|
|
92839
|
+
{
|
|
92840
|
+
subjectId: grant.subjectId,
|
|
92841
|
+
limit: boundedLimit(query.limit),
|
|
92842
|
+
materializeSnapshot: pageView,
|
|
92843
|
+
...query.cursor ? { cursor: query.cursor } : {},
|
|
92844
|
+
...query.search ? { search: query.search } : {},
|
|
92845
|
+
...query.pinsOnly ? { pinsOnly: true } : {},
|
|
92846
|
+
...query.includePinned === false ? { includePinned: false } : {},
|
|
92847
|
+
...query.archivedOnly ? { archivedOnly: true } : {},
|
|
92848
|
+
...query.sortBy ? { sortBy: query.sortBy } : {},
|
|
92849
|
+
...query.archiveStatus ? { archiveStatus: query.archiveStatus } : {},
|
|
92850
|
+
...query.parentSessionId !== void 0 ? { parentSessionId: query.parentSessionId } : {},
|
|
92851
|
+
...query.channelId !== void 0 ? { channelId: query.channelId } : {},
|
|
92852
|
+
...query.originSiteId ? { originSiteId: query.originSiteId } : {},
|
|
92853
|
+
...query.createdBy ? { createdBy: query.createdBy } : {},
|
|
92854
|
+
...query.updatedFrom ? { updatedFrom: query.updatedFrom } : {},
|
|
92855
|
+
...query.updatedBefore ? { updatedBefore: query.updatedBefore } : {},
|
|
92856
|
+
...query.createdFrom ? { createdFrom: query.createdFrom } : {},
|
|
92857
|
+
...query.createdBefore ? { createdBefore: query.createdBefore } : {},
|
|
92858
|
+
...query.scopeSubjectId ? { scopeSubjectId: query.scopeSubjectId } : {},
|
|
92859
|
+
...authorizationScope ? { authorizationScope } : {},
|
|
92860
|
+
// A managed human's own personal workspace has no membership row, so
|
|
92861
|
+
// the list's removal fence must fall back to the organization-membership
|
|
92862
|
+
// pointer, only with verified native or external owning-user provenance.
|
|
92863
|
+
personalWorkspaceOwnerException: hasVerifiedOwningUserAuthorization(authorization)
|
|
92864
|
+
}
|
|
92865
|
+
);
|
|
92547
92866
|
} catch (error) {
|
|
92548
92867
|
if (error instanceof SessionListAccessError) {
|
|
92549
92868
|
throw new HTTPException80(403, { message: error.message });
|
|
@@ -92557,10 +92876,6 @@ function registerSessionRoutes(app, deps) {
|
|
|
92557
92876
|
throw error;
|
|
92558
92877
|
}
|
|
92559
92878
|
c.header("x-opengeni-pinned-truncated", page2.pinnedTruncated === true ? "true" : "false");
|
|
92560
|
-
const policy = await loadEffectivePolicyContext(deps, workspaceId, grant.subjectId, [
|
|
92561
|
-
...page2.pinned,
|
|
92562
|
-
...page2.sessions
|
|
92563
|
-
]);
|
|
92564
92879
|
const commandActivity = await backgroundCommandActivityForSessions(db, {
|
|
92565
92880
|
accountId: grant.accountId,
|
|
92566
92881
|
workspaceId,
|
|
@@ -92571,14 +92886,33 @@ function registerSessionRoutes(app, deps) {
|
|
|
92571
92886
|
workspaceId,
|
|
92572
92887
|
[...page2.pinned, ...page2.sessions].map((session) => session.id)
|
|
92573
92888
|
) : /* @__PURE__ */ new Set();
|
|
92889
|
+
if ("projection" in page2) {
|
|
92890
|
+
const decorateEntry = (session) => ({
|
|
92891
|
+
...session,
|
|
92892
|
+
hasSchedules: scheduleTargets.has(session.id),
|
|
92893
|
+
...commandActivity.has(session.id) ? { backgroundCommandActivity: commandActivity.get(session.id) } : {}
|
|
92894
|
+
});
|
|
92895
|
+
return c.json({
|
|
92896
|
+
...page2,
|
|
92897
|
+
...query.hasPageFilters ? { filtersApplied: true } : {},
|
|
92898
|
+
...query.originSiteId ? { originSiteId: query.originSiteId } : {},
|
|
92899
|
+
pinned: page2.pinned.map(decorateEntry),
|
|
92900
|
+
sessions: page2.sessions.map(decorateEntry)
|
|
92901
|
+
});
|
|
92902
|
+
}
|
|
92903
|
+
const policy = await loadEffectivePolicyContext(deps, workspaceId, grant.subjectId, [
|
|
92904
|
+
...page2.pinned,
|
|
92905
|
+
...page2.sessions
|
|
92906
|
+
]);
|
|
92574
92907
|
const decorate = (session) => {
|
|
92575
92908
|
const activity = commandActivity.get(session.id);
|
|
92909
|
+
const decorated = {
|
|
92910
|
+
...session,
|
|
92911
|
+
hasSchedules: scheduleTargets.has(session.id),
|
|
92912
|
+
...activity ? { backgroundCommandActivity: activity } : {}
|
|
92913
|
+
};
|
|
92576
92914
|
return sessionWithEffectiveToolPolicy2(
|
|
92577
|
-
|
|
92578
|
-
...session,
|
|
92579
|
-
hasSchedules: scheduleTargets.has(session.id),
|
|
92580
|
-
...activity ? { backgroundCommandActivity: activity } : {}
|
|
92581
|
-
},
|
|
92915
|
+
decorated,
|
|
92582
92916
|
policy.workspaceServerIds,
|
|
92583
92917
|
policy.workspaceDefaultServerIds,
|
|
92584
92918
|
policy.effectiveToolsContext
|
|
@@ -94081,20 +94415,20 @@ function registerSessionRoutes(app, deps) {
|
|
|
94081
94415
|
const sessionId = c.req.param("sessionId");
|
|
94082
94416
|
await assertSessionExists(db, workspaceId, sessionId);
|
|
94083
94417
|
const payload = await parseRequestJson(c, ApplySessionGoalRevisionRequest);
|
|
94084
|
-
const
|
|
94418
|
+
const revision2 = await getSessionGoalRevision(
|
|
94085
94419
|
db,
|
|
94086
94420
|
workspaceId,
|
|
94087
94421
|
sessionId,
|
|
94088
94422
|
c.req.param("revisionId")
|
|
94089
94423
|
);
|
|
94090
|
-
if (!
|
|
94424
|
+
if (!revision2 || revision2.disposition !== "proposed") {
|
|
94091
94425
|
throw new HTTPException80(404, {
|
|
94092
94426
|
message: "goal rewrite proposal not found"
|
|
94093
94427
|
});
|
|
94094
94428
|
}
|
|
94095
|
-
if (!goalProposalMatchesExpectedRevision(
|
|
94429
|
+
if (!goalProposalMatchesExpectedRevision(revision2, payload.expectedObjectiveRevision)) {
|
|
94096
94430
|
throw new HTTPException80(409, {
|
|
94097
|
-
message: `goal proposal was based on objective revision ${
|
|
94431
|
+
message: `goal proposal was based on objective revision ${revision2.baseObjectiveRevision}; requested fence ${payload.expectedObjectiveRevision} cannot apply it`
|
|
94098
94432
|
});
|
|
94099
94433
|
}
|
|
94100
94434
|
try {
|
|
@@ -94102,15 +94436,15 @@ function registerSessionRoutes(app, deps) {
|
|
|
94102
94436
|
accountId: grant.accountId,
|
|
94103
94437
|
workspaceId,
|
|
94104
94438
|
sessionId,
|
|
94105
|
-
text:
|
|
94106
|
-
successCriteria:
|
|
94107
|
-
rootConstraints:
|
|
94108
|
-
mutationPolicy:
|
|
94439
|
+
text: revision2.text,
|
|
94440
|
+
successCriteria: revision2.successCriteria,
|
|
94441
|
+
rootConstraints: revision2.rootConstraints,
|
|
94442
|
+
mutationPolicy: revision2.mutationPolicy,
|
|
94109
94443
|
expectedObjectiveRevision: payload.expectedObjectiveRevision,
|
|
94110
|
-
expectedGoalId:
|
|
94111
|
-
changeKind:
|
|
94112
|
-
changeRationale: payload.rationale ?? `Applied goal proposal ${
|
|
94113
|
-
sourceProposalId:
|
|
94444
|
+
expectedGoalId: revision2.goalId,
|
|
94445
|
+
changeKind: revision2.changeKind,
|
|
94446
|
+
changeRationale: payload.rationale ?? `Applied goal proposal ${revision2.id}`,
|
|
94447
|
+
sourceProposalId: revision2.id,
|
|
94114
94448
|
createdBy: "api",
|
|
94115
94449
|
actor: "api"
|
|
94116
94450
|
});
|
|
@@ -94171,13 +94505,13 @@ function registerSessionRoutes(app, deps) {
|
|
|
94171
94505
|
const sessionId = c.req.param("sessionId");
|
|
94172
94506
|
await assertSessionExists(db, workspaceId, sessionId);
|
|
94173
94507
|
const payload = await parseRequestJson(c, RollbackSessionGoalRevisionRequest);
|
|
94174
|
-
const
|
|
94508
|
+
const revision2 = await getSessionGoalRevision(
|
|
94175
94509
|
db,
|
|
94176
94510
|
workspaceId,
|
|
94177
94511
|
sessionId,
|
|
94178
94512
|
c.req.param("revisionId")
|
|
94179
94513
|
);
|
|
94180
|
-
if (!
|
|
94514
|
+
if (!revision2 || revision2.disposition !== "applied") {
|
|
94181
94515
|
throw new HTTPException80(404, { message: "applied goal revision not found" });
|
|
94182
94516
|
}
|
|
94183
94517
|
try {
|
|
@@ -94185,15 +94519,15 @@ function registerSessionRoutes(app, deps) {
|
|
|
94185
94519
|
accountId: grant.accountId,
|
|
94186
94520
|
workspaceId,
|
|
94187
94521
|
sessionId,
|
|
94188
|
-
text:
|
|
94189
|
-
successCriteria:
|
|
94190
|
-
rootConstraints:
|
|
94191
|
-
mutationPolicy:
|
|
94522
|
+
text: revision2.text,
|
|
94523
|
+
successCriteria: revision2.successCriteria,
|
|
94524
|
+
rootConstraints: revision2.rootConstraints,
|
|
94525
|
+
mutationPolicy: revision2.mutationPolicy,
|
|
94192
94526
|
expectedObjectiveRevision: payload.expectedObjectiveRevision,
|
|
94193
|
-
expectedGoalId:
|
|
94527
|
+
expectedGoalId: revision2.goalId,
|
|
94194
94528
|
changeKind: "replacement",
|
|
94195
94529
|
changeRationale: payload.rationale,
|
|
94196
|
-
rollbackOfRevisionId:
|
|
94530
|
+
rollbackOfRevisionId: revision2.id,
|
|
94197
94531
|
createdBy: "api",
|
|
94198
94532
|
actor: "api"
|
|
94199
94533
|
});
|
|
@@ -94476,7 +94810,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
94476
94810
|
mode === "monitoring" ? 40 : 500
|
|
94477
94811
|
);
|
|
94478
94812
|
const dbPayloadMode = resultMode === "compact" ? "full" : payloadMode;
|
|
94479
|
-
const dbPage = await
|
|
94813
|
+
const dbPage = await listSessionEventPage3(db, workspaceId, sessionId, {
|
|
94480
94814
|
after,
|
|
94481
94815
|
...before !== void 0 ? { before } : {},
|
|
94482
94816
|
limit,
|
|
@@ -95828,13 +96162,13 @@ function registerSessionRoutes(app, deps) {
|
|
|
95828
96162
|
const revisionParam = c.req.query("revision");
|
|
95829
96163
|
let row;
|
|
95830
96164
|
if (revisionParam !== void 0 && revisionParam !== "") {
|
|
95831
|
-
const
|
|
95832
|
-
if (!Number.isInteger(
|
|
96165
|
+
const revision2 = Number(revisionParam);
|
|
96166
|
+
if (!Number.isInteger(revision2) || revision2 < 0) {
|
|
95833
96167
|
throw new HTTPException80(400, {
|
|
95834
96168
|
message: "revision must be a non-negative integer"
|
|
95835
96169
|
});
|
|
95836
96170
|
}
|
|
95837
|
-
row = await workspaceCaptureAtRevision(db, workspaceId, sessionId,
|
|
96171
|
+
row = await workspaceCaptureAtRevision(db, workspaceId, sessionId, revision2);
|
|
95838
96172
|
} else {
|
|
95839
96173
|
row = await latestWorkspaceCapture(db, workspaceId, sessionId);
|
|
95840
96174
|
}
|
|
@@ -96077,8 +96411,8 @@ function registerSessionRoutes(app, deps) {
|
|
|
96077
96411
|
return c.body(null, 204);
|
|
96078
96412
|
});
|
|
96079
96413
|
}
|
|
96080
|
-
function goalProposalMatchesExpectedRevision(
|
|
96081
|
-
return
|
|
96414
|
+
function goalProposalMatchesExpectedRevision(revision2, expectedObjectiveRevision) {
|
|
96415
|
+
return revision2.baseObjectiveRevision === expectedObjectiveRevision;
|
|
96082
96416
|
}
|
|
96083
96417
|
function eventListLimit(raw, max = 2e3, fallback = 500) {
|
|
96084
96418
|
const limit = Number(raw ?? fallback);
|
|
@@ -96367,6 +96701,13 @@ function sessionListQuery(query, allowCursor = true) {
|
|
|
96367
96701
|
});
|
|
96368
96702
|
}
|
|
96369
96703
|
const pinsOnly = query.pinsOnly === "true";
|
|
96704
|
+
if (query.includePinned !== void 0 && !["true", "false"].includes(query.includePinned)) {
|
|
96705
|
+
throw new HTTPException80(400, { message: 'includePinned must be "true" or "false"' });
|
|
96706
|
+
}
|
|
96707
|
+
const includePinned = query.includePinned !== "false";
|
|
96708
|
+
if (pinsOnly && !includePinned) {
|
|
96709
|
+
throw new HTTPException80(400, { message: "pinsOnly requires includePinned" });
|
|
96710
|
+
}
|
|
96370
96711
|
if (query.archivedOnly !== void 0 && query.archivedOnly !== "true") {
|
|
96371
96712
|
throw new HTTPException80(400, { message: 'archivedOnly must be the literal "true"' });
|
|
96372
96713
|
}
|
|
@@ -96461,6 +96802,7 @@ function sessionListQuery(query, allowCursor = true) {
|
|
|
96461
96802
|
cursor,
|
|
96462
96803
|
search: search || void 0,
|
|
96463
96804
|
pinsOnly,
|
|
96805
|
+
includePinned,
|
|
96464
96806
|
archivedOnly,
|
|
96465
96807
|
sortBy: sortBy.data,
|
|
96466
96808
|
archiveStatus: archiveStatus.data,
|
|
@@ -96724,6 +97066,21 @@ function optionalEventSequence(raw) {
|
|
|
96724
97066
|
return Math.floor(sequence);
|
|
96725
97067
|
}
|
|
96726
97068
|
function sessionCreateErrorResponse(c, error) {
|
|
97069
|
+
if (error instanceof UnsupportedLatencyModeError) {
|
|
97070
|
+
return c.json(
|
|
97071
|
+
{
|
|
97072
|
+
code: "SESSION_CREATE_REJECTED",
|
|
97073
|
+
message: error.message,
|
|
97074
|
+
details: {
|
|
97075
|
+
code: error.code,
|
|
97076
|
+
modelId: error.modelId,
|
|
97077
|
+
latencyMode: error.latencyMode,
|
|
97078
|
+
allowedLatencyModes: [...error.allowedLatencyModes]
|
|
97079
|
+
}
|
|
97080
|
+
},
|
|
97081
|
+
422
|
|
97082
|
+
);
|
|
97083
|
+
}
|
|
96727
97084
|
if (error instanceof SessionCreateConnectionSelectionUnavailableError2) {
|
|
96728
97085
|
return c.json({ code: error.code, message: error.message, retryable: false }, 409);
|
|
96729
97086
|
}
|
|
@@ -96856,12 +97213,11 @@ function commandConflictResponse(c, error) {
|
|
|
96856
97213
|
throw error;
|
|
96857
97214
|
}
|
|
96858
97215
|
async function loadEffectivePolicyContext(deps, workspaceId, subjectId, sessions) {
|
|
96859
|
-
const [
|
|
96860
|
-
|
|
96861
|
-
workspaceSessionToolPolicyDefaultServerIds2(deps.db, workspaceId, deps.settings, subjectId),
|
|
97216
|
+
const [policy, effectiveToolsContext] = await Promise.all([
|
|
97217
|
+
workspaceSessionToolPolicyContext(deps.db, workspaceId, deps.settings, subjectId),
|
|
96862
97218
|
workspaceSessionEffectiveToolsContext2(deps, workspaceId, subjectId, sessions)
|
|
96863
97219
|
]);
|
|
96864
|
-
return {
|
|
97220
|
+
return { ...policy, effectiveToolsContext };
|
|
96865
97221
|
}
|
|
96866
97222
|
async function withEffectivePolicy(deps, workspaceId, subjectId, session) {
|
|
96867
97223
|
const policy = await loadEffectivePolicyContext(deps, workspaceId, subjectId, [session]);
|
|
@@ -97330,9 +97686,12 @@ function socialHttpException(error) {
|
|
|
97330
97686
|
}
|
|
97331
97687
|
|
|
97332
97688
|
// src/routes/workspaces.ts
|
|
97689
|
+
import { withDirectModelProviders } from "@opengeni/config";
|
|
97690
|
+
import { listConnectionsMetadata as listConnectionsMetadata7 } from "@opengeni/db";
|
|
97333
97691
|
import {
|
|
97334
|
-
|
|
97335
|
-
|
|
97692
|
+
workspaceProviderApiKeyConnectionMetadataFromConnections,
|
|
97693
|
+
listWorkspaceProviderCustomModelsByKind,
|
|
97694
|
+
getOrganizationModelProviderCatalogForWorkspace
|
|
97336
97695
|
} from "@opengeni/db";
|
|
97337
97696
|
import { CLAUDE_CONNECTION_KINDS } from "@opengeni/config";
|
|
97338
97697
|
import { SessionControlConflictError as SessionControlConflictError2, WorkspacePauseTimerInputError } from "@opengeni/db";
|
|
@@ -97407,9 +97766,6 @@ import {
|
|
|
97407
97766
|
workspaceControlRequestLockTimeoutMs as workspaceControlRequestLockTimeoutMs2,
|
|
97408
97767
|
workspaceXaiSubscriptionActive,
|
|
97409
97768
|
workspaceVercelAiGatewayConnectionActive,
|
|
97410
|
-
workspaceOpenRouterConnectionActive,
|
|
97411
|
-
organizationModelProviderConnectionActiveForWorkspace,
|
|
97412
|
-
listOrganizationModelProviderCustomModelsForWorkspace,
|
|
97413
97769
|
WorkspaceGatewayCustomModelHistoryLimitError,
|
|
97414
97770
|
WorkspaceOpenRouterCustomModelHistoryLimitError,
|
|
97415
97771
|
WorkspaceExternalIdentityConflictError,
|
|
@@ -97542,6 +97898,11 @@ async function deleteWorkspaceForRequest(deps, input) {
|
|
|
97542
97898
|
if (state === "P0002") {
|
|
97543
97899
|
throw new HTTPException83(404, { message: "workspace not found" });
|
|
97544
97900
|
}
|
|
97901
|
+
if (state === "23503") {
|
|
97902
|
+
throw new HTTPException83(409, {
|
|
97903
|
+
message: "workspace deletion is blocked by retained or linked records; keep the workspace, revoke access, and disable scheduled work instead"
|
|
97904
|
+
});
|
|
97905
|
+
}
|
|
97545
97906
|
throw error;
|
|
97546
97907
|
}
|
|
97547
97908
|
if (deleted.status === "not_found") {
|
|
@@ -97882,6 +98243,13 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
97882
98243
|
const workspaceId = c.req.param("workspaceId");
|
|
97883
98244
|
const grant = await requireAccessGrant36(c, deps, workspaceId, "workspace:read");
|
|
97884
98245
|
const catalogSettings = deps.resolveCatalogSettings();
|
|
98246
|
+
const providerKinds = [
|
|
98247
|
+
"vercel_gateway",
|
|
98248
|
+
"openrouter",
|
|
98249
|
+
...CLAUDE_CONNECTION_KINDS.filter(
|
|
98250
|
+
(kind) => kind !== "claude_subscription" || deps.settings.claudeSubscriptionEnabled
|
|
98251
|
+
)
|
|
98252
|
+
];
|
|
97885
98253
|
const [
|
|
97886
98254
|
connectionModelRestrictions,
|
|
97887
98255
|
resolvedCatalog,
|
|
@@ -97889,14 +98257,9 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
97889
98257
|
codexSubscriptionActive,
|
|
97890
98258
|
codexModelAvailability,
|
|
97891
98259
|
xaiSubscriptionActive,
|
|
97892
|
-
|
|
97893
|
-
|
|
97894
|
-
|
|
97895
|
-
workspaceOpenRouterCustomModels,
|
|
97896
|
-
organizationGatewayConnectionActive,
|
|
97897
|
-
organizationOpenRouterConnectionActive,
|
|
97898
|
-
organizationGatewayCustomModels,
|
|
97899
|
-
organizationOpenRouterCustomModels,
|
|
98260
|
+
workspaceConnections,
|
|
98261
|
+
workspaceCustomModels,
|
|
98262
|
+
organizationProviders,
|
|
97900
98263
|
workspace
|
|
97901
98264
|
] = await Promise.all([
|
|
97902
98265
|
getWorkspaceConnectionModelRestrictions(deps.db, workspaceId, grant.subjectId),
|
|
@@ -97907,88 +98270,55 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
97907
98270
|
({ settings }) => loadWorkspaceCodexModelAvailability(deps.db, settings, workspaceId)
|
|
97908
98271
|
),
|
|
97909
98272
|
workspaceXaiSubscriptionActive(deps.db, deps.settings, workspaceId, grant.subjectId),
|
|
97910
|
-
|
|
97911
|
-
|
|
97912
|
-
accountId: grant.accountId,
|
|
97913
|
-
workspaceId
|
|
97914
|
-
}),
|
|
97915
|
-
workspaceOpenRouterConnectionActive(deps.db, workspaceId),
|
|
97916
|
-
listWorkspaceOpenRouterCustomModels(deps.db, {
|
|
97917
|
-
accountId: grant.accountId,
|
|
97918
|
-
workspaceId
|
|
97919
|
-
}),
|
|
97920
|
-
organizationModelProviderConnectionActiveForWorkspace(deps.db, {
|
|
98273
|
+
listConnectionsMetadata7(deps.db, workspaceId, null),
|
|
98274
|
+
listWorkspaceProviderCustomModelsByKind(deps.db, {
|
|
97921
98275
|
accountId: grant.accountId,
|
|
97922
98276
|
workspaceId,
|
|
97923
|
-
|
|
98277
|
+
providerKinds
|
|
97924
98278
|
}),
|
|
97925
|
-
|
|
98279
|
+
getOrganizationModelProviderCatalogForWorkspace(deps.db, {
|
|
97926
98280
|
accountId: grant.accountId,
|
|
97927
98281
|
workspaceId,
|
|
97928
|
-
|
|
97929
|
-
}),
|
|
97930
|
-
listOrganizationModelProviderCustomModelsForWorkspace(deps.db, {
|
|
97931
|
-
accountId: grant.accountId,
|
|
97932
|
-
workspaceId,
|
|
97933
|
-
providerKind: "vercel_gateway"
|
|
97934
|
-
}),
|
|
97935
|
-
listOrganizationModelProviderCustomModelsForWorkspace(deps.db, {
|
|
97936
|
-
accountId: grant.accountId,
|
|
97937
|
-
workspaceId,
|
|
97938
|
-
providerKind: "openrouter"
|
|
98282
|
+
providerKinds
|
|
97939
98283
|
}),
|
|
97940
98284
|
getWorkspace4(deps.db, workspaceId)
|
|
97941
98285
|
]);
|
|
97942
98286
|
const claudeConnections = {};
|
|
97943
98287
|
const workspaceClaudeConnections = {};
|
|
97944
|
-
|
|
97945
|
-
|
|
97946
|
-
|
|
97947
|
-
|
|
97948
|
-
|
|
97949
|
-
|
|
97950
|
-
|
|
97951
|
-
|
|
97952
|
-
|
|
97953
|
-
|
|
97954
|
-
|
|
97955
|
-
|
|
97956
|
-
providerKind: kind
|
|
97957
|
-
})
|
|
97958
|
-
]);
|
|
97959
|
-
claudeConnections[kind] = { active, models };
|
|
97960
|
-
const [metadata, workspaceModels] = await Promise.all([
|
|
97961
|
-
getWorkspaceProviderApiKeyConnectionMetadata3(deps.db, workspaceId, kind),
|
|
97962
|
-
listWorkspaceProviderCustomModels2(deps.db, {
|
|
97963
|
-
accountId: grant.accountId,
|
|
97964
|
-
workspaceId,
|
|
97965
|
-
providerKind: kind
|
|
97966
|
-
})
|
|
97967
|
-
]);
|
|
97968
|
-
workspaceClaudeConnections[kind] = { active: metadata !== null, models: workspaceModels };
|
|
97969
|
-
})
|
|
98288
|
+
const workspaceConnectionActive = (kind) => workspaceProviderApiKeyConnectionMetadataFromConnections(workspaceConnections, kind) !== null;
|
|
98289
|
+
for (const kind of CLAUDE_CONNECTION_KINDS) {
|
|
98290
|
+
if (kind === "claude_subscription" && !deps.settings.claudeSubscriptionEnabled) continue;
|
|
98291
|
+
claudeConnections[kind] = organizationProviders[kind];
|
|
98292
|
+
workspaceClaudeConnections[kind] = {
|
|
98293
|
+
active: workspaceConnectionActive(kind),
|
|
98294
|
+
models: workspaceCustomModels[kind]
|
|
98295
|
+
};
|
|
98296
|
+
}
|
|
98297
|
+
const workspaceCatalogSettings = withDirectModelProviders(
|
|
98298
|
+
resolvedCatalog.settings,
|
|
98299
|
+
workspaceConnections
|
|
97970
98300
|
);
|
|
97971
98301
|
const selections = resolveWorkspaceModelSelection2({
|
|
97972
98302
|
claudeConnections,
|
|
97973
98303
|
workspaceClaudeConnections,
|
|
97974
98304
|
connectionModelRestrictions,
|
|
97975
|
-
settings:
|
|
98305
|
+
settings: workspaceCatalogSettings,
|
|
97976
98306
|
policy,
|
|
97977
98307
|
observations: codexModelAvailability,
|
|
97978
98308
|
codexSubscriptionActive,
|
|
97979
98309
|
xaiSubscriptionActive,
|
|
97980
|
-
workspaceGatewayConnectionActive,
|
|
97981
|
-
workspaceGatewayCustomModels,
|
|
97982
|
-
workspaceOpenRouterConnectionActive:
|
|
97983
|
-
workspaceOpenRouterCustomModels,
|
|
97984
|
-
organizationGatewayConnectionActive,
|
|
97985
|
-
organizationOpenRouterConnectionActive,
|
|
97986
|
-
organizationGatewayCustomModels,
|
|
97987
|
-
organizationOpenRouterCustomModels
|
|
98310
|
+
workspaceGatewayConnectionActive: workspaceConnectionActive("vercel_gateway"),
|
|
98311
|
+
workspaceGatewayCustomModels: workspaceCustomModels.vercel_gateway,
|
|
98312
|
+
workspaceOpenRouterConnectionActive: workspaceConnectionActive("openrouter"),
|
|
98313
|
+
workspaceOpenRouterCustomModels: workspaceCustomModels.openrouter,
|
|
98314
|
+
organizationGatewayConnectionActive: organizationProviders.vercel_gateway.active,
|
|
98315
|
+
organizationOpenRouterConnectionActive: organizationProviders.openrouter.active,
|
|
98316
|
+
organizationGatewayCustomModels: organizationProviders.vercel_gateway.models,
|
|
98317
|
+
organizationOpenRouterCustomModels: organizationProviders.openrouter.models
|
|
97988
98318
|
});
|
|
97989
98319
|
const workspaceSettings = workspace?.settings ?? {};
|
|
97990
98320
|
const defaultSelection = await resolveDefaultSessionModelForSelections(deps.db, {
|
|
97991
|
-
settings:
|
|
98321
|
+
settings: workspaceCatalogSettings,
|
|
97992
98322
|
accountId: grant.accountId,
|
|
97993
98323
|
workspaceSettings,
|
|
97994
98324
|
selections
|
|
@@ -97999,7 +98329,7 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
97999
98329
|
projectWorkspaceModelCatalog(selections, {
|
|
98000
98330
|
defaultSelection,
|
|
98001
98331
|
creditsSelection: creditsDefaultSessionModel({
|
|
98002
|
-
settings:
|
|
98332
|
+
settings: workspaceCatalogSettings,
|
|
98003
98333
|
selections,
|
|
98004
98334
|
workspaceSettings
|
|
98005
98335
|
})
|
|
@@ -98982,7 +99312,7 @@ import {
|
|
|
98982
99312
|
WorkspaceInstructionPolicyOnboardingProposalStaleResponse,
|
|
98983
99313
|
WorkspaceInstructionPolicyOperationReuseResponse,
|
|
98984
99314
|
WorkspaceInstructionPolicyRevision,
|
|
98985
|
-
WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS
|
|
99315
|
+
WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS as WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS2
|
|
98986
99316
|
} from "@opengeni/contracts";
|
|
98987
99317
|
import { requireAccessGrant as requireAccessGrant37 } from "@opengeni/core";
|
|
98988
99318
|
import {
|
|
@@ -99039,7 +99369,7 @@ function policyErrorResponse(context, error) {
|
|
|
99039
99369
|
WorkspaceInstructionPolicyOnboardingProposalContentErrorResponse.parse({
|
|
99040
99370
|
code: error.code,
|
|
99041
99371
|
message: error.message,
|
|
99042
|
-
maxChars:
|
|
99372
|
+
maxChars: WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS2
|
|
99043
99373
|
}),
|
|
99044
99374
|
422
|
|
99045
99375
|
);
|
|
@@ -99788,67 +100118,67 @@ function canonicalJson(value) {
|
|
|
99788
100118
|
}
|
|
99789
100119
|
function companyProfileEntries(profile) {
|
|
99790
100120
|
const activeRevisionId = profile.current?.revisionId ?? null;
|
|
99791
|
-
const byId = new Map(profile.revisions.map((
|
|
100121
|
+
const byId = new Map(profile.revisions.map((revision2) => [revision2.id, revision2]));
|
|
99792
100122
|
if (profile.activeRevision) byId.set(profile.activeRevision.id, profile.activeRevision);
|
|
99793
100123
|
return {
|
|
99794
|
-
entries: [...byId.values()].map((
|
|
99795
|
-
const active =
|
|
100124
|
+
entries: [...byId.values()].map((revision2) => {
|
|
100125
|
+
const active = revision2.id === activeRevisionId;
|
|
99796
100126
|
return {
|
|
99797
100127
|
id: "company-profile",
|
|
99798
|
-
revisionId:
|
|
100128
|
+
revisionId: revision2.id,
|
|
99799
100129
|
path: "company/profile",
|
|
99800
100130
|
scope: "organization",
|
|
99801
100131
|
classification: "company_profile",
|
|
99802
100132
|
title: "Company profile",
|
|
99803
100133
|
description: "Company identity, mission, products, customers, goals, and constraints.",
|
|
99804
100134
|
// Company-profile hashes cover this exact canonical field order.
|
|
99805
|
-
content: JSON.stringify(
|
|
99806
|
-
contentHash:
|
|
99807
|
-
revision:
|
|
100135
|
+
content: JSON.stringify(revision2.profile),
|
|
100136
|
+
contentHash: revision2.contentHash,
|
|
100137
|
+
revision: revision2.revision,
|
|
99808
100138
|
active,
|
|
99809
|
-
lifecycle: active ? "active" :
|
|
100139
|
+
lifecycle: active ? "active" : revision2.intent === "proposal" ? "proposal" : "historical",
|
|
99810
100140
|
provenance: {
|
|
99811
|
-
source:
|
|
99812
|
-
sourceId:
|
|
99813
|
-
trust:
|
|
100141
|
+
source: revision2.provenance.source,
|
|
100142
|
+
sourceId: revision2.provenance.sourceId,
|
|
100143
|
+
trust: revision2.intent === "proposal" ? "untrusted_proposal" : "organization_managed"
|
|
99814
100144
|
},
|
|
99815
|
-
relationships:
|
|
99816
|
-
createdAt:
|
|
100145
|
+
relationships: revision2.supersedesRevisionId && byId.has(revision2.supersedesRevisionId) ? [{ type: "supersedes", targetId: revision2.supersedesRevisionId }] : [],
|
|
100146
|
+
createdAt: revision2.createdAt
|
|
99817
100147
|
};
|
|
99818
100148
|
}),
|
|
99819
100149
|
truncated: profile.nextAfterRevision !== null
|
|
99820
100150
|
};
|
|
99821
100151
|
}
|
|
99822
100152
|
function instructionPolicyEntries(policies, activeRevisions, activatedRevisionIds) {
|
|
99823
|
-
const byId = new Map(policies.revisions.map((
|
|
99824
|
-
for (const
|
|
100153
|
+
const byId = new Map(policies.revisions.map((revision2) => [revision2.id, revision2]));
|
|
100154
|
+
for (const revision2 of activeRevisions) byId.set(revision2.id, revision2);
|
|
99825
100155
|
const activeIds = new Set(policies.activeHeads.map((head) => head.revisionId));
|
|
99826
100156
|
const activatedIds = new Set(activatedRevisionIds);
|
|
99827
100157
|
return {
|
|
99828
|
-
entries: [...byId.values()].map((
|
|
99829
|
-
const roleSegment =
|
|
99830
|
-
const active = activeIds.has(
|
|
99831
|
-
const lifecycle3 = active ? "active" : activatedIds.has(
|
|
100158
|
+
entries: [...byId.values()].map((revision2) => {
|
|
100159
|
+
const roleSegment = revision2.roleKey ?? "all";
|
|
100160
|
+
const active = activeIds.has(revision2.id);
|
|
100161
|
+
const lifecycle3 = active ? "active" : activatedIds.has(revision2.id) ? "historical" : revision2.provenance.source === "onboarding" || revision2.provenance.source === "knowledge_proposal" ? "proposal" : "inactive";
|
|
99832
100162
|
return {
|
|
99833
|
-
id: `instruction-policy:${
|
|
99834
|
-
revisionId:
|
|
99835
|
-
path: `ways-of-working/rules/${
|
|
100163
|
+
id: `instruction-policy:${revision2.kind}:${revision2.scope}:${roleSegment}`,
|
|
100164
|
+
revisionId: revision2.id,
|
|
100165
|
+
path: `ways-of-working/rules/${revision2.kind}/${revision2.scope}/${roleSegment}`,
|
|
99836
100166
|
scope: "workspace",
|
|
99837
100167
|
classification: "mandatory_rule",
|
|
99838
|
-
title:
|
|
100168
|
+
title: revision2.kind === "charter" ? "Workspace charter" : revision2.scope === "role" ? `Role policy: ${roleSegment}` : "Workspace policy",
|
|
99839
100169
|
description: active ? "Mandatory context included for applicable agents." : null,
|
|
99840
|
-
content:
|
|
99841
|
-
contentHash:
|
|
99842
|
-
revision:
|
|
100170
|
+
content: revision2.content,
|
|
100171
|
+
contentHash: revision2.contentHash,
|
|
100172
|
+
revision: revision2.revision,
|
|
99843
100173
|
active,
|
|
99844
100174
|
lifecycle: lifecycle3,
|
|
99845
100175
|
provenance: {
|
|
99846
|
-
source:
|
|
99847
|
-
sourceId:
|
|
99848
|
-
trust:
|
|
100176
|
+
source: revision2.provenance.source,
|
|
100177
|
+
sourceId: revision2.provenance.sourceId,
|
|
100178
|
+
trust: revision2.provenance.source === "human" ? "workspace_managed" : revision2.provenance.source === "legacy_import" ? "migrated" : "untrusted_proposal"
|
|
99849
100179
|
},
|
|
99850
|
-
relationships:
|
|
99851
|
-
createdAt:
|
|
100180
|
+
relationships: revision2.supersedesRevisionId && byId.has(revision2.supersedesRevisionId) ? [{ type: "supersedes", targetId: revision2.supersedesRevisionId }] : [],
|
|
100181
|
+
createdAt: revision2.createdAt
|
|
99852
100182
|
};
|
|
99853
100183
|
}),
|
|
99854
100184
|
truncated: policies.nextAfterRevision !== null
|
|
@@ -100308,11 +100638,11 @@ async function readCompanyBrainPackage(deps, input) {
|
|
|
100308
100638
|
) : Promise.resolve(null)
|
|
100309
100639
|
]);
|
|
100310
100640
|
if (!workspace) throw new HTTPException89(404, { message: "workspace not found" });
|
|
100311
|
-
const listedRevisionIds = new Set(instructionPolicies.revisions.map((
|
|
100641
|
+
const listedRevisionIds = new Set(instructionPolicies.revisions.map((revision2) => revision2.id));
|
|
100312
100642
|
const missingActiveIds = instructionPolicies.activeHeads.map((head) => head.revisionId).filter((revisionId2) => !listedRevisionIds.has(revisionId2));
|
|
100313
100643
|
const activeInstructionPolicyRevisions = [
|
|
100314
100644
|
...instructionPolicies.revisions.filter(
|
|
100315
|
-
(
|
|
100645
|
+
(revision2) => instructionPolicies.activeHeads.some((head) => head.revisionId === revision2.id)
|
|
100316
100646
|
),
|
|
100317
100647
|
...await Promise.all(
|
|
100318
100648
|
missingActiveIds.map(
|
|
@@ -100326,7 +100656,7 @@ async function readCompanyBrainPackage(deps, input) {
|
|
|
100326
100656
|
workspaceId: input.workspaceId,
|
|
100327
100657
|
subjectId: input.subjectId,
|
|
100328
100658
|
revisionIds: [...instructionPolicies.revisions, ...activeInstructionPolicyRevisions].map(
|
|
100329
|
-
(
|
|
100659
|
+
(revision2) => revision2.id
|
|
100330
100660
|
)
|
|
100331
100661
|
}
|
|
100332
100662
|
);
|
|
@@ -101443,6 +101773,7 @@ import {
|
|
|
101443
101773
|
measureInsightsPhase,
|
|
101444
101774
|
workspaceInsightsPhaseMetricObserver,
|
|
101445
101775
|
normalizeWorkspaceInsightsFilter,
|
|
101776
|
+
normalizeWorkspaceInsightsSessionScope,
|
|
101446
101777
|
requireAccessGrant as requireAccessGrant43,
|
|
101447
101778
|
WorkspaceInsightsFilterValidationError
|
|
101448
101779
|
} from "@opengeni/core";
|
|
@@ -101451,7 +101782,7 @@ import { workspaceInsightsMetricObserver } from "@opengeni/observability";
|
|
|
101451
101782
|
import { HTTPException as HTTPException95 } from "hono/http-exception";
|
|
101452
101783
|
function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
101453
101784
|
try {
|
|
101454
|
-
return normalizeWorkspaceInsightsFilter(value, field);
|
|
101785
|
+
return field === "rootSessionId" || field === "sessionId" ? normalizeWorkspaceInsightsSessionScope(value, field) : normalizeWorkspaceInsightsFilter(value, field);
|
|
101455
101786
|
} catch (error) {
|
|
101456
101787
|
if (error instanceof WorkspaceInsightsFilterValidationError) {
|
|
101457
101788
|
throw new HTTPException95(400, { message: error.message });
|
|
@@ -101482,6 +101813,8 @@ function workspaceInsightsCoalesceKey(input) {
|
|
|
101482
101813
|
input.range,
|
|
101483
101814
|
input.provider,
|
|
101484
101815
|
input.model,
|
|
101816
|
+
input.rootSessionId ?? null,
|
|
101817
|
+
input.sessionId ?? null,
|
|
101485
101818
|
input.rlsActor
|
|
101486
101819
|
]);
|
|
101487
101820
|
}
|
|
@@ -101494,6 +101827,8 @@ function registerInsightsRoutes(app, deps) {
|
|
|
101494
101827
|
const rangeRaw = c.req.query("range") ?? "week";
|
|
101495
101828
|
const providerRaw = c.req.query("provider");
|
|
101496
101829
|
const modelRaw = c.req.query("model");
|
|
101830
|
+
const rootSessionIdRaw = c.req.query("rootSessionId");
|
|
101831
|
+
const sessionIdRaw = c.req.query("sessionId");
|
|
101497
101832
|
let provider = null;
|
|
101498
101833
|
let model = null;
|
|
101499
101834
|
let outcome = "failed";
|
|
@@ -101512,12 +101847,19 @@ function registerInsightsRoutes(app, deps) {
|
|
|
101512
101847
|
}
|
|
101513
101848
|
provider = normalizeWorkspaceInsightsQueryFilter(providerRaw, "provider");
|
|
101514
101849
|
model = normalizeWorkspaceInsightsQueryFilter(modelRaw, "model");
|
|
101850
|
+
const rootSessionId = normalizeWorkspaceInsightsQueryFilter(
|
|
101851
|
+
rootSessionIdRaw,
|
|
101852
|
+
"rootSessionId"
|
|
101853
|
+
);
|
|
101854
|
+
const sessionId = normalizeWorkspaceInsightsQueryFilter(sessionIdRaw, "sessionId");
|
|
101515
101855
|
const response = await coalesce.run(
|
|
101516
101856
|
workspaceInsightsCoalesceKey({
|
|
101517
101857
|
workspaceId,
|
|
101518
101858
|
range: rangeParsed.data,
|
|
101519
101859
|
provider,
|
|
101520
101860
|
model,
|
|
101861
|
+
rootSessionId,
|
|
101862
|
+
sessionId,
|
|
101521
101863
|
rlsActor: currentSessionRlsActorIdentityKey()
|
|
101522
101864
|
}),
|
|
101523
101865
|
() => getWorkspaceInsights(
|
|
@@ -101527,7 +101869,9 @@ function registerInsightsRoutes(app, deps) {
|
|
|
101527
101869
|
workspaceId,
|
|
101528
101870
|
range: rangeParsed.data,
|
|
101529
101871
|
provider,
|
|
101530
|
-
model
|
|
101872
|
+
model,
|
|
101873
|
+
rootSessionId,
|
|
101874
|
+
sessionId
|
|
101531
101875
|
},
|
|
101532
101876
|
observePhase
|
|
101533
101877
|
)
|
|
@@ -106809,7 +107153,7 @@ import {
|
|
|
106809
107153
|
namedSubjectPersonalWorkspaceId as namedSubjectPersonalWorkspaceId2,
|
|
106810
107154
|
resolveSlackTargetAuthority as resolveSlackTargetAuthority2,
|
|
106811
107155
|
listSlackInteractionProgressDeliveryEvidence,
|
|
106812
|
-
listSessionEventPage as
|
|
107156
|
+
listSessionEventPage as listSessionEventPage4,
|
|
106813
107157
|
listSessionHumanInputRequests as listSessionHumanInputRequests2,
|
|
106814
107158
|
listPendingSlackInteractionMessageActionHandles,
|
|
106815
107159
|
listPendingSlackUserLinkAccessRequests,
|
|
@@ -107734,17 +108078,17 @@ function slackReactionInboxEntry(payload, bot, settings) {
|
|
|
107734
108078
|
};
|
|
107735
108079
|
}
|
|
107736
108080
|
async function resolveSlackLinkTargetInstallation(deps, link, workspaceId) {
|
|
107737
|
-
const
|
|
107738
|
-
if (!
|
|
108081
|
+
const route2 = await resolveSlackInstallationRoute2(deps.db, link.slackTeamId);
|
|
108082
|
+
if (!route2 || route2.connectionId !== link.connectionId || route2.accountId.length === 0) {
|
|
107739
108083
|
return null;
|
|
107740
108084
|
}
|
|
107741
108085
|
const workspace = await getWorkspace10(deps.db, workspaceId);
|
|
107742
|
-
if (!workspace || workspace.accountId !==
|
|
108086
|
+
if (!workspace || workspace.accountId !== route2.accountId) return null;
|
|
107743
108087
|
return {
|
|
107744
|
-
accountId:
|
|
107745
|
-
connectionId:
|
|
108088
|
+
accountId: route2.accountId,
|
|
108089
|
+
connectionId: route2.connectionId,
|
|
107746
108090
|
workspaceName: workspace.name,
|
|
107747
|
-
identityHome: { accountId:
|
|
108091
|
+
identityHome: { accountId: route2.accountId, workspaceId: route2.workspaceId }
|
|
107748
108092
|
};
|
|
107749
108093
|
}
|
|
107750
108094
|
function registerSlackInteractionRoutes(app, deps) {
|
|
@@ -108169,22 +108513,22 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
108169
108513
|
{ connectionId }
|
|
108170
108514
|
);
|
|
108171
108515
|
const names = /* @__PURE__ */ new Map();
|
|
108172
|
-
for (const
|
|
108173
|
-
if (names.has(
|
|
108516
|
+
for (const route2 of routes) {
|
|
108517
|
+
if (names.has(route2.targetWorkspaceId)) continue;
|
|
108174
108518
|
names.set(
|
|
108175
|
-
|
|
108176
|
-
(await getWorkspace10(deps.db,
|
|
108519
|
+
route2.targetWorkspaceId,
|
|
108520
|
+
(await getWorkspace10(deps.db, route2.targetWorkspaceId))?.name ?? null
|
|
108177
108521
|
);
|
|
108178
108522
|
}
|
|
108179
108523
|
return c.json(
|
|
108180
108524
|
SlackChannelRouteListResponse.parse({
|
|
108181
108525
|
routingEnabled: deps.settings.slackWorkspaceRoutingEnabled,
|
|
108182
|
-
routes: routes.map((
|
|
108183
|
-
slackChannelId:
|
|
108184
|
-
targetWorkspaceId:
|
|
108185
|
-
targetWorkspaceName: names.get(
|
|
108186
|
-
source:
|
|
108187
|
-
updatedAt:
|
|
108526
|
+
routes: routes.map((route2) => ({
|
|
108527
|
+
slackChannelId: route2.slackChannelId,
|
|
108528
|
+
targetWorkspaceId: route2.targetWorkspaceId,
|
|
108529
|
+
targetWorkspaceName: names.get(route2.targetWorkspaceId) ?? null,
|
|
108530
|
+
source: route2.source,
|
|
108531
|
+
updatedAt: route2.updatedAt.toISOString()
|
|
108188
108532
|
}))
|
|
108189
108533
|
})
|
|
108190
108534
|
);
|
|
@@ -108205,38 +108549,38 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
108205
108549
|
accountId: grant.accountId,
|
|
108206
108550
|
subjectId: grant.subjectId
|
|
108207
108551
|
});
|
|
108208
|
-
for (const
|
|
108209
|
-
if (
|
|
108552
|
+
for (const route2 of payload.routes) {
|
|
108553
|
+
if (route2.targetWorkspaceId === null) continue;
|
|
108210
108554
|
const authorized = await resolveSlackTargetAuthority2(deps.db, {
|
|
108211
108555
|
subjectId: grant.subjectId,
|
|
108212
108556
|
targetAccountId: grant.accountId,
|
|
108213
|
-
targetWorkspaceId:
|
|
108557
|
+
targetWorkspaceId: route2.targetWorkspaceId
|
|
108214
108558
|
});
|
|
108215
108559
|
if (!authorized || !hasPermission29(authorized.permissions, "sessions:create")) {
|
|
108216
108560
|
throw new HTTPException106(403, {
|
|
108217
|
-
message: `you cannot start work in the workspace chosen for ${
|
|
108561
|
+
message: `you cannot start work in the workspace chosen for ${route2.slackChannelId}`
|
|
108218
108562
|
});
|
|
108219
108563
|
}
|
|
108220
|
-
if (callerPersonalWorkspaceId !== null &&
|
|
108564
|
+
if (callerPersonalWorkspaceId !== null && route2.targetWorkspaceId === callerPersonalWorkspaceId) {
|
|
108221
108565
|
throw new HTTPException106(422, {
|
|
108222
|
-
message: `a channel cannot be routed to a personal workspace: work started in ${
|
|
108566
|
+
message: `a channel cannot be routed to a personal workspace: work started in ${route2.slackChannelId} would be invisible to everyone else in it`
|
|
108223
108567
|
});
|
|
108224
108568
|
}
|
|
108225
108569
|
}
|
|
108226
|
-
for (const
|
|
108227
|
-
if (
|
|
108570
|
+
for (const route2 of payload.routes) {
|
|
108571
|
+
if (route2.targetWorkspaceId === null) {
|
|
108228
108572
|
await deleteSlackChannelRoute(deps.db, home, {
|
|
108229
108573
|
connectionId: payload.connectionId,
|
|
108230
|
-
slackChannelId:
|
|
108574
|
+
slackChannelId: route2.slackChannelId
|
|
108231
108575
|
});
|
|
108232
108576
|
continue;
|
|
108233
108577
|
}
|
|
108234
108578
|
await upsertSlackChannelRoute(deps.db, home, {
|
|
108235
108579
|
connectionId: payload.connectionId,
|
|
108236
108580
|
slackTeamId: binding.slackTeamId,
|
|
108237
|
-
slackChannelId:
|
|
108581
|
+
slackChannelId: route2.slackChannelId,
|
|
108238
108582
|
targetAccountId: grant.accountId,
|
|
108239
|
-
targetWorkspaceId:
|
|
108583
|
+
targetWorkspaceId: route2.targetWorkspaceId,
|
|
108240
108584
|
decidedBySubjectId: grant.subjectId,
|
|
108241
108585
|
decidedBySlackUserId: "admin",
|
|
108242
108586
|
source: "admin"
|
|
@@ -110200,8 +110544,8 @@ async function processSlackBlockAction(deps, entry2) {
|
|
|
110200
110544
|
const actionId = separator > 0 ? entry2.text.slice(0, separator) : "";
|
|
110201
110545
|
const handleId = separator > 0 ? entry2.text.slice(separator + 1) : "";
|
|
110202
110546
|
const home = { accountId: entry2.accountId, workspaceId: entry2.workspaceId };
|
|
110203
|
-
const
|
|
110204
|
-
if (!
|
|
110547
|
+
const route2 = await resolveSlackInstallationRoute2(deps.db, entry2.slackTeamId);
|
|
110548
|
+
if (!route2 || route2.accountId !== entry2.accountId || route2.workspaceId !== entry2.workspaceId || route2.connectionId !== entry2.connectionId) {
|
|
110205
110549
|
throw new SlackInteractionPermanentError("slack_action_installation_changed");
|
|
110206
110550
|
}
|
|
110207
110551
|
if (actionId === "opengeni.route.select" || actionId === "opengeni.route.cancel") {
|
|
@@ -111051,7 +111395,7 @@ async function resolveSlackDeliveryHome(deps, interaction) {
|
|
|
111051
111395
|
}
|
|
111052
111396
|
async function deliverSlackSessionEvents(deps, interaction, claimHolderId) {
|
|
111053
111397
|
if (!interaction.sessionId) return;
|
|
111054
|
-
const page2 = await
|
|
111398
|
+
const page2 = await listSessionEventPage4(deps.db, interaction.workspaceId, interaction.sessionId, {
|
|
111055
111399
|
after: interaction.lastDeliveredSessionEventSequence,
|
|
111056
111400
|
limit: 100,
|
|
111057
111401
|
includeTypes: [...SLACK_DELIVERY_EVENT_TYPES],
|
|
@@ -111412,11 +111756,11 @@ async function deliverSlackModelText(deliver) {
|
|
|
111412
111756
|
await deliver((text) => text);
|
|
111413
111757
|
}
|
|
111414
111758
|
}
|
|
111415
|
-
async function enqueueNormalizedSlackInteraction(deps,
|
|
111759
|
+
async function enqueueNormalizedSlackInteraction(deps, route2, entry2) {
|
|
111416
111760
|
await enqueueSlackInteractionInbox(deps.db, {
|
|
111417
|
-
accountId:
|
|
111418
|
-
workspaceId:
|
|
111419
|
-
connectionId:
|
|
111761
|
+
accountId: route2.accountId,
|
|
111762
|
+
workspaceId: route2.workspaceId,
|
|
111763
|
+
connectionId: route2.connectionId,
|
|
111420
111764
|
...entry2
|
|
111421
111765
|
});
|
|
111422
111766
|
}
|
|
@@ -112153,14 +112497,14 @@ function createAppComposition(deps) {
|
|
|
112153
112497
|
app.use("/v1/*", bearerApiContractHeaderCompatibility());
|
|
112154
112498
|
app.use("*", async (c, next) => {
|
|
112155
112499
|
const url = new URL(c.req.url);
|
|
112156
|
-
const
|
|
112500
|
+
const route2 = routeLabel(url.pathname, registeredHandlerRoutePath(c));
|
|
112157
112501
|
const correlationId2 = correlationIds.get(c.req.raw) ?? crypto.randomUUID();
|
|
112158
112502
|
const start = performance.now();
|
|
112159
112503
|
const span = observability.startSpan(
|
|
112160
|
-
`HTTP ${c.req.method} ${
|
|
112504
|
+
`HTTP ${c.req.method} ${route2}`,
|
|
112161
112505
|
{
|
|
112162
112506
|
"http.request.method": c.req.method,
|
|
112163
|
-
"opengeni.route":
|
|
112507
|
+
"opengeni.route": route2
|
|
112164
112508
|
},
|
|
112165
112509
|
{ parent: null }
|
|
112166
112510
|
);
|
|
@@ -112174,7 +112518,7 @@ function createAppComposition(deps) {
|
|
|
112174
112518
|
const durationSeconds = (performance.now() - start) / 1e3;
|
|
112175
112519
|
observability.recordHttpRequest({
|
|
112176
112520
|
method: c.req.method,
|
|
112177
|
-
route,
|
|
112521
|
+
route: route2,
|
|
112178
112522
|
status,
|
|
112179
112523
|
durationSeconds
|
|
112180
112524
|
});
|
|
@@ -112186,7 +112530,7 @@ function createAppComposition(deps) {
|
|
|
112186
112530
|
});
|
|
112187
112531
|
observability.info("HTTP request completed", {
|
|
112188
112532
|
method: c.req.method,
|
|
112189
|
-
route,
|
|
112533
|
+
route: route2,
|
|
112190
112534
|
status,
|
|
112191
112535
|
durationMs: Math.round(durationSeconds * 1e3),
|
|
112192
112536
|
traceId: span.traceId,
|
|
@@ -112199,14 +112543,14 @@ function createAppComposition(deps) {
|
|
|
112199
112543
|
const durationSeconds = (performance.now() - start) / 1e3;
|
|
112200
112544
|
observability.recordHttpRequest({
|
|
112201
112545
|
method: c.req.method,
|
|
112202
|
-
route,
|
|
112546
|
+
route: route2,
|
|
112203
112547
|
status,
|
|
112204
112548
|
durationSeconds
|
|
112205
112549
|
});
|
|
112206
112550
|
observability.incrementCounter({
|
|
112207
112551
|
name: "opengeni_http_errors_total",
|
|
112208
112552
|
help: "Total OpenGeni HTTP request failures by bounded route, status, and stable code.",
|
|
112209
|
-
labels: { route, status: String(status), code: errorCode }
|
|
112553
|
+
labels: { route: route2, status: String(status), code: errorCode }
|
|
112210
112554
|
});
|
|
112211
112555
|
span.end({
|
|
112212
112556
|
attributes: {
|
|
@@ -112217,7 +112561,7 @@ function createAppComposition(deps) {
|
|
|
112217
112561
|
});
|
|
112218
112562
|
observability.error("HTTP request failed", {
|
|
112219
112563
|
method: c.req.method,
|
|
112220
|
-
route,
|
|
112564
|
+
route: route2,
|
|
112221
112565
|
status,
|
|
112222
112566
|
durationMs: Math.round(durationSeconds * 1e3),
|
|
112223
112567
|
traceId: span.traceId,
|
|
@@ -112639,6 +112983,8 @@ function createAppComposition(deps) {
|
|
|
112639
112983
|
auth: clientAuthConfig(deps.settings),
|
|
112640
112984
|
documentationUrl: deps.settings.documentationUrl,
|
|
112641
112985
|
analytics: clientAnalyticsConfig(deps.settings),
|
|
112986
|
+
legal: clientLegalConfig(deps.settings),
|
|
112987
|
+
...deps.settings.supportEmail ? { supportEmail: deps.settings.supportEmail } : {},
|
|
112642
112988
|
// Channel-A structured services (P4.4) ride exec/readFile/createEditor,
|
|
112643
112989
|
// available on every real backend; `none` has no box so they are all off.
|
|
112644
112990
|
// Per-session availability is still negotiated on /stream-capabilities.
|
|
@@ -113029,7 +113375,18 @@ function createAppComposition(deps) {
|
|
|
113029
113375
|
}
|
|
113030
113376
|
const importErrorResponse = archivedSessionImportErrorResponse(c, rawError);
|
|
113031
113377
|
if (importErrorResponse) return importErrorResponse;
|
|
113032
|
-
const error = rawError instanceof OrganizationIntegrationDeniedError4 ? new HTTPException107(403, { message: rawError.message }) : allowanceExhaustedHttpError(rawError) ?? workspaceControlBusyHttpError(rawError) ?? agentConfigHttpError(rawError) ??
|
|
113378
|
+
const error = rawError instanceof OrganizationIntegrationDeniedError4 ? new HTTPException107(403, { message: rawError.message }) : allowanceExhaustedHttpError(rawError) ?? workspaceControlBusyHttpError(rawError) ?? agentConfigHttpError(rawError) ?? modelUnavailableHttpError(rawError) ?? (rawError instanceof UnsupportedLatencyModeError2 ? new ApiHttpError(422, {
|
|
113379
|
+
code: "validation_failed",
|
|
113380
|
+
message: rawError.message,
|
|
113381
|
+
retryable: false,
|
|
113382
|
+
outcomeUnknown: false,
|
|
113383
|
+
details: {
|
|
113384
|
+
code: rawError.code,
|
|
113385
|
+
modelId: rawError.modelId,
|
|
113386
|
+
latencyMode: rawError.latencyMode,
|
|
113387
|
+
allowedLatencyModes: [...rawError.allowedLatencyModes]
|
|
113388
|
+
}
|
|
113389
|
+
}) : null) ?? requestBodyValidationHttpError(rawError) ?? invalidPathIdentifierHttpError(rawError, new URL(c.req.url).pathname) ?? rawError;
|
|
113033
113390
|
const compactionLock = codexCompactionV2ProviderLockedError(error);
|
|
113034
113391
|
const apiError = error instanceof ApiHttpError ? error : null;
|
|
113035
113392
|
const status = compactionLock ? 422 : httpStatusForError(error);
|
|
@@ -113080,7 +113437,7 @@ function workspaceActorContextExempt(method, pathname) {
|
|
|
113080
113437
|
))
|
|
113081
113438
|
return true;
|
|
113082
113439
|
if (/^\/v1\/workspaces\/[^/]+\/mcp(?:\/(?:docs|files))?$/.test(pathname)) return true;
|
|
113083
|
-
if (method === "GET" && publicWorkspaceBrowserRoutePatterns.some((
|
|
113440
|
+
if (method === "GET" && publicWorkspaceBrowserRoutePatterns.some((route2) => route2.test(pathname))) {
|
|
113084
113441
|
return true;
|
|
113085
113442
|
}
|
|
113086
113443
|
return method === "POST" && /^\/v1\/workspaces\/[^/]+\/github\/installations$/.test(pathname);
|
|
@@ -113331,6 +113688,12 @@ function clientAnalyticsConfig(settings) {
|
|
|
113331
113688
|
}
|
|
113332
113689
|
};
|
|
113333
113690
|
}
|
|
113691
|
+
function clientLegalConfig(settings) {
|
|
113692
|
+
return {
|
|
113693
|
+
...settings.legalPrivacyPolicyUrl ? { privacyPolicyUrl: settings.legalPrivacyPolicyUrl } : {},
|
|
113694
|
+
...settings.legalTermsOfServiceUrl ? { termsOfServiceUrl: settings.legalTermsOfServiceUrl } : {}
|
|
113695
|
+
};
|
|
113696
|
+
}
|
|
113334
113697
|
function structuredServicesHint(backend) {
|
|
113335
113698
|
const hasBox = backend !== "none";
|
|
113336
113699
|
return { fileSystem: hasBox, git: hasBox, terminalEvents: hasBox };
|
|
@@ -114462,4 +114825,4 @@ export {
|
|
|
114462
114825
|
withDefaultEnabledCapabilityMcpTools,
|
|
114463
114826
|
workflowIdForSession4 as workflowIdForSession
|
|
114464
114827
|
};
|
|
114465
|
-
//# sourceMappingURL=chunk-
|
|
114828
|
+
//# sourceMappingURL=chunk-ZQ7PIFGF.js.map
|