@opengeni/core 2.5.3 → 2.6.4-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/access/index.d.ts +24 -0
  2. package/dist/billing/limits.d.ts +5 -0
  3. package/dist/canonical-human-identities.js +2 -2
  4. package/dist/{chunk-ZVZJTMSV.js → chunk-OF65T3PM.js} +2 -2
  5. package/dist/{chunk-YGOMUGYS.js → chunk-QO5GVFFO.js} +17 -8
  6. package/dist/{chunk-YGOMUGYS.js.map → chunk-QO5GVFFO.js.map} +1 -1
  7. package/dist/dependencies.d.ts +10 -1
  8. package/dist/domain/company-brain-governed-writes.d.ts +15 -6
  9. package/dist/domain/company-profile-agent-admin.d.ts +3 -2
  10. package/dist/domain/environments.d.ts +1 -1
  11. package/dist/domain/memory-slack-delivery.d.ts +4 -1
  12. package/dist/domain/personal-connection-delegations.d.ts +1 -0
  13. package/dist/domain/pr-review.d.ts +1 -1
  14. package/dist/domain/scheduled-tasks.d.ts +12 -0
  15. package/dist/domain/sessions.d.ts +37 -11
  16. package/dist/domain/workspace-members.d.ts +8 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1706 -667
  19. package/dist/index.js.map +1 -1
  20. package/dist/managed-auth-session-sets.d.ts +18 -0
  21. package/dist/managed-auth-session-sets.js +3 -1
  22. package/dist/model-catalog.d.ts +89 -0
  23. package/dist/sandbox/fleet.d.ts +6 -4
  24. package/dist/sandbox/routing.d.ts +7 -2
  25. package/dist/sandbox/runtime-settings.d.ts +17 -1
  26. package/package.json +10 -10
  27. package/src/access/index.ts +140 -5
  28. package/src/application/user-resource-grants.ts +31 -2
  29. package/src/billing/limits.ts +57 -24
  30. package/src/dependencies.ts +15 -1
  31. package/src/domain/company-brain-governed-writes.ts +29 -13
  32. package/src/domain/company-profile-agent-admin.ts +3 -2
  33. package/src/domain/environments.ts +6 -34
  34. package/src/domain/memory-slack-delivery.ts +30 -0
  35. package/src/domain/personal-connection-delegations.ts +40 -7
  36. package/src/domain/remember.ts +5 -6
  37. package/src/domain/scheduled-tasks.ts +146 -1
  38. package/src/domain/sessions.ts +912 -358
  39. package/src/domain/workspace-members.ts +34 -2
  40. package/src/index.ts +1 -0
  41. package/src/managed-auth-session-sets.ts +38 -11
  42. package/src/model-catalog.ts +565 -0
  43. package/src/sandbox/fleet.ts +20 -17
  44. package/src/sandbox/routing.ts +18 -4
  45. package/src/sandbox/runtime-settings.ts +32 -0
  46. /package/dist/{chunk-ZVZJTMSV.js.map → chunk-OF65T3PM.js.map} +0 -0
package/dist/index.js CHANGED
@@ -125,8 +125,8 @@ import {
125
125
  markManagedAuthRequestActorTransitionApplied,
126
126
  releaseManagedAuthRequestActorLease,
127
127
  validateManagedAuthRequestActorLease
128
- } from "./chunk-ZVZJTMSV.js";
129
- import "./chunk-YGOMUGYS.js";
128
+ } from "./chunk-OF65T3PM.js";
129
+ import "./chunk-QO5GVFFO.js";
130
130
 
131
131
  // src/workflow-wake-contract.ts
132
132
  var SESSION_WORKFLOW_WAKE_DISPATCHER_SCHEDULE_ID = "opengeni-session-workflow-wake-dispatcher";
@@ -208,6 +208,367 @@ function filenameForMimeType(mimeType) {
208
208
  }
209
209
  }
210
210
 
211
+ // src/model-catalog.ts
212
+ import {
213
+ applyModelCatalogDocument,
214
+ configuredGatewayWorkspaceProductModelIds,
215
+ configuredModels,
216
+ configuredModelNotes,
217
+ configuredOpenRouterWorkspaceProductModelIds,
218
+ configuredProviders,
219
+ validateModelCatalogSettings,
220
+ withCodexCatalogProvider,
221
+ withWorkspaceGatewayCatalogProvider,
222
+ withWorkspaceOpenRouterCatalogProvider,
223
+ withXaiSubscriptionCatalogProvider,
224
+ WORKSPACE_GATEWAY_MODEL_ID_PREFIX,
225
+ WORKSPACE_OPENROUTER_MODEL_ID_PREFIX,
226
+ WORKSPACE_OPENROUTER_PROVIDER_ID
227
+ } from "@opengeni/config";
228
+ import {
229
+ evaluateWorkspaceModelPolicy
230
+ } from "@opengeni/contracts";
231
+ import {
232
+ getDeploymentModelCatalog,
233
+ getWorkspaceGatewayCustomModelForExecution,
234
+ getWorkspaceOpenRouterCustomModelForExecution,
235
+ listWorkspaceGatewayCustomModels,
236
+ listWorkspaceOpenRouterCustomModels
237
+ } from "@opengeni/db";
238
+ function isWorkspaceGatewayCustomModelId(settings, modelId) {
239
+ return modelId.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) && !configuredGatewayWorkspaceProductModelIds(settings).includes(modelId);
240
+ }
241
+ function isWorkspaceOpenRouterCustomModelId(settings, modelId) {
242
+ return modelId.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX) && !configuredOpenRouterWorkspaceProductModelIds(settings).includes(modelId);
243
+ }
244
+ function workspaceCustomModelReference(settings, modelId) {
245
+ if (isWorkspaceGatewayCustomModelId(settings, modelId)) {
246
+ return {
247
+ providerKind: "vercel_gateway",
248
+ upstreamModelId: modelId.slice(WORKSPACE_GATEWAY_MODEL_ID_PREFIX.length)
249
+ };
250
+ }
251
+ if (isWorkspaceOpenRouterCustomModelId(settings, modelId)) {
252
+ return {
253
+ providerKind: "openrouter",
254
+ upstreamModelId: modelId.slice(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX.length)
255
+ };
256
+ }
257
+ return null;
258
+ }
259
+ function isWorkspaceCustomModelId(settings, modelId) {
260
+ return workspaceCustomModelReference(settings, modelId) !== null;
261
+ }
262
+ async function resolveCatalogSettings(db, envSettings) {
263
+ if (envSettings.modelCatalogSource === "code") {
264
+ validateModelCatalogSettings(envSettings);
265
+ return {
266
+ settings: envSettings,
267
+ source: "code",
268
+ version: null,
269
+ modelNotes: configuredModelNotes(envSettings)
270
+ };
271
+ }
272
+ const row = await getDeploymentModelCatalog(db);
273
+ if (!row) {
274
+ throw new Error("database model catalog source is configured but the singleton row is missing");
275
+ }
276
+ const settings = applyModelCatalogDocument(envSettings, row.document);
277
+ validateModelCatalogSettings(settings);
278
+ return {
279
+ settings,
280
+ source: "database",
281
+ version: row.version,
282
+ modelNotes: configuredModelNotes(settings)
283
+ };
284
+ }
285
+ async function resolveWorkspaceCatalogSettings(db, envSettings, input) {
286
+ const retainedProductModelIds = [
287
+ ...input.retainedProductModelIds ?? [],
288
+ input.retainedProductModelId
289
+ ];
290
+ const retainedGatewayUpstreamModelIds = retainedProductModelIds.flatMap(
291
+ (productModelId) => productModelId?.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) ? [productModelId.slice(WORKSPACE_GATEWAY_MODEL_ID_PREFIX.length)] : []
292
+ );
293
+ const retainedOpenRouterUpstreamModelIds = retainedProductModelIds.flatMap(
294
+ (productModelId) => productModelId?.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX) ? [productModelId.slice(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX.length)] : []
295
+ );
296
+ const [
297
+ resolved,
298
+ activeGatewayCustomModels,
299
+ activeOpenRouterCustomModels,
300
+ retainedGatewayCustomModels,
301
+ retainedOpenRouterCustomModels
302
+ ] = await Promise.all([
303
+ resolveCatalogSettings(db, envSettings),
304
+ listWorkspaceGatewayCustomModels(db, {
305
+ accountId: input.accountId,
306
+ workspaceId: input.workspaceId
307
+ }),
308
+ listWorkspaceOpenRouterCustomModels(db, {
309
+ accountId: input.accountId,
310
+ workspaceId: input.workspaceId
311
+ }),
312
+ Promise.all(
313
+ [...new Set(retainedGatewayUpstreamModelIds)].map(
314
+ async (upstreamModelId) => await getWorkspaceGatewayCustomModelForExecution(db, {
315
+ accountId: input.accountId,
316
+ workspaceId: input.workspaceId,
317
+ upstreamModelId
318
+ })
319
+ )
320
+ ),
321
+ Promise.all(
322
+ [...new Set(retainedOpenRouterUpstreamModelIds)].map(
323
+ async (upstreamModelId) => await getWorkspaceOpenRouterCustomModelForExecution(db, {
324
+ accountId: input.accountId,
325
+ workspaceId: input.workspaceId,
326
+ upstreamModelId
327
+ })
328
+ )
329
+ )
330
+ ]);
331
+ const includeRetainedModels = (activeModels, retainedModels) => {
332
+ const customModels = [...activeModels];
333
+ const includedUpstreamModelIds = new Set(activeModels.map((model) => model.upstreamModelId));
334
+ for (const retainedCustomModel of retainedModels) {
335
+ if (retainedCustomModel && !includedUpstreamModelIds.has(retainedCustomModel.upstreamModelId)) {
336
+ customModels.push(retainedCustomModel);
337
+ includedUpstreamModelIds.add(retainedCustomModel.upstreamModelId);
338
+ }
339
+ }
340
+ return customModels;
341
+ };
342
+ const gatewayCustomModels = includeRetainedModels(
343
+ activeGatewayCustomModels,
344
+ retainedGatewayCustomModels
345
+ );
346
+ const openRouterCustomModels = includeRetainedModels(
347
+ activeOpenRouterCustomModels,
348
+ retainedOpenRouterCustomModels
349
+ );
350
+ return {
351
+ ...resolved,
352
+ settings: withWorkspaceOpenRouterCatalogProvider(
353
+ withWorkspaceGatewayCatalogProvider(resolved.settings, gatewayCustomModels),
354
+ openRouterCustomModels
355
+ )
356
+ };
357
+ }
358
+ var MODEL_CREDENTIAL_READINESS_OBSERVATION_MAX_AGE_MS = 5 * 6e4;
359
+ function modelDefinitionRunnable(model) {
360
+ return model.capabilities.inputModalities.includes("text") && model.capabilities.outputModalities.includes("text") && model.capabilities.transports.sse.runnable;
361
+ }
362
+ function observedCredentialReadiness(input) {
363
+ if (!input.observation) {
364
+ return {
365
+ status: "not_ready",
366
+ reason: "prerequisites_missing",
367
+ basis: input.basis,
368
+ checkedAt: null
369
+ };
370
+ }
371
+ const checkedAtMs = Date.parse(input.observation.checkedAt);
372
+ if (!Number.isFinite(checkedAtMs)) {
373
+ return {
374
+ status: "error",
375
+ reason: "resolver_error",
376
+ basis: input.basis,
377
+ checkedAt: null
378
+ };
379
+ }
380
+ const checkedAt = new Date(checkedAtMs).toISOString();
381
+ if (Math.abs(input.nowMs - checkedAtMs) > input.maxAgeMs) {
382
+ return {
383
+ status: "not_ready",
384
+ reason: "observation_stale",
385
+ basis: input.basis,
386
+ checkedAt
387
+ };
388
+ }
389
+ if (input.observation.status === "ready") {
390
+ return { status: "ready", reason: null, basis: input.basis, checkedAt };
391
+ }
392
+ if (input.observation.status === "not_ready") {
393
+ return {
394
+ status: "not_ready",
395
+ reason: input.observation.reason === "needs_reauth" ? "needs_reauth" : "prerequisites_missing",
396
+ basis: input.basis,
397
+ checkedAt
398
+ };
399
+ }
400
+ return {
401
+ status: "error",
402
+ reason: "resolver_error",
403
+ basis: input.basis,
404
+ checkedAt
405
+ };
406
+ }
407
+ function credentialReadinessFor(input) {
408
+ const source = input.model.credentialSource;
409
+ if (source.kind === "connected_subscription") {
410
+ const active = source.provider === "xai" ? input.xaiSubscriptionActive : input.codexSubscriptionActive;
411
+ return active ? { status: "ready", reason: null, basis: "connection", checkedAt: null } : {
412
+ status: "not_ready",
413
+ reason: "needs_reauth",
414
+ basis: "connection",
415
+ checkedAt: null
416
+ };
417
+ }
418
+ if (source.kind === "workspace_connection") {
419
+ const connectionActive = input.model.providerId === WORKSPACE_OPENROUTER_PROVIDER_ID ? input.workspaceOpenRouterConnectionActive : input.workspaceGatewayConnectionActive;
420
+ return connectionActive ? { status: "ready", reason: null, basis: "connection", checkedAt: null } : {
421
+ status: "not_ready",
422
+ reason: "needs_reauth",
423
+ basis: "connection",
424
+ checkedAt: null
425
+ };
426
+ }
427
+ if (source.kind === "deployment" && source.mechanism === "none") {
428
+ return { status: "ready", reason: null, basis: "configuration", checkedAt: null };
429
+ }
430
+ if (source.kind === "deployment" && source.mechanism === "api_key") {
431
+ return input.provider?.apiKey ? { status: "ready", reason: null, basis: "configuration", checkedAt: null } : {
432
+ status: "not_ready",
433
+ reason: "missing_credential",
434
+ basis: "configuration",
435
+ checkedAt: null
436
+ };
437
+ }
438
+ return observedCredentialReadiness({
439
+ observation: input.observation,
440
+ basis: "resolver",
441
+ nowMs: input.nowMs,
442
+ maxAgeMs: input.maxAgeMs
443
+ });
444
+ }
445
+ function isXaiGrokModel(model) {
446
+ return model.providerId === "xai" && model.id.startsWith("xai/grok-");
447
+ }
448
+ function observationTimestamp(observation) {
449
+ if (!observation || typeof observation.checkedAt !== "string") {
450
+ return { checkedAt: null, checkedAtMs: null };
451
+ }
452
+ const checkedAtMs = Date.parse(observation.checkedAt);
453
+ if (!Number.isFinite(checkedAtMs)) {
454
+ return { checkedAt: null, checkedAtMs: null };
455
+ }
456
+ return { checkedAt: new Date(checkedAtMs).toISOString(), checkedAtMs };
457
+ }
458
+ function xaiGrokAvailabilityFor(input) {
459
+ const { checkedAt, checkedAtMs } = observationTimestamp(input.observation);
460
+ const freshSuccessfulObservation = input.observation?.status === "available" && input.observation.reason === null && checkedAtMs !== null && checkedAtMs <= input.nowMs && input.nowMs - checkedAtMs <= input.maxAgeMs;
461
+ if (freshSuccessfulObservation) {
462
+ return {
463
+ status: "available",
464
+ selectable: true,
465
+ reason: null,
466
+ checkedAt
467
+ };
468
+ }
469
+ return {
470
+ status: "unavailable",
471
+ selectable: false,
472
+ reason: input.observation?.status === "unavailable" ? input.observation.reason ?? "provider_unhealthy" : "provider_unhealthy",
473
+ checkedAt
474
+ };
475
+ }
476
+ function availabilityFor(input) {
477
+ if (!modelDefinitionRunnable(input.model)) {
478
+ return {
479
+ status: "unavailable",
480
+ selectable: false,
481
+ reason: "unsupported",
482
+ checkedAt: null
483
+ };
484
+ }
485
+ if (input.credentialReadiness.status !== "ready") {
486
+ return {
487
+ status: "unavailable",
488
+ selectable: false,
489
+ reason: input.credentialReadiness.reason === "missing_credential" ? "missing_credential" : input.credentialReadiness.reason === "needs_reauth" ? "needs_reauth" : "credential_not_ready",
490
+ checkedAt: input.credentialReadiness.checkedAt
491
+ };
492
+ }
493
+ if (!input.policyAllowed) {
494
+ return {
495
+ status: "unavailable",
496
+ selectable: false,
497
+ reason: "policy_blocked",
498
+ checkedAt: null
499
+ };
500
+ }
501
+ if (isXaiGrokModel(input.model)) {
502
+ return xaiGrokAvailabilityFor({
503
+ observation: input.observation,
504
+ nowMs: input.nowMs,
505
+ maxAgeMs: input.maxAgeMs
506
+ });
507
+ }
508
+ if (!input.observation) {
509
+ return { status: "unknown", selectable: true, reason: null, checkedAt: null };
510
+ }
511
+ if (input.observation.status === "unavailable") {
512
+ return {
513
+ status: "unavailable",
514
+ selectable: false,
515
+ reason: input.observation.reason ?? "provider_unhealthy",
516
+ checkedAt: input.observation.checkedAt
517
+ };
518
+ }
519
+ return {
520
+ status: input.observation.status,
521
+ selectable: true,
522
+ reason: null,
523
+ checkedAt: input.observation.checkedAt
524
+ };
525
+ }
526
+ function resolveWorkspaceModelSelection(input) {
527
+ const codexSettings = input.settings.codexSubscriptionEnabled ? withCodexCatalogProvider(input.settings) : input.settings;
528
+ const xaiSettings = input.settings.supergrokSubscriptionEnabled ? withXaiSubscriptionCatalogProvider(codexSettings) : codexSettings;
529
+ const catalogSettings = withWorkspaceOpenRouterCatalogProvider(
530
+ withWorkspaceGatewayCatalogProvider(xaiSettings, input.workspaceGatewayCustomModels ?? []),
531
+ input.workspaceOpenRouterCustomModels ?? []
532
+ );
533
+ const providers = new Map(
534
+ configuredProviders(catalogSettings).map((provider) => [provider.id, provider])
535
+ );
536
+ const requestedNowMs = input.now?.getTime();
537
+ const nowMs = typeof requestedNowMs === "number" && Number.isFinite(requestedNowMs) ? requestedNowMs : Date.now();
538
+ const maxAgeMs = typeof input.credentialReadinessMaxAgeMs === "number" && Number.isFinite(input.credentialReadinessMaxAgeMs) && input.credentialReadinessMaxAgeMs >= 0 ? input.credentialReadinessMaxAgeMs : MODEL_CREDENTIAL_READINESS_OBSERVATION_MAX_AGE_MS;
539
+ return configuredModels(catalogSettings).map((model) => {
540
+ const provider = providers.get(model.providerId);
541
+ const policyAllowed = evaluateWorkspaceModelPolicy(input.policy, {
542
+ providerId: model.providerId,
543
+ modelId: model.id
544
+ }).allowed;
545
+ const credentialReadiness = credentialReadinessFor({
546
+ model,
547
+ provider,
548
+ codexSubscriptionActive: input.codexSubscriptionActive,
549
+ xaiSubscriptionActive: input.xaiSubscriptionActive === true,
550
+ workspaceGatewayConnectionActive: input.workspaceGatewayConnectionActive === true,
551
+ workspaceOpenRouterConnectionActive: input.workspaceOpenRouterConnectionActive === true,
552
+ observation: input.credentialReadinessObservations?.[model.definitionVersion],
553
+ nowMs,
554
+ maxAgeMs
555
+ });
556
+ return {
557
+ model,
558
+ credentialReadiness,
559
+ policyAllowed,
560
+ availability: availabilityFor({
561
+ model,
562
+ credentialReadiness,
563
+ policyAllowed,
564
+ observation: input.observations?.[model.definitionVersion],
565
+ nowMs,
566
+ maxAgeMs
567
+ })
568
+ };
569
+ });
570
+ }
571
+
211
572
  // src/sandbox/fleet.ts
212
573
  import {
213
574
  authorizePersonalMachineForAttempt,
@@ -260,6 +621,16 @@ import {
260
621
  function directRetainedProcessMatchesBackend(durable, process, backend) {
261
622
  return durable.providerSessionId === process.providerSessionId && durable.providerBackend === backend.kind && durable.providerInstanceId === backend.providerInstanceId && durable.leaseEpoch === backend.leaseEpoch && durable.routeKind === "active" && durable.routeTargetId === backend.sandboxId && durable.routeEpoch === backend.activeEpoch;
262
623
  }
624
+ function retainedProcessBackgroundSettlement(process, fallback) {
625
+ if (process.state === "active") {
626
+ throw new Error("Retained-process settlement returned an active durable process");
627
+ }
628
+ return {
629
+ outcome: process.state,
630
+ exitCode: process.exitCode,
631
+ reason: process.settlementReason ?? fallback.reason
632
+ };
633
+ }
263
634
  function relayConfigFromSettings(settings) {
264
635
  const raw = settings.selfhostedRelayUrl?.trim();
265
636
  if (!raw) {
@@ -460,7 +831,7 @@ function wrapChannelABoxWithRouting(services, ids, established) {
460
831
  "API retained-process settlement lost its exact durable backend identity"
461
832
  );
462
833
  }
463
- await settleRetainedProcess(db, {
834
+ const settlement = await settleRetainedProcess(db, {
464
835
  accountId: ids.accountId,
465
836
  workspaceId: ids.workspaceId,
466
837
  sessionId: ids.sessionId,
@@ -471,14 +842,13 @@ function wrapChannelABoxWithRouting(services, ids, established) {
471
842
  reason: proof.reason,
472
843
  idleGraceMs: settings.sandboxIdleGraceMs
473
844
  });
845
+ const backgroundSettlement = retainedProcessBackgroundSettlement(settlement.process, proof);
474
846
  await settleSessionBackgroundCommandForRetainedProcess(db, {
475
847
  accountId: ids.accountId,
476
848
  workspaceId: ids.workspaceId,
477
849
  sessionId: ids.sessionId,
478
850
  retainedProcessId: process.id,
479
- outcome: proof.outcome,
480
- exitCode: proof.exitCode,
481
- reason: proof.reason
851
+ ...backgroundSettlement
482
852
  });
483
853
  } : void 0;
484
854
  const resolver = makeActiveBackendResolver({
@@ -588,6 +958,235 @@ function wrapChannelABoxWithRouting(services, ids, established) {
588
958
  return { ...established, session: proxy };
589
959
  }
590
960
 
961
+ // src/sandbox/runtime-settings.ts
962
+ import {
963
+ CapabilityPack
964
+ } from "@opengeni/contracts";
965
+ import {
966
+ getRigVersion,
967
+ getWorkspacePack,
968
+ listPackInstallations
969
+ } from "@opengeni/db";
970
+ import { resolveModalCheckpointProviderBinding } from "@opengeni/runtime/sandbox";
971
+
972
+ // src/rigs/provider-images.ts
973
+ import { createHash } from "crypto";
974
+ import {
975
+ RigProviderImage as RigProviderImageContract,
976
+ stableJson
977
+ } from "@opengeni/contracts";
978
+ function sha256(value) {
979
+ return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
980
+ }
981
+ function rigProviderImageProviderBindingKeyHash(bindingKey) {
982
+ return sha256(bindingKey);
983
+ }
984
+ function rigProviderImageSetupHash(definition) {
985
+ return sha256(definition.setupScript ?? "");
986
+ }
987
+ function rigProviderImageContentHash(input) {
988
+ return sha256(
989
+ stableJson({
990
+ version: 2,
991
+ backend: input.backend,
992
+ sourceImage: input.sourceImage,
993
+ setupScript: input.definition.setupScript,
994
+ checks: input.definition.checks,
995
+ credentialHooks: input.definition.credentialHooks,
996
+ defaultVariableSetIds: input.definition.defaultVariableSetIds
997
+ })
998
+ );
999
+ }
1000
+ function rigProviderImageBuildRequestId(input) {
1001
+ const bytes = createHash("sha256").update("opengeni-rig-provider-image-build-v2\0", "utf8").update(input.targetId, "utf8").update("\0", "utf8").update(input.backend, "utf8").update("\0", "utf8").update(input.contentHash, "utf8").digest().subarray(0, 16);
1002
+ bytes[6] = bytes[6] & 15 | 80;
1003
+ bytes[8] = bytes[8] & 63 | 128;
1004
+ const hex = bytes.toString("hex");
1005
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
1006
+ }
1007
+ function rigProviderImageMatchesDefinition(image, definition) {
1008
+ return image.setupHash === rigProviderImageSetupHash(definition) && image.contentHash === rigProviderImageContentHash({
1009
+ backend: image.backend,
1010
+ sourceImage: image.sourceImage,
1011
+ definition
1012
+ });
1013
+ }
1014
+ function rigProviderImagesFromVerification(verification, definition) {
1015
+ const parsed = RigProviderImageContract.safeParse(verification?.providerImage);
1016
+ if (!parsed.success || parsed.data.status === "building") return {};
1017
+ if (!rigProviderImageMatchesDefinition(parsed.data, definition)) return {};
1018
+ return { [parsed.data.backend]: parsed.data };
1019
+ }
1020
+
1021
+ // src/sandbox/runtime-settings.ts
1022
+ function managedSessionGroupBackend(deploymentBackend, sessionBackend) {
1023
+ if (sessionBackend === "none") return null;
1024
+ const backend = sessionBackend === "selfhosted" ? deploymentBackend : sessionBackend;
1025
+ return backend === "none" || backend === "selfhosted" ? null : backend;
1026
+ }
1027
+ function managedSessionGroupOs(sessionBackend, sessionOs) {
1028
+ return sessionBackend === "selfhosted" ? "linux" : sessionOs;
1029
+ }
1030
+ function packInstallationUsesLegacyRuntime(input) {
1031
+ return input.manifestSnapshot === null && input.manifestDigest === null;
1032
+ }
1033
+ async function resolveWorkspaceLegacyRuntimePacks(db, workspaceId) {
1034
+ const installations = await listPackInstallations(db, workspaceId);
1035
+ const packs2 = [];
1036
+ for (const installation of installations) {
1037
+ if (installation.status !== "active" || !packInstallationUsesLegacyRuntime(installation)) {
1038
+ continue;
1039
+ }
1040
+ const registration = await getWorkspacePack(db, workspaceId, installation.packId);
1041
+ const parsed = CapabilityPack.safeParse(registration?.pack);
1042
+ if (parsed.success) packs2.push(parsed.data);
1043
+ }
1044
+ return packs2;
1045
+ }
1046
+ function legacySandboxRuntimeFromPacks(packs2) {
1047
+ const imagePacks = packs2.filter(
1048
+ (pack) => typeof pack.sandboxImage === "string" && pack.sandboxImage.trim().length > 0
1049
+ );
1050
+ if (imagePacks.length > 1) {
1051
+ const ids = imagePacks.map((pack) => pack.id).sort().join(", ");
1052
+ throw new Error(
1053
+ `Multiple enabled packs declare a sandbox image (${ids}). Only one enabled pack per workspace may declare sandboxImage; disable the others and retry.`
1054
+ );
1055
+ }
1056
+ return {
1057
+ sandboxImage: imagePacks[0]?.sandboxImage?.trim() ?? null,
1058
+ sandboxProviderImages: imagePacks[0]?.sandboxProviderImages ?? null
1059
+ };
1060
+ }
1061
+ function settingsWithPackSandboxImage(settings, sandboxImage, sandboxProviderImages = null) {
1062
+ if (!sandboxImage) return settings;
1063
+ return {
1064
+ ...settings,
1065
+ dockerImage: sandboxImage,
1066
+ modalImageRef: sandboxImage,
1067
+ modalImageId: sandboxProviderImages?.modal?.imageId
1068
+ };
1069
+ }
1070
+ function settingsWithRigImage(settings, rigImage) {
1071
+ void rigImage;
1072
+ return settings;
1073
+ }
1074
+ function rigProviderImageSourceImage(settings, backend) {
1075
+ if (backend === "modal") return settings.modalImageId ?? settings.modalImageRef ?? null;
1076
+ if (backend === "docker") return settings.dockerImage ?? null;
1077
+ return null;
1078
+ }
1079
+ function resolveRigProviderImageSelection(settings, version, backend, currentProviderBindingKeyHash) {
1080
+ if (!version) return { settings, reason: "missing", contentHash: null, imageId: null };
1081
+ if (backend !== "modal") {
1082
+ return { settings, reason: "provider_unsupported", contentHash: null, imageId: null };
1083
+ }
1084
+ const image = version.providerImages[backend];
1085
+ if (!image) return { settings, reason: "missing", contentHash: null, imageId: null };
1086
+ if (image.status !== "ready" || !image.imageId) {
1087
+ return {
1088
+ settings,
1089
+ reason: "not_ready",
1090
+ contentHash: image.contentHash,
1091
+ imageId: image.imageId
1092
+ };
1093
+ }
1094
+ if (image.coldBootValidation?.version !== 1) {
1095
+ return {
1096
+ settings,
1097
+ reason: "not_cold_boot_validated",
1098
+ contentHash: image.contentHash,
1099
+ imageId: null
1100
+ };
1101
+ }
1102
+ const sourceImage = rigProviderImageSourceImage(settings, backend);
1103
+ const expectedContentHash = rigProviderImageContentHash({
1104
+ backend,
1105
+ sourceImage,
1106
+ definition: version
1107
+ });
1108
+ if (image.sourceImage !== sourceImage || image.contentHash !== expectedContentHash || !rigProviderImageMatchesDefinition(image, version)) {
1109
+ return {
1110
+ settings,
1111
+ reason: "content_mismatch",
1112
+ contentHash: expectedContentHash,
1113
+ imageId: null
1114
+ };
1115
+ }
1116
+ if (!image.providerBindingKeyHash || !currentProviderBindingKeyHash) {
1117
+ return {
1118
+ settings,
1119
+ reason: "provider_binding_unavailable",
1120
+ contentHash: expectedContentHash,
1121
+ imageId: null
1122
+ };
1123
+ }
1124
+ if (image.providerBindingKeyHash !== currentProviderBindingKeyHash) {
1125
+ return {
1126
+ settings,
1127
+ reason: "provider_binding_mismatch",
1128
+ contentHash: expectedContentHash,
1129
+ imageId: null
1130
+ };
1131
+ }
1132
+ return {
1133
+ settings: { ...settings, modalImageId: image.imageId },
1134
+ reason: "selected",
1135
+ contentHash: expectedContentHash,
1136
+ imageId: image.imageId
1137
+ };
1138
+ }
1139
+ async function resolveRigProviderImageForRun(settings, version, backend, resolveBinding = resolveModalCheckpointProviderBinding) {
1140
+ const image = backend === "modal" ? version?.providerImages.modal : null;
1141
+ if (image?.status !== "ready" || !image.providerBindingKeyHash) {
1142
+ return resolveRigProviderImageSelection(settings, version, backend, null);
1143
+ }
1144
+ const structural = resolveRigProviderImageSelection(
1145
+ settings,
1146
+ version,
1147
+ backend,
1148
+ image.providerBindingKeyHash
1149
+ );
1150
+ if (structural.reason !== "selected") return structural;
1151
+ let currentProviderBindingKeyHash = null;
1152
+ try {
1153
+ const binding = await resolveBinding(settings);
1154
+ currentProviderBindingKeyHash = rigProviderImageProviderBindingKeyHash(binding.key);
1155
+ } catch {
1156
+ }
1157
+ return resolveRigProviderImageSelection(
1158
+ settings,
1159
+ version,
1160
+ backend,
1161
+ currentProviderBindingKeyHash
1162
+ );
1163
+ }
1164
+ async function settingsWithRigProviderImage(settings, version, backend, resolveBinding = resolveModalCheckpointProviderBinding) {
1165
+ return (await resolveRigProviderImageForRun(settings, version, backend, resolveBinding)).settings;
1166
+ }
1167
+ async function resolveSessionSandboxRuntime(db, settings, session) {
1168
+ const [packs2, rigVersion] = await Promise.all([
1169
+ resolveWorkspaceLegacyRuntimePacks(db, session.workspaceId),
1170
+ session.rigId && session.rigVersionId ? getRigVersion(db, session.workspaceId, session.rigId, session.rigVersionId) : Promise.resolve(null)
1171
+ ]);
1172
+ if (session.rigVersionId && !rigVersion) {
1173
+ throw new Error(`Frozen rig version ${session.rigVersionId} is unavailable`);
1174
+ }
1175
+ const legacy = legacySandboxRuntimeFromPacks(packs2);
1176
+ const logicalSettings = rigVersion ? settings : settingsWithPackSandboxImage(settings, legacy.sandboxImage, legacy.sandboxProviderImages);
1177
+ return {
1178
+ settings: {
1179
+ ...logicalSettings,
1180
+ sandboxBackend: session.sandboxBackend
1181
+ },
1182
+ image: rigProviderImageSourceImage(logicalSettings, session.sandboxBackend),
1183
+ rigVersion
1184
+ };
1185
+ }
1186
+ async function providerSettingsForSessionSandboxRuntime(runtime, backend) {
1187
+ return await settingsWithRigProviderImage(runtime.settings, runtime.rigVersion, backend);
1188
+ }
1189
+
591
1190
  // src/sandbox/fleet.ts
592
1191
  async function buildFleetContextForSession(deps, ctx) {
593
1192
  const session = await requireSession(deps.db, ctx.workspaceId, ctx.sessionId);
@@ -661,7 +1260,11 @@ async function listFleet(services, ctx) {
661
1260
  activeEpoch: 0
662
1261
  };
663
1262
  const entries = [];
664
- if (ctx.sessionBackend !== "none") {
1263
+ const groupBackend = managedSessionGroupBackend(
1264
+ services.settings.sandboxBackend,
1265
+ ctx.sessionBackend
1266
+ );
1267
+ if (groupBackend) {
665
1268
  const groupActive = pointer.activeSandboxId === null;
666
1269
  const groupLease = await readLease(db, ctx.workspaceId, ctx.sessionGroupId);
667
1270
  const groupOnline = Boolean(
@@ -673,10 +1276,10 @@ async function listFleet(services, ctx) {
673
1276
  const groupRecoveryUnavailable = Boolean(
674
1277
  groupLease && (groupLease.recovery.restore.status === "degraded" || groupLease.recovery.restore.status === "unrecoverable" || groupLease.recovery.workspace.status === "degraded" || groupLease.recovery.workspace.status === "unrecoverable")
675
1278
  );
676
- const groupOperationAvailability = groupOnline ? "ready" : groupRecoveryUnavailable ? "unavailable" : groupRecovering ? "recovering" : ctx.sessionBackend === "selfhosted" ? "unavailable" : "wakeable";
1279
+ const groupOperationAvailability = groupOnline ? "ready" : groupRecoveryUnavailable ? "unavailable" : groupRecovering ? "recovering" : "wakeable";
677
1280
  entries.push({
678
1281
  id: ctx.sessionGroupId,
679
- kind: ctx.sessionBackend === "selfhosted" ? "selfhosted" : ctx.sessionBackend === "opensandbox" ? "opensandbox" : "modal",
1282
+ kind: groupBackend === "opensandbox" ? "opensandbox" : "modal",
680
1283
  name: "session sandbox",
681
1284
  liveness: groupOnline ? "online" : groupRecovering ? "reconnecting" : "offline",
682
1285
  active: groupActive,
@@ -780,10 +1383,10 @@ async function listFleet(services, ctx) {
780
1383
  }
781
1384
  async function resolveTarget(services, ctx, target) {
782
1385
  if (target === ctx.sessionGroupId || target === "session" || target === "default") {
783
- if (ctx.sessionBackend === "none") {
1386
+ if (!managedSessionGroupBackend(services.settings.sandboxBackend, ctx.sessionBackend)) {
784
1387
  return {
785
1388
  ok: false,
786
- reason: "this session has no home sandbox; attach a Connected Machine",
1389
+ reason: ctx.sessionBackend === "none" ? "this session has no home sandbox; attach a Connected Machine" : "this deployment has no managed session sandbox; select an enrolled machine",
787
1390
  code: "unsupported_backend_context"
788
1391
  };
789
1392
  }
@@ -1227,228 +1830,7 @@ async function provisionSandbox(services, ctx, input) {
1227
1830
  kind: "modal",
1228
1831
  sandbox,
1229
1832
  note: "A named Modal sandbox record was created, but it is NOT yet attachable as a swap target: routing a session onto a second Modal box is not supported yet, so a sandbox_swap to this id is rejected. Use the session's own box (the default) or attach a Connected Machine instead."
1230
- };
1231
- }
1232
-
1233
- // src/sandbox/runtime-settings.ts
1234
- import {
1235
- CapabilityPack
1236
- } from "@opengeni/contracts";
1237
- import {
1238
- getRigVersion,
1239
- getWorkspacePack,
1240
- listPackInstallations
1241
- } from "@opengeni/db";
1242
- import { resolveModalCheckpointProviderBinding } from "@opengeni/runtime/sandbox";
1243
-
1244
- // src/rigs/provider-images.ts
1245
- import { createHash } from "crypto";
1246
- import {
1247
- RigProviderImage as RigProviderImageContract,
1248
- stableJson
1249
- } from "@opengeni/contracts";
1250
- function sha256(value) {
1251
- return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
1252
- }
1253
- function rigProviderImageProviderBindingKeyHash(bindingKey) {
1254
- return sha256(bindingKey);
1255
- }
1256
- function rigProviderImageSetupHash(definition) {
1257
- return sha256(definition.setupScript ?? "");
1258
- }
1259
- function rigProviderImageContentHash(input) {
1260
- return sha256(
1261
- stableJson({
1262
- version: 2,
1263
- backend: input.backend,
1264
- sourceImage: input.sourceImage,
1265
- setupScript: input.definition.setupScript,
1266
- checks: input.definition.checks,
1267
- credentialHooks: input.definition.credentialHooks,
1268
- defaultVariableSetIds: input.definition.defaultVariableSetIds
1269
- })
1270
- );
1271
- }
1272
- function rigProviderImageBuildRequestId(input) {
1273
- const bytes = createHash("sha256").update("opengeni-rig-provider-image-build-v2\0", "utf8").update(input.targetId, "utf8").update("\0", "utf8").update(input.backend, "utf8").update("\0", "utf8").update(input.contentHash, "utf8").digest().subarray(0, 16);
1274
- bytes[6] = bytes[6] & 15 | 80;
1275
- bytes[8] = bytes[8] & 63 | 128;
1276
- const hex = bytes.toString("hex");
1277
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
1278
- }
1279
- function rigProviderImageMatchesDefinition(image, definition) {
1280
- return image.setupHash === rigProviderImageSetupHash(definition) && image.contentHash === rigProviderImageContentHash({
1281
- backend: image.backend,
1282
- sourceImage: image.sourceImage,
1283
- definition
1284
- });
1285
- }
1286
- function rigProviderImagesFromVerification(verification, definition) {
1287
- const parsed = RigProviderImageContract.safeParse(verification?.providerImage);
1288
- if (!parsed.success || parsed.data.status === "building") return {};
1289
- if (!rigProviderImageMatchesDefinition(parsed.data, definition)) return {};
1290
- return { [parsed.data.backend]: parsed.data };
1291
- }
1292
-
1293
- // src/sandbox/runtime-settings.ts
1294
- function packInstallationUsesLegacyRuntime(input) {
1295
- return input.manifestSnapshot === null && input.manifestDigest === null;
1296
- }
1297
- async function resolveWorkspaceLegacyRuntimePacks(db, workspaceId) {
1298
- const installations = await listPackInstallations(db, workspaceId);
1299
- const packs2 = [];
1300
- for (const installation of installations) {
1301
- if (installation.status !== "active" || !packInstallationUsesLegacyRuntime(installation)) {
1302
- continue;
1303
- }
1304
- const registration = await getWorkspacePack(db, workspaceId, installation.packId);
1305
- const parsed = CapabilityPack.safeParse(registration?.pack);
1306
- if (parsed.success) packs2.push(parsed.data);
1307
- }
1308
- return packs2;
1309
- }
1310
- function legacySandboxRuntimeFromPacks(packs2) {
1311
- const imagePacks = packs2.filter(
1312
- (pack) => typeof pack.sandboxImage === "string" && pack.sandboxImage.trim().length > 0
1313
- );
1314
- if (imagePacks.length > 1) {
1315
- const ids = imagePacks.map((pack) => pack.id).sort().join(", ");
1316
- throw new Error(
1317
- `Multiple enabled packs declare a sandbox image (${ids}). Only one enabled pack per workspace may declare sandboxImage; disable the others and retry.`
1318
- );
1319
- }
1320
- return {
1321
- sandboxImage: imagePacks[0]?.sandboxImage?.trim() ?? null,
1322
- sandboxProviderImages: imagePacks[0]?.sandboxProviderImages ?? null
1323
- };
1324
- }
1325
- function settingsWithPackSandboxImage(settings, sandboxImage, sandboxProviderImages = null) {
1326
- if (!sandboxImage) return settings;
1327
- return {
1328
- ...settings,
1329
- dockerImage: sandboxImage,
1330
- modalImageRef: sandboxImage,
1331
- modalImageId: sandboxProviderImages?.modal?.imageId
1332
- };
1333
- }
1334
- function settingsWithRigImage(settings, rigImage) {
1335
- void rigImage;
1336
- return settings;
1337
- }
1338
- function rigProviderImageSourceImage(settings, backend) {
1339
- if (backend === "modal") return settings.modalImageId ?? settings.modalImageRef ?? null;
1340
- if (backend === "docker") return settings.dockerImage ?? null;
1341
- return null;
1342
- }
1343
- function resolveRigProviderImageSelection(settings, version, backend, currentProviderBindingKeyHash) {
1344
- if (!version) return { settings, reason: "missing", contentHash: null, imageId: null };
1345
- if (backend !== "modal") {
1346
- return { settings, reason: "provider_unsupported", contentHash: null, imageId: null };
1347
- }
1348
- const image = version.providerImages[backend];
1349
- if (!image) return { settings, reason: "missing", contentHash: null, imageId: null };
1350
- if (image.status !== "ready" || !image.imageId) {
1351
- return {
1352
- settings,
1353
- reason: "not_ready",
1354
- contentHash: image.contentHash,
1355
- imageId: image.imageId
1356
- };
1357
- }
1358
- if (image.coldBootValidation?.version !== 1) {
1359
- return {
1360
- settings,
1361
- reason: "not_cold_boot_validated",
1362
- contentHash: image.contentHash,
1363
- imageId: null
1364
- };
1365
- }
1366
- const sourceImage = rigProviderImageSourceImage(settings, backend);
1367
- const expectedContentHash = rigProviderImageContentHash({
1368
- backend,
1369
- sourceImage,
1370
- definition: version
1371
- });
1372
- if (image.sourceImage !== sourceImage || image.contentHash !== expectedContentHash || !rigProviderImageMatchesDefinition(image, version)) {
1373
- return {
1374
- settings,
1375
- reason: "content_mismatch",
1376
- contentHash: expectedContentHash,
1377
- imageId: null
1378
- };
1379
- }
1380
- if (!image.providerBindingKeyHash || !currentProviderBindingKeyHash) {
1381
- return {
1382
- settings,
1383
- reason: "provider_binding_unavailable",
1384
- contentHash: expectedContentHash,
1385
- imageId: null
1386
- };
1387
- }
1388
- if (image.providerBindingKeyHash !== currentProviderBindingKeyHash) {
1389
- return {
1390
- settings,
1391
- reason: "provider_binding_mismatch",
1392
- contentHash: expectedContentHash,
1393
- imageId: null
1394
- };
1395
- }
1396
- return {
1397
- settings: { ...settings, modalImageId: image.imageId },
1398
- reason: "selected",
1399
- contentHash: expectedContentHash,
1400
- imageId: image.imageId
1401
- };
1402
- }
1403
- async function resolveRigProviderImageForRun(settings, version, backend, resolveBinding = resolveModalCheckpointProviderBinding) {
1404
- const image = backend === "modal" ? version?.providerImages.modal : null;
1405
- if (image?.status !== "ready" || !image.providerBindingKeyHash) {
1406
- return resolveRigProviderImageSelection(settings, version, backend, null);
1407
- }
1408
- const structural = resolveRigProviderImageSelection(
1409
- settings,
1410
- version,
1411
- backend,
1412
- image.providerBindingKeyHash
1413
- );
1414
- if (structural.reason !== "selected") return structural;
1415
- let currentProviderBindingKeyHash = null;
1416
- try {
1417
- const binding = await resolveBinding(settings);
1418
- currentProviderBindingKeyHash = rigProviderImageProviderBindingKeyHash(binding.key);
1419
- } catch {
1420
- }
1421
- return resolveRigProviderImageSelection(
1422
- settings,
1423
- version,
1424
- backend,
1425
- currentProviderBindingKeyHash
1426
- );
1427
- }
1428
- async function settingsWithRigProviderImage(settings, version, backend, resolveBinding = resolveModalCheckpointProviderBinding) {
1429
- return (await resolveRigProviderImageForRun(settings, version, backend, resolveBinding)).settings;
1430
- }
1431
- async function resolveSessionSandboxRuntime(db, settings, session) {
1432
- const [packs2, rigVersion] = await Promise.all([
1433
- resolveWorkspaceLegacyRuntimePacks(db, session.workspaceId),
1434
- session.rigId && session.rigVersionId ? getRigVersion(db, session.workspaceId, session.rigId, session.rigVersionId) : Promise.resolve(null)
1435
- ]);
1436
- if (session.rigVersionId && !rigVersion) {
1437
- throw new Error(`Frozen rig version ${session.rigVersionId} is unavailable`);
1438
- }
1439
- const legacy = legacySandboxRuntimeFromPacks(packs2);
1440
- const logicalSettings = rigVersion ? settings : settingsWithPackSandboxImage(settings, legacy.sandboxImage, legacy.sandboxProviderImages);
1441
- return {
1442
- settings: {
1443
- ...logicalSettings,
1444
- sandboxBackend: session.sandboxBackend
1445
- },
1446
- image: rigProviderImageSourceImage(logicalSettings, session.sandboxBackend),
1447
- rigVersion
1448
- };
1449
- }
1450
- async function providerSettingsForSessionSandboxRuntime(runtime, backend) {
1451
- return await settingsWithRigProviderImage(runtime.settings, runtime.rigVersion, backend);
1833
+ };
1452
1834
  }
1453
1835
 
1454
1836
  // src/access/index.ts
@@ -1467,7 +1849,38 @@ import { HTTPException } from "hono/http-exception";
1467
1849
  var bearerPrefix = "Bearer ";
1468
1850
  var accessContextByRequest = /* @__PURE__ */ new WeakMap();
1469
1851
  var canonicalManagedCookieContexts = /* @__PURE__ */ new WeakSet();
1852
+ var canonicalLocalHumanContexts = /* @__PURE__ */ new WeakSet();
1470
1853
  var resolvedAccessGrantAuthorizations = /* @__PURE__ */ new WeakSet();
1854
+ var accountScopedApiKeyContexts = /* @__PURE__ */ new WeakMap();
1855
+ var accountScopedApiKeyAccountPermissions = /* @__PURE__ */ new Set([
1856
+ "account:read",
1857
+ "account:admin",
1858
+ "workspace:create",
1859
+ "billing:read",
1860
+ "billing:manage",
1861
+ "api_keys:manage"
1862
+ ]);
1863
+ var accountScopedApiKeyWorkspaceExcludedPermissions = /* @__PURE__ */ new Set([
1864
+ "account:read",
1865
+ "account:admin",
1866
+ "workspace:create",
1867
+ "billing:read",
1868
+ "billing:manage"
1869
+ ]);
1870
+ function accountScopedApiKeyWorkspaceAuthority(context) {
1871
+ const authority = accountScopedApiKeyContexts.get(context);
1872
+ if (!authority) return null;
1873
+ const matchingAccountGrants = context.accountGrants.filter(
1874
+ (grant) => grant.accountId === authority.accountId && grant.subjectId === context.subjectId
1875
+ );
1876
+ if (!context.subjectId.startsWith("api_key:") || matchingAccountGrants.length !== 1 || context.defaultAccountId !== authority.accountId || context.defaultWorkspaceId !== null) {
1877
+ return null;
1878
+ }
1879
+ return {
1880
+ accountId: authority.accountId,
1881
+ permissions: [...authority.permissions]
1882
+ };
1883
+ }
1471
1884
  async function requireAccessContext(c, deps) {
1472
1885
  let pending = accessContextByRequest.get(c.req.raw);
1473
1886
  if (!pending) {
@@ -1505,7 +1918,8 @@ function accessGrantAuthorizationFromContext(context, grant) {
1505
1918
  accountGrant: contextIntegrity ? matchingAccountGrants[0] : null,
1506
1919
  authenticatedSubjectId: context.subjectId,
1507
1920
  contextIntegrity,
1508
- canonicalManagedHumanSession: isCanonicalManagedHumanSession(context, grant)
1921
+ canonicalManagedHumanSession: isCanonicalManagedHumanSession(context, grant),
1922
+ canonicalLocalHumanSession: isCanonicalLocalHumanSession(context, grant)
1509
1923
  };
1510
1924
  resolvedAccessGrantAuthorizations.add(authorization);
1511
1925
  return authorization;
@@ -1522,13 +1936,31 @@ function requireAccountAdminAuthorizationStamp(authorization) {
1522
1936
  permission: "account:admin"
1523
1937
  });
1524
1938
  }
1939
+ async function requireCanonicalLocalAccountAdministrator(c, deps, accountId) {
1940
+ if (c.req.header("authorization")) {
1941
+ throw new HTTPException(401, { message: "organization administrator session required" });
1942
+ }
1943
+ const context = await requireAccessContext(c, deps);
1944
+ const grant = context.workspaceGrants.find((candidate) => candidate.accountId === accountId);
1945
+ if (!grant) {
1946
+ throw new HTTPException(403, {
1947
+ message: "local organization administration is not authorized"
1948
+ });
1949
+ }
1950
+ const authorization = accessGrantAuthorizationFromContext(context, grant);
1951
+ if (!authorization.canonicalLocalHumanSession) {
1952
+ throw new HTTPException(401, { message: "organization administrator session required" });
1953
+ }
1954
+ requireAccountAdminAuthorizationStamp(authorization);
1955
+ return { subjectId: context.subjectId, authorization };
1956
+ }
1525
1957
  async function requireAccessGrantAuthorization(c, deps, workspaceId, permission) {
1526
1958
  const context = await requireAccessContext(c, deps);
1527
1959
  return await accessGrantAuthorization(context, deps, workspaceId, permission);
1528
1960
  }
1529
1961
  async function accessGrantAuthorization(context, deps, workspaceId, permission) {
1530
1962
  const principalKind = hostedHumanSessionPrincipalKind(context);
1531
- const grant = context.workspaceGrants.find((candidate) => candidate.workspaceId === workspaceId) ?? await getWorkspaceGrant(
1963
+ let grant = context.workspaceGrants.find((candidate) => candidate.workspaceId === workspaceId) ?? await getWorkspaceGrant(
1532
1964
  deps.db,
1533
1965
  context.subjectId,
1534
1966
  workspaceId,
@@ -1539,7 +1971,20 @@ async function accessGrantAuthorization(context, deps, workspaceId, permission)
1539
1971
  if (!workspace) {
1540
1972
  throw new HTTPException(404, { message: "workspace not found" });
1541
1973
  }
1542
- throw new HTTPException(403, { message: "workspace access denied" });
1974
+ const authority = accountScopedApiKeyWorkspaceAuthority(context);
1975
+ const requiredWorkspacePermission = permission ?? "workspace:read";
1976
+ if (authority && workspace.accountId === authority.accountId && workspace.kind === "shared" && hasPermission(authority.permissions, requiredWorkspacePermission)) {
1977
+ grant = {
1978
+ workspaceId: workspace.id,
1979
+ accountId: workspace.accountId,
1980
+ subjectId: context.subjectId,
1981
+ ...context.subjectLabel ? { subjectLabel: context.subjectLabel } : {},
1982
+ permissions: authority.permissions,
1983
+ principalKind: "api_key"
1984
+ };
1985
+ } else {
1986
+ throw new HTTPException(403, { message: "workspace access denied" });
1987
+ }
1543
1988
  }
1544
1989
  if (permission) {
1545
1990
  requirePermission(grant, permission);
@@ -1549,6 +1994,9 @@ async function accessGrantAuthorization(context, deps, workspaceId, permission)
1549
1994
  function isCanonicalManagedHumanSession(context, grant) {
1550
1995
  return canonicalManagedCookieContexts.has(context) && grant.subjectId === context.subjectId && grant.subjectId.startsWith("user:");
1551
1996
  }
1997
+ function isCanonicalLocalHumanSession(context, grant) {
1998
+ return canonicalLocalHumanContexts.has(context) && context.mode === "local" && context.subjectId === "dev" && grant.subjectId === context.subjectId && grant.principalKind === "human_session" && grant.metadata?.delegated !== true && !grant.serviceInitiator;
1999
+ }
1552
2000
  function hostedHumanSessionPrincipalKind(context) {
1553
2001
  if (context.mode !== "managed" || context.workspaceGrants.length === 0) {
1554
2002
  return void 0;
@@ -1598,7 +2046,7 @@ async function resolveAccessContext(c, deps) {
1598
2046
  if (delegated) {
1599
2047
  return delegated;
1600
2048
  }
1601
- return await bootstrapWorkspace(deps.db, {
2049
+ const context = await bootstrapWorkspace(deps.db, {
1602
2050
  accountExternalSource: "opengeni:local",
1603
2051
  accountExternalId: "default",
1604
2052
  accountName: "Local",
@@ -1608,6 +2056,8 @@ async function resolveAccessContext(c, deps) {
1608
2056
  subjectId: "dev",
1609
2057
  subjectLabel: "Local dev"
1610
2058
  });
2059
+ canonicalLocalHumanContexts.add(context);
2060
+ return context;
1611
2061
  }
1612
2062
  if (deps.settings.productAccessMode === "configured") {
1613
2063
  const delegated = await delegatedAccessContext(c, deps, "configured");
@@ -1676,8 +2126,10 @@ async function apiKeyAccessContext(c, deps, mode) {
1676
2126
  const subjectId = `api_key:${apiKey.id}`;
1677
2127
  const accountPermissions = apiKey.workspaceId ? apiKey.permissions.filter(
1678
2128
  (permission) => permission === "billing:read" || permission === "billing:manage"
1679
- ) : apiKey.permissions;
1680
- return {
2129
+ ) : apiKey.permissions.filter(
2130
+ (permission) => accountScopedApiKeyAccountPermissions.has(permission)
2131
+ );
2132
+ const context = {
1681
2133
  mode,
1682
2134
  subjectId,
1683
2135
  subjectLabel: apiKey.name,
@@ -1702,6 +2154,20 @@ async function apiKeyAccessContext(c, deps, mode) {
1702
2154
  defaultAccountId: apiKey.accountId,
1703
2155
  defaultWorkspaceId: apiKey.workspaceId
1704
2156
  };
2157
+ if (apiKey.workspaceId === null && apiKey.credentialKind === "organization") {
2158
+ accountScopedApiKeyContexts.set(
2159
+ context,
2160
+ Object.freeze({
2161
+ accountId: apiKey.accountId,
2162
+ permissions: Object.freeze(
2163
+ apiKey.permissions.filter(
2164
+ (permission) => !accountScopedApiKeyWorkspaceExcludedPermissions.has(permission)
2165
+ )
2166
+ )
2167
+ })
2168
+ );
2169
+ }
2170
+ return context;
1705
2171
  }
1706
2172
  async function delegatedAccessContext(c, deps, mode, token = bearerToken(c)) {
1707
2173
  const delegationSecret = resolveFirstPartyDelegationSecret(deps.settings);
@@ -1969,9 +2435,13 @@ async function resolveSessionAuthorizationActor(db, grant) {
1969
2435
  }
1970
2436
 
1971
2437
  // src/billing/limits.ts
1972
- import { configuredStaticUsageLimits, resolveModelProvider } from "@opengeni/config";
2438
+ import {
2439
+ configuredStaticUsageLimits,
2440
+ resolveModelProviderForTurn
2441
+ } from "@opengeni/config";
1973
2442
  import {
1974
2443
  countActiveApiKeysForWorkspace,
2444
+ countActiveOrganizationApiKeysForAccount,
1975
2445
  countScheduledTasksForWorkspace,
1976
2446
  countWorkspacesForAccount,
1977
2447
  getBillingBalance,
@@ -1980,6 +2450,18 @@ import {
1980
2450
  sumUsageQuantity
1981
2451
  } from "@opengeni/db";
1982
2452
  import { HTTPException as HTTPException2 } from "hono/http-exception";
2453
+ function modelFundingForAdmission(settings, model, codexBilled) {
2454
+ const resolvedModel = model ? resolveModelProviderForTurn(settings, model)?.model : null;
2455
+ const codexSubscriptionModel = resolvedModel?.credentialSource.kind === "connected_subscription" && resolvedModel.credentialSource.provider === "codex";
2456
+ return {
2457
+ // A Codex namespace/definition never bypasses credits by itself: the live
2458
+ // workspace credential predicate above remains authoritative. SuperGrok's
2459
+ // static overlay is likewise secret-free; its worker/provider admission
2460
+ // owns live account selection before any upstream request can occur.
2461
+ fundedWithoutCredits: codexBilled || resolvedModel != null && !codexSubscriptionModel && resolvedModel.cost !== "credits",
2462
+ countsTowardTokenCap: !codexBilled && resolvedModel != null && resolvedModel.billing.upstreamPayer === "deployment"
2463
+ };
2464
+ }
1983
2465
  async function requireLimit(deps, input) {
1984
2466
  const decision = await checkLimit(deps, input);
1985
2467
  if (decision.allowed) {
@@ -1996,19 +2478,22 @@ async function checkLimit(deps, input) {
1996
2478
  workspaceId: input.workspaceId,
1997
2479
  model: input.model
1998
2480
  }) : false;
1999
- const credentialFreeExternal = input.model ? (() => {
2000
- const resolved = resolveModelProvider(deps.settings, input.model);
2001
- return resolved?.model.billing.metering === "external" && resolved.model.credentialSource.kind === "deployment" && resolved.model.credentialSource.mechanism === "none";
2002
- })() : false;
2003
- const externallyBilled = codexBilled || credentialFreeExternal;
2004
- const creditDecision = await checkCreditBalance(deps, input, externallyBilled);
2481
+ const { fundedWithoutCredits, countsTowardTokenCap } = modelFundingForAdmission(
2482
+ deps.settings,
2483
+ input.model,
2484
+ codexBilled
2485
+ );
2486
+ const creditDecision = await checkCreditBalance(deps, input, fundedWithoutCredits);
2005
2487
  if (!creditDecision.allowed) {
2006
2488
  return creditDecision;
2007
2489
  }
2008
2490
  if (deps.settings.usageLimitsMode !== "static" && deps.settings.usageLimitsMode !== "managed") {
2009
2491
  return { allowed: true };
2010
2492
  }
2011
- return await checkStaticCaps(deps, input, externallyBilled);
2493
+ return await checkStaticCaps(deps, input, {
2494
+ fundedWithoutCredits,
2495
+ countsTowardTokenCap
2496
+ });
2012
2497
  }
2013
2498
  async function checkCreditBalance(deps, input, externallyBilled) {
2014
2499
  if (externallyBilled) {
@@ -2023,9 +2508,9 @@ async function checkCreditBalance(deps, input, externallyBilled) {
2023
2508
  }
2024
2509
  return { allowed: false, code: "insufficient_credits", message: "insufficient OpenGeni credits" };
2025
2510
  }
2026
- async function checkStaticCaps(deps, input, externallyBilled) {
2511
+ async function checkStaticCaps(deps, input, funding) {
2027
2512
  const limits = configuredStaticUsageLimits(deps.settings);
2028
- if (limits.maxMonthlyCostMicrosPerAccount && isCostlyAction(input.action) && !externallyBilled) {
2513
+ if (limits.maxMonthlyCostMicrosPerAccount && isCostlyAction(input.action) && !funding.fundedWithoutCredits) {
2029
2514
  const used = await sumUsageQuantity(deps.db, {
2030
2515
  accountId: input.accountId,
2031
2516
  eventType: "model.cost",
@@ -2050,10 +2535,10 @@ async function checkStaticCaps(deps, input, externallyBilled) {
2050
2535
  );
2051
2536
  }
2052
2537
  case "api_key:create": {
2053
- if (!limits.maxApiKeysPerWorkspace || !input.workspaceId) {
2538
+ if (!limits.maxApiKeysPerWorkspace) {
2054
2539
  return { allowed: true };
2055
2540
  }
2056
- const count = await countActiveApiKeysForWorkspace(deps.db, input.workspaceId);
2541
+ const count = input.workspaceId ? await countActiveApiKeysForWorkspace(deps.db, input.workspaceId) : await countActiveOrganizationApiKeysForAccount(deps.db, input.accountId);
2057
2542
  return count < limits.maxApiKeysPerWorkspace ? { allowed: true } : blocked(
2058
2543
  "max_api_keys_per_workspace",
2059
2544
  `API key limit reached (${limits.maxApiKeysPerWorkspace})`
@@ -2094,7 +2579,7 @@ async function checkStaticCaps(deps, input, externallyBilled) {
2094
2579
  );
2095
2580
  }
2096
2581
  case "tokens:consume": {
2097
- if (externallyBilled || !limits.maxMonthlyTokensPerWorkspace || !input.workspaceId) {
2582
+ if (!funding.countsTowardTokenCap || !limits.maxMonthlyTokensPerWorkspace || !input.workspaceId) {
2098
2583
  return { allowed: true };
2099
2584
  }
2100
2585
  const used = await sumUsageQuantity(deps.db, {
@@ -4965,42 +5450,15 @@ function sha256Hex2(bytes) {
4965
5450
 
4966
5451
  // src/domain/environments.ts
4967
5452
  import { environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2 } from "@opengeni/config";
5453
+ import {
5454
+ variableSetVariableNameReservation
5455
+ } from "@opengeni/contracts";
4968
5456
  import { getVariableSet as getVariableSet2, recordAuditEvent } from "@opengeni/db";
4969
5457
  import { HTTPException as HTTPException6 } from "hono/http-exception";
4970
5458
  var MAX_ENVIRONMENTS_PER_WORKSPACE = 25;
4971
5459
  var MAX_VARIABLES_PER_ENVIRONMENT = 100;
4972
- var reservedExactNames = /* @__PURE__ */ new Set([
4973
- "HOME",
4974
- "PATH",
4975
- "SHELL",
4976
- "USER",
4977
- "LOGNAME",
4978
- "TMPDIR",
4979
- "IFS",
4980
- "ENV",
4981
- "BASH_ENV",
4982
- "NODE_OPTIONS",
4983
- "PYTHONPATH",
4984
- "PYTHONSTARTUP",
4985
- "PERL5OPT",
4986
- "PERL5LIB",
4987
- "GH_TOKEN",
4988
- "GITHUB_TOKEN",
4989
- "GITLAB_TOKEN",
4990
- "AZURE_DEVOPS_EXT_PAT",
4991
- "GIT_ASKPASS",
4992
- "GIT_TERMINAL_PROMPT"
4993
- ]);
4994
- var reservedPrefixes = [
4995
- "OPENGENI_",
4996
- "GIT_CONFIG_",
4997
- "GIT_AUTHOR_",
4998
- "GIT_COMMITTER_",
4999
- "LD_",
5000
- "DYLD_"
5001
- ];
5002
5460
  function assertAllowedVariableSetVariableName(name) {
5003
- if (reservedExactNames.has(name) || reservedPrefixes.some((prefix) => name.startsWith(prefix))) {
5461
+ if (variableSetVariableNameReservation(name)) {
5004
5462
  throw new HTTPException6(422, {
5005
5463
  message: `reserved variable set variable name / reserved environment variable name: ${name}`
5006
5464
  });
@@ -6250,15 +6708,40 @@ function personalConnectionDelegationsFromParent(input) {
6250
6708
  const projected = [
6251
6709
  ...mcp,
6252
6710
  ...input.parentDelegations.filter(
6253
- (item) => childEligible(item) && (item.connectionType === "social" || item.connectionType === "atlassian" || item.serverId === GOOGLE_DRIVE_PUBLICATION_SERVER_ID)
6711
+ (item) => childEligible(item) && (item.connectionType === "social" || item.connectionType === "atlassian" || item.connectionType === "github_personal" || item.serverId === GOOGLE_DRIVE_PUBLICATION_SERVER_ID)
6254
6712
  ).map((item) => ({ ...item }))
6255
6713
  ];
6256
- if (input.rejectActivatedConnections && projected.some((delegation) => delegation.userDelegation)) {
6714
+ const requestedGitHub = personalGitHubRepositoryResources(input.personalGitHubResources ?? []);
6715
+ const inherited = projected.flatMap((delegation) => {
6716
+ if (delegation.connectionType !== "github_personal") return [delegation];
6717
+ if (requestedGitHub.length === 0) return [];
6718
+ const snapshot = delegation.personalGitHubRepositorySelection;
6719
+ if (!snapshot) return [];
6720
+ const repositories = requestedGitHub.map((resource) => {
6721
+ const parent = snapshot.repositories.find(
6722
+ (candidate) => candidate.repositoryId === resource.repositoryId && candidate.canonicalUrl === resource.uri && candidate.ref === resource.ref
6723
+ );
6724
+ if (!parent || resource.credentialBindingId !== snapshot.credentialBindingId || resource.access === "write" && parent.access !== "write") {
6725
+ throw new Error("agent-created personal GitHub repository exceeds parent authority");
6726
+ }
6727
+ return { ...parent, access: resource.access };
6728
+ });
6729
+ return [
6730
+ {
6731
+ ...delegation,
6732
+ personalGitHubRepositorySelection: { ...snapshot, repositories }
6733
+ }
6734
+ ];
6735
+ });
6736
+ if (requestedGitHub.length > 0 && !inherited.some((delegation) => delegation.connectionType === "github_personal")) {
6737
+ throw new Error("agent-created personal GitHub repository authority is unavailable");
6738
+ }
6739
+ if (input.rejectActivatedConnections && inherited.some((delegation) => delegation.userDelegation)) {
6257
6740
  throw new Error(
6258
6741
  "scheduled connection authority is not available until task occurrence authority is activated"
6259
6742
  );
6260
6743
  }
6261
- return projected;
6744
+ return inherited;
6262
6745
  }
6263
6746
  function googleDrivePublicationDelegationFromVisibleConnections(input) {
6264
6747
  const selection = input.authoritySelection;
@@ -6471,11 +6954,6 @@ async function freezePersonalConnectionDelegations(input) {
6471
6954
  "agent-created work inherits connection authority from its exact parent turn"
6472
6955
  );
6473
6956
  }
6474
- if (personalGitHubResources.length > 0) {
6475
- throw new Error(
6476
- "agent-created personal GitHub repository authority is not activated in this delivery phase"
6477
- );
6478
- }
6479
6957
  const inherited = personalConnectionDelegationsFromParent({
6480
6958
  servers,
6481
6959
  parentDelegations: await getSessionTurnPersonalConnectionDelegations(
@@ -6484,6 +6962,7 @@ async function freezePersonalConnectionDelegations(input) {
6484
6962
  input.source.sessionId,
6485
6963
  input.source.turnId
6486
6964
  ),
6965
+ personalGitHubResources,
6487
6966
  ...input.targetSessionId ? { targetSessionId: input.targetSessionId } : {},
6488
6967
  ...input.rejectUnselectedActivatedConnections !== void 0 ? { rejectActivatedConnections: input.rejectUnselectedActivatedConnections } : {}
6489
6968
  });
@@ -6935,6 +7414,8 @@ import {
6935
7414
  createScheduledTask,
6936
7415
  deleteScheduledTask,
6937
7416
  getConnectionMetadata as getConnectionMetadata4,
7417
+ getEnrollment as getEnrollment3,
7418
+ getLiveEnrollmentConnection as getLiveEnrollmentConnection3,
6938
7419
  getKnowledgeSourceForSyncAuthority,
6939
7420
  getNestedAgentDepthDeploymentPolicy,
6940
7421
  getRig as getRig5,
@@ -6942,8 +7423,11 @@ import {
6942
7423
  getScheduledTaskIncludingDeletedForUpdate,
6943
7424
  getScheduledTaskPersonalConnectionDelegations,
6944
7425
  getScheduledTaskXaiProviderAccountAuthoritySnapshot,
7426
+ getSandbox as getSandbox4,
6945
7427
  getSessionTurnXaiProviderAccountAuthoritySnapshot as getSessionTurnXaiProviderAccountAuthoritySnapshot2,
6946
7428
  getSession as getSession3,
7429
+ lockActiveWorkspaceGatewayCustomModelForAdmission as lockActiveWorkspaceGatewayCustomModelForAdmission2,
7430
+ lockActiveWorkspaceOpenRouterCustomModelForAdmission as lockActiveWorkspaceOpenRouterCustomModelForAdmission2,
6947
7431
  nestedPostgresSqlState as nestedPostgresSqlState2,
6948
7432
  requireWorkspace as requireWorkspace4,
6949
7433
  scopedKnowledgeScopeKey,
@@ -6959,13 +7443,15 @@ import { CODEX_MODEL_ID_PREFIX, isCodexBilledModel } from "@opengeni/codex";
6959
7443
  import {
6960
7444
  canonicalizeConfiguredModelId,
6961
7445
  configuredAllowedModels,
7446
+ WORKSPACE_GATEWAY_MODEL_ID_PREFIX as WORKSPACE_GATEWAY_MODEL_ID_PREFIX2,
7447
+ WORKSPACE_OPENROUTER_MODEL_ID_PREFIX as WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2,
6962
7448
  resolveFirstPartyMcpToolPolicy,
6963
7449
  policyProviderIdForModel,
6964
7450
  resolveTurnExecutionPolicyV1,
6965
- WORKSPACE_GATEWAY_MODEL_ID_PREFIX,
6966
7451
  XAI_SUBSCRIPTION_MODEL_ID_PREFIX
6967
7452
  } from "@opengeni/config";
6968
7453
  import {
7454
+ AUTOMATIC_SESSION_TITLE_FALLBACK,
6969
7455
  CreateSessionRequest,
6970
7456
  DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
6971
7457
  DEFAULT_FIRST_PARTY_MCP_TOOLS,
@@ -6975,14 +7461,18 @@ import {
6975
7461
  SessionSpawnDenial,
6976
7462
  ServiceTurnInitiator,
6977
7463
  ServiceTurnInitiatorContext,
6978
- evaluateWorkspaceModelPolicy,
7464
+ evaluateWorkspaceModelPolicy as evaluateWorkspaceModelPolicy2,
7465
+ normalizeAutomaticSessionTitle,
6979
7466
  resolveWorkspaceSessionToolDefaults as resolveWorkspaceSessionToolDefaults2,
7467
+ metadataWithTurnExecutionPolicyV1,
7468
+ readTurnExecutionPolicyV1,
6980
7469
  stableJson as stableJson4,
6981
7470
  SessionMcpApprovalPolicy
6982
7471
  } from "@opengeni/contracts";
6983
7472
  import {
6984
7473
  createSession,
6985
7474
  createSessionWithIdempotencyKeyResult,
7475
+ canonicalSessionCommandHash,
6986
7476
  encryptVariableSetValue as encryptVariableSetValue2,
6987
7477
  getAnySessionInGroup,
6988
7478
  getEnrollment as getEnrollment2,
@@ -6993,10 +7483,10 @@ import {
6993
7483
  listDistinctRigVersionIdsInGroup,
6994
7484
  getSandbox as getSandbox3,
6995
7485
  getSession as getSession2,
7486
+ getInitializedSessionCreateReplay,
6996
7487
  getSessionAuthorityProjection as getSessionAuthorityProjection2,
6997
7488
  SessionIdConflictError,
6998
7489
  NewSessionDraftConflictError,
6999
- getSessionSpawnDenialByIdempotencyKey,
7000
7490
  getWorkspaceControlEvent,
7001
7491
  getSessionLineage,
7002
7492
  getSessionTurn,
@@ -7008,7 +7498,10 @@ import {
7008
7498
  initializeSessionStartAtomically,
7009
7499
  listSessionTurns,
7010
7500
  listSessionMcpServersForChildInheritance,
7501
+ lockActiveWorkspaceGatewayCustomModelForAdmission,
7502
+ lockActiveWorkspaceOpenRouterCustomModelForAdmission,
7011
7503
  requireSession as requireSession2,
7504
+ replaySubmittedHumanPromptFromBoundaryReceipt,
7012
7505
  submitHumanPromptInTransaction,
7013
7506
  appendSessionEventsWithLockedSessionUpdate,
7014
7507
  updateSessionTitleWithEvent,
@@ -7876,13 +8369,60 @@ function validateSessionMcpCredentialUpdates(input) {
7876
8369
  });
7877
8370
  return encryptedUpdates;
7878
8371
  }
8372
+ var AGENT_CHILD_AUTOMATIC_TITLE_CONTEXT_KEY = "agentChildAutomaticTitle";
8373
+ function freezeAgentChildAutomaticTitleInCreatorContext(context, title) {
8374
+ return title ? { ...context ?? {}, [AGENT_CHILD_AUTOMATIC_TITLE_CONTEXT_KEY]: title } : context;
8375
+ }
8376
+ function initialAutomaticTitleForSessionStart(session, requestedTitle) {
8377
+ const frozenTitle = session.createdByContext[AGENT_CHILD_AUTOMATIC_TITLE_CONTEXT_KEY];
8378
+ return typeof frozenTitle === "string" ? frozenTitle : requestedTitle ?? null;
8379
+ }
8380
+ function automaticTitleForAgentChildCreate(presentation, goal, initialMessage) {
8381
+ for (const candidate of [presentation.automaticTitleCandidate, goal?.text, initialMessage]) {
8382
+ if (typeof candidate !== "string") continue;
8383
+ const normalized = normalizeAutomaticSessionTitle(candidate);
8384
+ if (normalized && normalized !== AUTOMATIC_SESSION_TITLE_FALLBACK) return normalized;
8385
+ }
8386
+ return null;
8387
+ }
7879
8388
  async function createAndStartSessionWithOutcome(input) {
7880
- const sessionMetadata = {
7881
- ...input.metadata,
7882
- model: input.model,
7883
- reasoningEffort: input.reasoningEffort,
7884
- ...input.latencyMode !== void 0 ? { latencyMode: input.latencyMode } : {}
7885
- };
8389
+ const sessionMetadata = metadataWithTurnExecutionPolicyV1(
8390
+ {
8391
+ ...input.metadata,
8392
+ model: input.model,
8393
+ reasoningEffort: input.reasoningEffort,
8394
+ ...input.latencyMode !== void 0 ? { latencyMode: input.latencyMode } : {}
8395
+ },
8396
+ input.turnExecutionPolicy
8397
+ );
8398
+ const frozenCreatedByContext = freezeAgentChildAutomaticTitleInCreatorContext(
8399
+ input.createdByContext,
8400
+ input.initialAutomaticTitle
8401
+ );
8402
+ const requiresActiveWorkspaceCustomModel = (input.workspaceCustomModel === true || input.workspaceGatewayCustomModel === true) && input.retainWorkspaceCustomModel !== true && input.retainWorkspaceGatewayModel !== true;
8403
+ const beforeCreateCommit = requiresActiveWorkspaceCustomModel || input.beforeCreateCommit ? async (tx, sessionId, context) => {
8404
+ if (requiresActiveWorkspaceCustomModel && context?.created !== false) {
8405
+ const openRouter = input.model.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2);
8406
+ const upstreamModelId = input.model.slice(
8407
+ openRouter ? WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2.length : WORKSPACE_GATEWAY_MODEL_ID_PREFIX2.length
8408
+ );
8409
+ const active = openRouter ? await lockActiveWorkspaceOpenRouterCustomModelForAdmission(tx, {
8410
+ accountId: input.accountId,
8411
+ workspaceId: input.workspaceId,
8412
+ upstreamModelId
8413
+ }) : await lockActiveWorkspaceGatewayCustomModelForAdmission(tx, {
8414
+ accountId: input.accountId,
8415
+ workspaceId: input.workspaceId,
8416
+ upstreamModelId
8417
+ });
8418
+ if (!active) {
8419
+ throw new HTTPException11(422, {
8420
+ message: `model is not available: ${input.model}`
8421
+ });
8422
+ }
8423
+ }
8424
+ await input.beforeCreateCommit?.(tx, sessionId);
8425
+ } : void 0;
7886
8426
  if (input.createIdempotencyKey) {
7887
8427
  const keyedResult = await createSessionWithIdempotencyKeyResult(input.db, {
7888
8428
  ...input.requestedSessionId ? { requestedSessionId: input.requestedSessionId } : {},
@@ -7897,7 +8437,7 @@ async function createAndStartSessionWithOutcome(input) {
7897
8437
  toolPolicy: input.toolPolicy,
7898
8438
  metadata: sessionMetadata,
7899
8439
  ...input.createdBy ? { createdBy: input.createdBy } : {},
7900
- ...input.createdByContext ? { createdByContext: input.createdByContext } : {},
8440
+ ...frozenCreatedByContext ? { createdByContext: frozenCreatedByContext } : {},
7901
8441
  createdByActor: input.createdByActor ?? null,
7902
8442
  model: input.model,
7903
8443
  reasoningEffort: input.reasoningEffort,
@@ -7925,15 +8465,23 @@ async function createAndStartSessionWithOutcome(input) {
7925
8465
  maxNestedAgentDepthOverride: input.maxNestedAgentDepthOverride ?? null,
7926
8466
  allowNestedAgentDepthIncrease: input.allowNestedAgentDepthIncrease ?? false,
7927
8467
  subjectId: input.subjectId ?? null,
7928
- ...input.beforeCreateCommit ? { beforeCreateCommit: input.beforeCreateCommit } : {}
8468
+ ...beforeCreateCommit ? { beforeCreateCommit } : {}
7929
8469
  });
7930
8470
  if (keyedResult.denied) {
7931
8471
  throw new SessionSpawnDeniedError(SessionSpawnDenial.parse(keyedResult.denial));
7932
8472
  }
7933
8473
  const { session: keyed, created } = keyedResult;
7934
8474
  if (!created) {
8475
+ const persistedPolicy = readTurnExecutionPolicyV1(keyed.metadata);
7935
8476
  const finished3 = await finishStartSession(
7936
- keyed.temporalWorkflowId ? { ...input, seedTargetSandbox: null } : input,
8477
+ keyed.temporalWorkflowId ? {
8478
+ ...input,
8479
+ seedTargetSandbox: null,
8480
+ ...persistedPolicy.kind === "valid" ? { turnExecutionPolicy: persistedPolicy.policy } : {}
8481
+ } : {
8482
+ ...input,
8483
+ ...persistedPolicy.kind === "valid" ? { turnExecutionPolicy: persistedPolicy.policy } : {}
8484
+ },
7937
8485
  keyed
7938
8486
  );
7939
8487
  return {
@@ -7966,7 +8514,7 @@ async function createAndStartSessionWithOutcome(input) {
7966
8514
  toolPolicy: input.toolPolicy,
7967
8515
  metadata: sessionMetadata,
7968
8516
  ...input.createdBy ? { createdBy: input.createdBy } : {},
7969
- ...input.createdByContext ? { createdByContext: input.createdByContext } : {},
8517
+ ...frozenCreatedByContext ? { createdByContext: frozenCreatedByContext } : {},
7970
8518
  createdByActor: input.createdByActor ?? null,
7971
8519
  model: input.model,
7972
8520
  reasoningEffort: input.reasoningEffort,
@@ -7993,7 +8541,7 @@ async function createAndStartSessionWithOutcome(input) {
7993
8541
  maxNestedAgentDepthOverride: input.maxNestedAgentDepthOverride ?? null,
7994
8542
  allowNestedAgentDepthIncrease: input.allowNestedAgentDepthIncrease ?? false,
7995
8543
  subjectId: input.subjectId ?? null,
7996
- ...input.beforeCreateCommit ? { beforeCreateCommit: input.beforeCreateCommit } : {}
8544
+ ...beforeCreateCommit ? { beforeCreateCommit } : {}
7997
8545
  });
7998
8546
  } catch (error) {
7999
8547
  if (error instanceof SessionSpawnDeniedDbError) {
@@ -8070,6 +8618,10 @@ async function finishStartSession(input, session) {
8070
8618
  ...input.goal.maxAutoContinuations !== void 0 ? { maxAutoContinuations: input.goal.maxAutoContinuations } : {},
8071
8619
  ...input.goal.mutationPolicy !== void 0 ? { mutationPolicy: input.goal.mutationPolicy } : {}
8072
8620
  } : null,
8621
+ initialAutomaticTitle: initialAutomaticTitleForSessionStart(
8622
+ session,
8623
+ input.initialAutomaticTitle
8624
+ ),
8073
8625
  consumeNewSessionDraft: input.consumeNewSessionDraft ?? null,
8074
8626
  rememberNewSessionSelection: input.rememberNewSessionSelection ?? null,
8075
8627
  deferInitialTurn: input.deferInitialTurn === true
@@ -8108,9 +8660,6 @@ function canonicalConfiguredModel(settings, model) {
8108
8660
  if (settings.supergrokSubscriptionEnabled && canonicalModel.startsWith(XAI_SUBSCRIPTION_MODEL_ID_PREFIX)) {
8109
8661
  return canonicalModel;
8110
8662
  }
8111
- if (canonicalModel.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX)) {
8112
- return canonicalModel;
8113
- }
8114
8663
  throw new HTTPException11(422, { message: `model is not available: ${model}` });
8115
8664
  }
8116
8665
  function assertConfiguredModel(settings, model) {
@@ -8147,7 +8696,7 @@ async function assertWorkspaceModelPolicyAllows(db, settings, workspaceId, model
8147
8696
  return;
8148
8697
  }
8149
8698
  const providerId = policyProviderIdForModel(settings, canonicalModel);
8150
- const verdict = evaluateWorkspaceModelPolicy(policy, {
8699
+ const verdict = evaluateWorkspaceModelPolicy2(policy, {
8151
8700
  providerId,
8152
8701
  modelId: canonicalModel
8153
8702
  });
@@ -8169,91 +8718,8 @@ async function requireQueuedTurnForApi(db, workspaceId, sessionId, turnId) {
8169
8718
  }
8170
8719
  return turn;
8171
8720
  }
8172
- async function postUserMessageTurn(input) {
8173
- const { db, bus, workflowClient, settings, accountId, workspaceId, sessionId } = input;
8174
- const requestedModel = canonicalConfiguredModel(settings, input.model ?? null) ?? null;
8175
- const requestedReasoningEffort = input.reasoningEffort ?? null;
8176
- assertConfiguredModel(settings, requestedModel);
8177
- await assertWorkspaceModelPolicyAllows(db, settings, workspaceId, requestedModel);
8178
- const sessionForModelGate = await requireSession2(db, workspaceId, sessionId);
8179
- const effectiveModelForGate = requestedModel ?? sessionForModelGate.model;
8180
- try {
8181
- assertSessionAllowsProductModel(sessionForModelGate, effectiveModelForGate);
8182
- } catch (error) {
8183
- if (error instanceof CodexCompactionV2ProviderLockedError) {
8184
- throw new HTTPException11(422, { message: error.message, cause: error });
8185
- }
8186
- throw error;
8187
- }
8188
- const operationKey = input.clientEventId ?? crypto.randomUUID();
8189
- let result;
8190
- try {
8191
- result = await runIdempotentPersistenceTransaction(
8192
- {
8193
- stage: "session.prompt.submit",
8194
- eventTypes: ["user.message", "turn.queued", "session.status.changed"],
8195
- maxAttempts: 3
8196
- },
8197
- async () => await withWorkspaceSubjectSessionActivityRls(
8198
- db,
8199
- workspaceId,
8200
- input.actor ?? accountId,
8201
- (scoped) => submitHumanPromptInTransaction(scoped, {
8202
- accountId,
8203
- workspaceId,
8204
- sessionId,
8205
- subjectId: input.actor ?? accountId,
8206
- ...input.actorLabel ? { subjectLabel: input.actorLabel } : {},
8207
- actor: input.commandActor ?? {
8208
- type: "human",
8209
- subjectId: input.actor ?? accountId
8210
- },
8211
- operationKey,
8212
- delivery: input.delivery ?? "send",
8213
- controlEtag: input.controlEtag ?? null,
8214
- expectedDraftRevision: input.expectedDraftRevision ?? null,
8215
- text: input.text,
8216
- annotations: input.annotations ?? [],
8217
- modelContext: input.modelContext ?? null,
8218
- resources: input.resources,
8219
- ...input.composerDraftResources ? { composerDraftResources: input.composerDraftResources } : {},
8220
- model: requestedModel,
8221
- reasoningEffort: requestedReasoningEffort,
8222
- latencyMode: input.latencyMode ?? null,
8223
- reasoningEffortFallback: input.reasoningEffortFallback ?? settings.openaiReasoningEffort,
8224
- turnExecutionPolicy: input.turnExecutionPolicy,
8225
- source: input.origin === "operator" ? "api" : "user",
8226
- ...input.recordAgentRunUsage !== void 0 ? { recordAgentRunUsage: input.recordAgentRunUsage } : {},
8227
- personalConnectionDelegations: input.personalConnectionDelegations ?? [],
8228
- ...input.personalResourceAttachment ? {
8229
- personalResourceAttachment: input.personalResourceAttachment
8230
- } : {},
8231
- mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
8232
- controlLockTimeoutMs: workspaceControlRequestLockTimeoutMs()
8233
- })
8234
- )
8235
- );
8236
- } catch (error) {
8237
- if (error instanceof WorkspaceControlBusyError) {
8238
- throw error;
8239
- }
8240
- if (error instanceof PersonalResourceAttachmentAcceptanceError) {
8241
- throw new HTTPException11(
8242
- error.kind === "invalid" ? 422 : error.kind === "forbidden" ? 403 : 409,
8243
- { message: error.message, cause: error }
8244
- );
8245
- }
8246
- if (error instanceof QueueCommandConflictError || error instanceof SessionControlConflictError) {
8247
- throw new HTTPException11(409, { message: error.message });
8248
- }
8249
- if (error instanceof Error && error.message.includes("cancelled")) {
8250
- throw new HTTPException11(409, { message: error.message });
8251
- }
8252
- if (error instanceof Error && error.message.startsWith("Unknown session MCP server")) {
8253
- throw new HTTPException11(422, { message: error.message });
8254
- }
8255
- throw error;
8256
- }
8721
+ function finalizePostUserMessageTurn(input, result) {
8722
+ const { db, bus, workflowClient, accountId, workspaceId, sessionId } = input;
8257
8723
  const postCommitTask = async () => {
8258
8724
  await Promise.all([
8259
8725
  (async () => {
@@ -8312,37 +8778,151 @@ async function postUserMessageTurn(input) {
8312
8778
  origin: "core"
8313
8779
  });
8314
8780
  }
8315
- return {
8316
- accepted: result.accepted,
8317
- turn: result.turn,
8318
- receipt: {
8319
- id: result.receipt.id,
8320
- action: result.receipt.action,
8321
- operationKey: result.receipt.operationKey,
8322
- targetSessionId: result.receipt.targetSessionId,
8323
- targetTurnId: result.receipt.targetTurnId,
8324
- appliedControlRevision: result.receipt.appliedControlRevision,
8325
- appliedQueueVersion: result.receipt.appliedQueueVersion,
8326
- appliedTurnVersion: result.receipt.appliedTurnVersion,
8327
- appliedDraftRevision: result.receipt.appliedDraftRevision,
8328
- createdAt: result.receipt.createdAt.toISOString()
8329
- },
8330
- routing: result.routing,
8331
- draft: result.draft ? {
8332
- revision: result.draft.revision,
8333
- text: result.draft.text,
8334
- annotations: DraftTimelineAnnotations2.parse(result.draft.annotations),
8335
- resources: result.draft.resources,
8336
- model: result.draft.model,
8337
- reasoningEffort: result.draft.reasoningEffort,
8338
- latencyMode: result.draft.latencyMode,
8339
- sourceTurnId: result.draft.sourceTurnId,
8340
- sourceTurnVersion: result.draft.sourceTurnVersion,
8341
- updatedAt: result.draft.updatedAt.toISOString()
8342
- } : null,
8343
- interruptionCount: result.interruptionCount,
8344
- replay: result.replay
8345
- };
8781
+ return {
8782
+ accepted: result.accepted,
8783
+ turn: result.turn,
8784
+ receipt: {
8785
+ id: result.receipt.id,
8786
+ action: result.receipt.action,
8787
+ operationKey: result.receipt.operationKey,
8788
+ targetSessionId: result.receipt.targetSessionId,
8789
+ targetTurnId: result.receipt.targetTurnId,
8790
+ appliedControlRevision: result.receipt.appliedControlRevision,
8791
+ appliedQueueVersion: result.receipt.appliedQueueVersion,
8792
+ appliedTurnVersion: result.receipt.appliedTurnVersion,
8793
+ appliedDraftRevision: result.receipt.appliedDraftRevision,
8794
+ createdAt: result.receipt.createdAt.toISOString()
8795
+ },
8796
+ routing: result.routing,
8797
+ draft: result.draft ? {
8798
+ revision: result.draft.revision,
8799
+ text: result.draft.text,
8800
+ annotations: DraftTimelineAnnotations2.parse(result.draft.annotations),
8801
+ resources: result.draft.resources,
8802
+ model: result.draft.model,
8803
+ reasoningEffort: result.draft.reasoningEffort,
8804
+ latencyMode: result.draft.latencyMode,
8805
+ sourceTurnId: result.draft.sourceTurnId,
8806
+ sourceTurnVersion: result.draft.sourceTurnVersion,
8807
+ updatedAt: result.draft.updatedAt.toISOString()
8808
+ } : null,
8809
+ interruptionCount: result.interruptionCount,
8810
+ replay: result.replay
8811
+ };
8812
+ }
8813
+ async function postUserMessageTurn(input) {
8814
+ const { db, settings, accountId, workspaceId, sessionId } = input;
8815
+ const requestedModel = canonicalConfiguredModel(settings, input.model ?? null) ?? null;
8816
+ const requestedReasoningEffort = input.reasoningEffort ?? null;
8817
+ assertConfiguredModel(settings, requestedModel);
8818
+ const sessionForModelGate = await requireSession2(db, workspaceId, sessionId);
8819
+ const effectiveModelForGate = requestedModel ?? sessionForModelGate.model;
8820
+ const freshWorkspaceCustomModel = requestedModel !== null && isWorkspaceCustomModelId(settings, requestedModel) && requestedModel !== sessionForModelGate.model ? requestedModel : null;
8821
+ await assertWorkspaceModelPolicyAllows(db, settings, workspaceId, effectiveModelForGate);
8822
+ try {
8823
+ assertSessionAllowsProductModel(sessionForModelGate, effectiveModelForGate);
8824
+ } catch (error) {
8825
+ if (error instanceof CodexCompactionV2ProviderLockedError) {
8826
+ throw new HTTPException11(422, { message: error.message, cause: error });
8827
+ }
8828
+ throw error;
8829
+ }
8830
+ const operationKey = input.clientEventId ?? crypto.randomUUID();
8831
+ let result;
8832
+ try {
8833
+ result = await runIdempotentPersistenceTransaction(
8834
+ {
8835
+ stage: "session.prompt.submit",
8836
+ eventTypes: ["user.message", "turn.queued", "session.status.changed"],
8837
+ maxAttempts: 3
8838
+ },
8839
+ async () => await withWorkspaceSubjectSessionActivityRls(
8840
+ db,
8841
+ workspaceId,
8842
+ input.actor ?? accountId,
8843
+ (scoped) => submitHumanPromptInTransaction(scoped, {
8844
+ accountId,
8845
+ workspaceId,
8846
+ sessionId,
8847
+ subjectId: input.actor ?? accountId,
8848
+ ...input.actorLabel ? { subjectLabel: input.actorLabel } : {},
8849
+ actor: input.commandActor ?? {
8850
+ type: "human",
8851
+ subjectId: input.actor ?? accountId
8852
+ },
8853
+ operationKey,
8854
+ ...input.boundaryRequestHash ? { boundaryRequestHash: input.boundaryRequestHash } : {},
8855
+ delivery: input.delivery ?? "send",
8856
+ controlEtag: input.controlEtag ?? null,
8857
+ expectedDraftRevision: input.expectedDraftRevision ?? null,
8858
+ text: input.text,
8859
+ annotations: input.annotations ?? [],
8860
+ modelContext: input.modelContext ?? null,
8861
+ resources: input.resources,
8862
+ ...input.composerDraftResources ? { composerDraftResources: input.composerDraftResources } : {},
8863
+ model: requestedModel,
8864
+ reasoningEffort: requestedReasoningEffort,
8865
+ latencyMode: input.latencyMode ?? null,
8866
+ reasoningEffortFallback: input.reasoningEffortFallback ?? settings.openaiReasoningEffort,
8867
+ turnExecutionPolicy: input.turnExecutionPolicy,
8868
+ source: input.origin === "operator" ? "api" : "user",
8869
+ ...input.recordAgentRunUsage !== void 0 ? { recordAgentRunUsage: input.recordAgentRunUsage } : {},
8870
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
8871
+ ...input.personalResourceAttachment ? {
8872
+ personalResourceAttachment: input.personalResourceAttachment
8873
+ } : {},
8874
+ mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
8875
+ ...freshWorkspaceCustomModel ? {
8876
+ beforeFreshPromptCommit: async (tx) => {
8877
+ const reference = workspaceCustomModelReference(
8878
+ settings,
8879
+ freshWorkspaceCustomModel
8880
+ );
8881
+ if (!reference) {
8882
+ throw new Error("workspace custom model reference disappeared");
8883
+ }
8884
+ const active = reference.providerKind === "openrouter" ? await lockActiveWorkspaceOpenRouterCustomModelForAdmission(tx, {
8885
+ accountId,
8886
+ workspaceId,
8887
+ upstreamModelId: reference.upstreamModelId
8888
+ }) : await lockActiveWorkspaceGatewayCustomModelForAdmission(tx, {
8889
+ accountId,
8890
+ workspaceId,
8891
+ upstreamModelId: reference.upstreamModelId
8892
+ });
8893
+ if (!active) {
8894
+ throw new HTTPException11(422, {
8895
+ message: `model is not available: ${freshWorkspaceCustomModel}`
8896
+ });
8897
+ }
8898
+ }
8899
+ } : {},
8900
+ controlLockTimeoutMs: workspaceControlRequestLockTimeoutMs()
8901
+ })
8902
+ )
8903
+ );
8904
+ } catch (error) {
8905
+ if (error instanceof WorkspaceControlBusyError) {
8906
+ throw error;
8907
+ }
8908
+ if (error instanceof PersonalResourceAttachmentAcceptanceError) {
8909
+ throw new HTTPException11(
8910
+ error.kind === "invalid" ? 422 : error.kind === "forbidden" ? 403 : 409,
8911
+ { message: error.message, cause: error }
8912
+ );
8913
+ }
8914
+ if (error instanceof QueueCommandConflictError || error instanceof SessionControlConflictError) {
8915
+ throw new HTTPException11(409, { message: error.message });
8916
+ }
8917
+ if (error instanceof Error && error.message.includes("cancelled")) {
8918
+ throw new HTTPException11(409, { message: error.message });
8919
+ }
8920
+ if (error instanceof Error && error.message.startsWith("Unknown session MCP server")) {
8921
+ throw new HTTPException11(422, { message: error.message });
8922
+ }
8923
+ throw error;
8924
+ }
8925
+ return finalizePostUserMessageTurn(input, result);
8346
8926
  }
8347
8927
  function resolveChildGoalFromAcceptedSnapshot(goal, parentGoalSnapshot) {
8348
8928
  const inheritedRootConstraints = parentGoalSnapshot.state === "none" ? [] : parentGoalSnapshot.rootConstraints;
@@ -8372,9 +8952,56 @@ function resolveSessionCreateVisibility(input) {
8372
8952
  }
8373
8953
  return input.requestedVisibility === "private" ? "user_private" : "workspace_shared";
8374
8954
  }
8375
- async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawPayload, authorization) {
8376
- const { settings, db, bus, workflowClient, objectStorage } = deps;
8955
+ async function resolveWorkspaceModelBoundarySettings(deps, grant, workspaceId, modelIds, retainedProductModelId) {
8956
+ const retainedWorkspaceModel = retainedProductModelId?.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX2) === true || retainedProductModelId?.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2) === true;
8957
+ if (deps.catalogSourceSettings) {
8958
+ if (!retainedWorkspaceModel) return deps.settings;
8959
+ }
8960
+ const workspaceModelIds = modelIds.filter(
8961
+ (modelId) => typeof modelId === "string" && (modelId.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX2) || modelId.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX2))
8962
+ );
8963
+ const needsWorkspaceResolution = deps.settings.modelCatalogSource === "database" || workspaceModelIds.length > 0;
8964
+ if (!needsWorkspaceResolution) return deps.settings;
8965
+ return (await resolveWorkspaceCatalogSettings(deps.db, deps.catalogSourceSettings ?? deps.settings, {
8966
+ accountId: grant.accountId,
8967
+ workspaceId,
8968
+ ...retainedProductModelId !== void 0 ? { retainedProductModelId } : {}
8969
+ })).settings;
8970
+ }
8971
+ async function withSessionCreateUsageRecording(input) {
8972
+ let usageRecording = "recorded";
8973
+ if (input.startMode !== "realtime") {
8974
+ try {
8975
+ await recordWorkspaceUsage(input.deps, {
8976
+ accountId: input.grant.accountId,
8977
+ workspaceId: input.workspaceId,
8978
+ subjectId: input.grant.subjectId,
8979
+ eventType: "agent_run.created",
8980
+ quantity: 1,
8981
+ unit: "run",
8982
+ sourceResourceType: "session",
8983
+ sourceResourceId: input.createOutcome.session.id,
8984
+ sessionId: input.createOutcome.session.id,
8985
+ initiator: input.createOutcome.session.createdBy,
8986
+ initiatorContext: input.createOutcome.session.createdByContext,
8987
+ origin: input.origin,
8988
+ idempotencyKey: `agent_run.created:${input.workspaceId}:${input.createOutcome.session.id}`
8989
+ });
8990
+ } catch (error) {
8991
+ usageRecording = "failed";
8992
+ reportSessionUsageRecordingFailure(error);
8993
+ }
8994
+ }
8995
+ return { ...input.createOutcome, usageRecording };
8996
+ }
8997
+ async function createSessionForRequestWithOutcome(unresolvedDeps, grant, workspaceId, rawPayload, authorization, agentChildPresentation) {
8377
8998
  const payload = CreateSessionRequest.parse(rawPayload);
8999
+ if (hasReservedOpenGeniSlackBotSessionMetadata(payload.metadata)) {
9000
+ throw new HTTPException11(422, {
9001
+ message: `${OPENGENI_SLACK_BOT_SESSION_METADATA_KEY2} is reserved for scheduler routing`
9002
+ });
9003
+ }
9004
+ const db = unresolvedDeps.db;
8378
9005
  const visibilityProvided = hasOwnProperty(rawPayload, "visibility");
8379
9006
  if (payload.visibility === "private" && !grant.metadata?.["sessionId"]) {
8380
9007
  if (!authorization) {
@@ -8382,39 +9009,17 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8382
9009
  message: "managed human session required"
8383
9010
  });
8384
9011
  }
8385
- await requireManagedHumanPrivateSessionCreate(deps, authorization, workspaceId);
9012
+ await requireManagedHumanPrivateSessionCreate(unresolvedDeps, authorization, workspaceId);
8386
9013
  if (payload.sandbox === "shared" || typeof payload.sandbox === "object") {
8387
9014
  throw new HTTPException11(422, {
8388
9015
  message: "Only-me sessions require their own sandbox"
8389
9016
  });
8390
9017
  }
8391
9018
  }
8392
- if (hasReservedOpenGeniSlackBotSessionMetadata(payload.metadata)) {
8393
- throw new HTTPException11(422, {
8394
- message: `${OPENGENI_SLACK_BOT_SESSION_METADATA_KEY2} is reserved for scheduler routing`
8395
- });
8396
- }
8397
- if (payload.idempotencyKey) {
8398
- const denial = await getSessionSpawnDenialByIdempotencyKey(
8399
- db,
8400
- workspaceId,
8401
- payload.idempotencyKey
8402
- );
8403
- if (denial) {
8404
- throw new SessionSpawnDeniedError(SessionSpawnDenial.parse(denial));
8405
- }
8406
- }
8407
- await requireAtomicPersonalResourceAttachment(
8408
- deps,
8409
- authorization,
8410
- workspaceId,
8411
- payload.personalResourceAttachment,
8412
- false
8413
- );
8414
9019
  const parentSessionId = typeof grant.metadata?.["sessionId"] === "string" ? grant.metadata["sessionId"] : null;
8415
9020
  if (parentSessionId) {
8416
9021
  try {
8417
- await requireSessionAuthorization(deps, grant, {
9022
+ await requireSessionAuthorization(unresolvedDeps, grant, {
8418
9023
  sessionId: parentSessionId,
8419
9024
  operation: "session.child.create",
8420
9025
  surface: "core"
@@ -8464,6 +9069,102 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8464
9069
  message: "caller attempt does not belong to the parent session"
8465
9070
  });
8466
9071
  }
9072
+ const replayManagedHumanSubjectId = creationInitiator.actor ? parentCallingTurn?.initiatingHumanSubjectId ?? (parentCallingTurn?.initiator.kind === "subject" ? parentCallingTurn.initiator.subjectId : null) : authorization?.canonicalManagedHumanSession || grant.principalKind === "human_session" ? grant.subjectId : null;
9073
+ let retainedKeyedShellModel = null;
9074
+ if (payload.idempotencyKey && (effectiveVisibility !== "user_private" || replayManagedHumanSubjectId !== null)) {
9075
+ try {
9076
+ const initializedReplay = await getInitializedSessionCreateReplay(db, {
9077
+ accountId: grant.accountId,
9078
+ workspaceId,
9079
+ subjectId: replayManagedHumanSubjectId ?? grant.subjectId,
9080
+ ...replayManagedHumanSubjectId ? { activeManagedHumanSubjectId: replayManagedHumanSubjectId } : {},
9081
+ createIdempotencyKey: payload.idempotencyKey,
9082
+ ...payload.requestedSessionId ? { requestedSessionId: payload.requestedSessionId } : {},
9083
+ visibility: effectiveVisibility,
9084
+ variableSetIds: payload.variableSetIds ?? [],
9085
+ initialPersonalResourceAttachmentIntent: payload.personalResourceAttachment ?? null,
9086
+ deferInitialTurn: payload.startMode === "realtime"
9087
+ });
9088
+ if (initializedReplay) {
9089
+ if (initializedReplay.outcome === "denied") {
9090
+ throw new SessionSpawnDeniedError(SessionSpawnDenial.parse(initializedReplay.denial));
9091
+ }
9092
+ if (initializedReplay.outcome === "pending") {
9093
+ retainedKeyedShellModel = initializedReplay.session.model;
9094
+ } else {
9095
+ if (initializedReplay.workflowWakeRevision !== null) {
9096
+ await unresolvedDeps.workflowClient.wakeSessionWorkflow({
9097
+ accountId: grant.accountId,
9098
+ workspaceId,
9099
+ sessionId: initializedReplay.session.id,
9100
+ workflowId: initializedReplay.temporalWorkflowId,
9101
+ wakeRevision: initializedReplay.workflowWakeRevision
9102
+ });
9103
+ }
9104
+ return await withSessionCreateUsageRecording({
9105
+ deps: unresolvedDeps,
9106
+ grant,
9107
+ workspaceId,
9108
+ startMode: payload.startMode,
9109
+ origin: creationInitiator.actor ? "system" : "user",
9110
+ createOutcome: {
9111
+ session: initializedReplay.session,
9112
+ outcome: initializedReplay.changed ? "repaired" : "replayed",
9113
+ replay: !initializedReplay.changed,
9114
+ changed: initializedReplay.changed
9115
+ }
9116
+ });
9117
+ }
9118
+ }
9119
+ } catch (error) {
9120
+ if (error instanceof SessionIdConflictError) {
9121
+ throw new HTTPException11(409, {
9122
+ message: "requested session id is already in use"
9123
+ });
9124
+ }
9125
+ if (error instanceof SessionCreateIdempotencyConflictError) {
9126
+ throw new HTTPException11(409, { message: error.message, cause: error });
9127
+ }
9128
+ throw error;
9129
+ }
9130
+ }
9131
+ let settings = await resolveWorkspaceModelBoundarySettings(
9132
+ unresolvedDeps,
9133
+ grant,
9134
+ workspaceId,
9135
+ [payload.model],
9136
+ retainedKeyedShellModel
9137
+ );
9138
+ let deps = settings === unresolvedDeps.settings ? unresolvedDeps : {
9139
+ ...unresolvedDeps,
9140
+ catalogSourceSettings: unresolvedDeps.catalogSourceSettings ?? unresolvedDeps.settings,
9141
+ settings
9142
+ };
9143
+ const { bus, workflowClient, objectStorage } = deps;
9144
+ await requireAtomicPersonalResourceAttachment(
9145
+ deps,
9146
+ authorization,
9147
+ workspaceId,
9148
+ payload.personalResourceAttachment,
9149
+ false
9150
+ );
9151
+ const inheritedModel = parentCallingTurn?.model ?? parentSession?.model ?? settings.openaiModel;
9152
+ const effectiveModelId = payload.model ?? inheritedModel;
9153
+ const effectiveCatalogSettings = await resolveWorkspaceModelBoundarySettings(
9154
+ deps,
9155
+ grant,
9156
+ workspaceId,
9157
+ [effectiveModelId],
9158
+ parentSession ? inheritedModel : null
9159
+ );
9160
+ if (effectiveCatalogSettings !== settings) {
9161
+ deps = {
9162
+ ...deps,
9163
+ catalogSourceSettings: deps.catalogSourceSettings ?? settings,
9164
+ settings: effectiveCatalogSettings
9165
+ };
9166
+ settings = effectiveCatalogSettings;
9167
+ }
8467
9168
  let effectiveGoal = payload.goal;
8468
9169
  if (parentSession && payload.goal) {
8469
9170
  try {
@@ -8480,6 +9181,11 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8480
9181
  });
8481
9182
  }
8482
9183
  }
9184
+ const initialAutomaticTitle = parentSession && agentChildPresentation ? automaticTitleForAgentChildCreate(
9185
+ agentChildPresentation,
9186
+ effectiveGoal,
9187
+ payload.initialMessage
9188
+ ) : null;
8483
9189
  const personalResourceSubjectId = creationInitiator.actor ? (await requireLiveAgentAttemptAuthorization(db, grant, creationInitiator.actor.sessionId)).initiatingHumanSubjectId : grant.subjectId;
8484
9190
  const xaiProviderAccountAuthoritySnapshot = parentSession && creationInitiator.actor ? await getSessionTurnXaiProviderAccountAuthoritySnapshot(
8485
9191
  db,
@@ -8609,8 +9315,7 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8609
9315
  }
8610
9316
  channelId = channel.id;
8611
9317
  }
8612
- const inheritedModel = parentCallingTurn?.model ?? parentSession?.model ?? settings.openaiModel;
8613
- const model = canonicalConfiguredModel(settings, payload.model ?? inheritedModel);
9318
+ const model = canonicalConfiguredModel(settings, effectiveModelId);
8614
9319
  if (model === null || model === void 0) {
8615
9320
  throw new Error("effective session model unexpectedly resolved to null");
8616
9321
  }
@@ -8733,6 +9438,8 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8733
9438
  const sandboxChoice = payload.sandbox ?? (payload.targetSandboxId ? "new" : parentSessionId ? "shared" : "new");
8734
9439
  let sandboxGroupId = null;
8735
9440
  let inheritedBackend;
9441
+ let inheritedSandboxOs;
9442
+ let inheritedActiveTarget = null;
8736
9443
  const requestedVariableSetIds = variableSets.map((variableSet) => variableSet.id);
8737
9444
  const variableSetsMatchGroup = (memberVariableSetIds) => stableJson4(memberVariableSetIds) === stableJson4(requestedVariableSetIds);
8738
9445
  const rigVersionMatchesGroup = (memberRigVersionId) => memberRigVersionId === frozenRigVersionId;
@@ -8768,6 +9475,11 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8768
9475
  } else {
8769
9476
  sandboxGroupId = parent.sandboxGroupId;
8770
9477
  inheritedBackend = parent.sandboxBackend;
9478
+ inheritedSandboxOs = parent.sandboxOs;
9479
+ inheritedActiveTarget = parent.activeSandboxId ? {
9480
+ sandboxId: parent.activeSandboxId,
9481
+ workingDir: parent.workingDir
9482
+ } : null;
8771
9483
  }
8772
9484
  } else if (typeof sandboxChoice === "object") {
8773
9485
  const member = await getAnySessionInGroup(db, workspaceId, sandboxChoice.groupId);
@@ -8804,12 +9516,18 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8804
9516
  }
8805
9517
  sandboxGroupId = sandboxChoice.groupId;
8806
9518
  inheritedBackend = member.sandboxBackend;
9519
+ inheritedSandboxOs = member.sandboxOs;
8807
9520
  }
8808
9521
  if (payload.workingDir !== void 0 && !payload.targetSandboxId) {
8809
9522
  throw new HTTPException11(422, {
8810
9523
  message: "workingDir requires targetSandboxId (it is the targeted machine's working directory)"
8811
9524
  });
8812
9525
  }
9526
+ if (inheritedBackend === void 0 && !payload.targetSandboxId && (payload.sandboxBackend ?? settings.sandboxBackend) === "selfhosted") {
9527
+ throw new HTTPException11(422, {
9528
+ message: "selfhosted sessions require targetSandboxId; select an online Connected Machine"
9529
+ });
9530
+ }
8813
9531
  let machineHomeBackend;
8814
9532
  let machineHomeOs;
8815
9533
  if (payload.targetSandboxId && inheritedBackend === void 0 && settings.sandboxOwnershipEnabled && settings.sandboxSelfhostedEnabled) {
@@ -8832,6 +9550,17 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8832
9550
  }
8833
9551
  }
8834
9552
  }
9553
+ const effectiveSandboxBackend = inheritedBackend ?? machineHomeBackend ?? payload.sandboxBackend ?? settings.sandboxBackend;
9554
+ const effectiveSandboxOs = inheritedSandboxOs ?? machineHomeOs;
9555
+ const effectiveSeedTarget = payload.targetSandboxId ? {
9556
+ sandboxId: payload.targetSandboxId,
9557
+ workingDir: payload.workingDir ?? null
9558
+ } : inheritedActiveTarget;
9559
+ if (effectiveSandboxBackend === "selfhosted" && effectiveSeedTarget === null && managedSessionGroupBackend(settings.sandboxBackend, effectiveSandboxBackend) === null) {
9560
+ throw new HTTPException11(422, {
9561
+ message: "self-hosted execution runs on a Connected Machine, but no machine was selected or inherited; connect the parent session to a machine or provide machineTarget"
9562
+ });
9563
+ }
8835
9564
  if (payload.startMode !== "realtime") {
8836
9565
  await requireLimit(deps, {
8837
9566
  accountId: grant.accountId,
@@ -8868,10 +9597,10 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8868
9597
  // machine-targeted create (top-level or own-box child) labels the home
8869
9598
  // "selfhosted" (machineHomeBackend), overriding the caller/deployment
8870
9599
  // default so the row matches where the session actually runs.
8871
- sandboxBackend: inheritedBackend ?? machineHomeBackend ?? payload.sandboxBackend ?? settings.sandboxBackend,
9600
+ sandboxBackend: effectiveSandboxBackend,
8872
9601
  // Mirror the backend relabel on the OS axis: a machine-targeted own-box
8873
- // create carries a derived OS; shared spawns keep the parent-box behavior.
8874
- ...machineHomeOs ? { sandboxOs: machineHomeOs } : {},
9602
+ // create carries a derived OS; shared spawns inherit the exact parent box.
9603
+ ...effectiveSandboxOs ? { sandboxOs: effectiveSandboxOs } : {},
8875
9604
  sandboxGroupId,
8876
9605
  metadata: payload.metadata,
8877
9606
  ...creationInitiator.initiator ? { createdBy: creationInitiator.initiator } : {},
@@ -8887,6 +9616,7 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8887
9616
  rigVersionId: frozenRigVersionId,
8888
9617
  channelId,
8889
9618
  goal: effectiveGoal ?? null,
9619
+ initialAutomaticTitle,
8890
9620
  // Per-session persona instructions (already trimmed/validated by the
8891
9621
  // contracts schema). Persisted on the row; composed system-level at turn
8892
9622
  // time. Not surfaced as an event.
@@ -8898,6 +9628,8 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8898
9628
  sessionMcpServers: sessionMcpServers.metadata,
8899
9629
  personalConnectionDelegations,
8900
9630
  initialPersonalResourceAttachmentIntent: payload.personalResourceAttachment ?? null,
9631
+ workspaceCustomModel: isWorkspaceCustomModelId(settings, model),
9632
+ retainWorkspaceCustomModel: parentSession !== null && model === inheritedModel,
8901
9633
  ...xaiProviderAccountAuthoritySnapshot ? { xaiProviderAccountAuthoritySnapshot } : {},
8902
9634
  parentSessionId,
8903
9635
  createIdempotencyKey: payload.idempotencyKey ?? null,
@@ -8908,10 +9640,10 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8908
9640
  // active-sandbox pointer is seeded race-free inside createAndStartSession
8909
9641
  // (after the row exists, before the first turn dispatches). Validation
8910
9642
  // (ownership/liveness) lives in swapActiveSandbox; an invalid target 422s.
8911
- seedTargetSandbox: payload.targetSandboxId ? {
8912
- sandboxId: payload.targetSandboxId,
9643
+ seedTargetSandbox: effectiveSeedTarget ? {
9644
+ sandboxId: effectiveSeedTarget.sandboxId,
8913
9645
  settings,
8914
- workingDir: payload.workingDir ?? null,
9646
+ workingDir: effectiveSeedTarget.workingDir,
8915
9647
  resourceSubjectId: personalResourceSubjectId
8916
9648
  } : null,
8917
9649
  consumeNewSessionDraft: payload.expectedNewSessionDraftRevision !== void 0 && payload.startMode !== "realtime" ? {
@@ -8953,207 +9685,322 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
8953
9685
  message: error.message,
8954
9686
  cause: error
8955
9687
  });
8956
- }
8957
- if (error instanceof SessionCreateIdempotencyConflictError) {
8958
- throw new HTTPException11(409, { message: error.message, cause: error });
8959
- }
8960
- throw error;
8961
- }
8962
- let usageRecording = "recorded";
8963
- if (payload.startMode !== "realtime") {
8964
- try {
8965
- await recordWorkspaceUsage(deps, {
8966
- accountId: grant.accountId,
8967
- workspaceId,
8968
- subjectId: grant.subjectId,
8969
- eventType: "agent_run.created",
8970
- quantity: 1,
8971
- unit: "run",
8972
- sourceResourceType: "session",
8973
- sourceResourceId: createOutcome.session.id,
8974
- sessionId: createOutcome.session.id,
8975
- initiator: createOutcome.session.createdBy,
8976
- initiatorContext: createOutcome.session.createdByContext,
8977
- origin: creationInitiator.actor ? "system" : "user",
8978
- idempotencyKey: `agent_run.created:${workspaceId}:${createOutcome.session.id}`
8979
- });
8980
- } catch (error) {
8981
- usageRecording = "failed";
8982
- reportSessionUsageRecordingFailure(error);
8983
- }
8984
- }
8985
- return { ...createOutcome, usageRecording };
8986
- }
8987
- function reportSessionUsageRecordingFailure(_error) {
8988
- console.warn(
8989
- "[sessions] usage recording failed after committed session create; returning committed outcome",
8990
- {
8991
- errorClass: "UsageRecordingError",
8992
- errorCode: "session_create_usage_recording_failed",
8993
- origin: "core"
8994
- }
8995
- );
8996
- }
8997
- async function createSessionForRequest(deps, grant, workspaceId, rawPayload, authorization) {
8998
- return (await createSessionForRequestWithOutcome(deps, grant, workspaceId, rawPayload, authorization)).session;
8999
- }
9000
- async function acceptSessionUserMessageWithOutcome(deps, grant, workspaceId, sessionId, input) {
9001
- const { settings, db, bus, workflowClient, objectStorage } = deps;
9002
- const delegatedServiceInitiator = serviceInitiatorForGrant(grant);
9003
- await requireSessionAuthorization(deps, grant, {
9004
- sessionId,
9005
- operation: input.delivery === "steer" ? "session.steer" : "session.append",
9006
- surface: "core"
9007
- });
9008
- await requireAtomicPersonalResourceAttachment(
9009
- deps,
9010
- input.authorization,
9011
- workspaceId,
9012
- input.personalResourceAttachment,
9013
- true
9014
- );
9015
- const existingSession = await requireSession2(db, workspaceId, sessionId);
9016
- const requestedModel = canonicalConfiguredModel(settings, input.model ?? null) ?? null;
9017
- const effectiveModel = canonicalConfiguredModel(settings, requestedModel ?? existingSession.model) ?? null;
9018
- if (effectiveModel === null) {
9019
- throw new Error("effective follow-up model unexpectedly resolved to null");
9020
- }
9021
- try {
9022
- assertSessionAllowsProductModel(existingSession, effectiveModel);
9023
- } catch (error) {
9024
- if (error instanceof CodexCompactionV2ProviderLockedError) {
9025
- throw new HTTPException11(422, { message: error.message, cause: error });
9026
- }
9027
- throw error;
9028
- }
9029
- const sessionReasoningEffort = existingSession.reasoningEffort;
9030
- const effectiveReasoningEffort = input.reasoningEffort ?? sessionReasoningEffort;
9031
- const sessionLatencyMode = existingSession.latencyMode;
9032
- const effectiveLatencyMode = input.latencyMode ?? sessionLatencyMode;
9033
- const turnExecutionPolicy = resolveTurnExecutionPolicyV1(settings, {
9034
- modelId: effectiveModel,
9035
- requestedModelId: input.model ?? null,
9036
- modelSource: input.model == null ? "session" : "explicit",
9037
- reasoningEffort: effectiveReasoningEffort,
9038
- reasoningSource: input.reasoningEffort == null ? "session" : "explicit",
9039
- latencyMode: effectiveLatencyMode,
9040
- latencyModeSource: input.latencyMode == null ? "session" : "explicit"
9041
- });
9042
- const requestedResources = normalizeResources(input.resources ?? []);
9043
- const composerDraftResources = input.composerDraftResources ? normalizeResources(input.composerDraftResources) : void 0;
9044
- if (composerDraftResources) {
9045
- const acceptedResources = new Set(requestedResources.map((resource) => stableJson4(resource)));
9046
- const unacceptedDraftResource = composerDraftResources.find(
9047
- (resource) => !acceptedResources.has(stableJson4(resource))
9048
- );
9049
- if (unacceptedDraftResource) {
9050
- throw new HTTPException11(422, {
9051
- message: "composer draft resources must be included in the accepted resource set"
9052
- });
9053
- }
9054
- }
9055
- const annotations = await validateSubmittedTimelineAnnotations(
9056
- db,
9057
- workspaceId,
9058
- sessionId,
9059
- input.annotations ?? []
9060
- );
9061
- await requireLimit(deps, {
9062
- accountId: grant.accountId,
9063
- workspaceId,
9064
- action: "agent_run:create",
9065
- quantity: 1,
9066
- model: effectiveModel
9067
- });
9068
- if (requestedResources.some((resource) => resource.kind === "file") && !objectStorage) {
9069
- throw new HTTPException11(503, {
9070
- message: "object storage is not configured"
9071
- });
9072
- }
9073
- await validateFileResources(
9074
- db,
9075
- grant.accountId,
9076
- workspaceId,
9077
- grant.subjectId,
9078
- requestedResources
9079
- );
9080
- await validateGitHubRepositorySelection(db, workspaceId, [
9081
- ...existingSession.resources,
9082
- ...requestedResources
9083
- ]);
9084
- const mcpCredentialUpdates = validateSessionMcpCredentialUpdates({
9085
- settings,
9086
- grant,
9087
- session: existingSession,
9088
- updates: input.mcpCredentialUpdates ?? []
9089
- });
9090
- const connectionDelegationSource = personalConnectionDelegationSourceForGrant(grant);
9091
- const inheritedPersonalConnectionDelegations = connectionDelegationSource.kind === "turn" ? await getSessionTurnPersonalConnectionDelegations2(
9092
- db,
9093
- workspaceId,
9094
- connectionDelegationSource.sessionId,
9095
- connectionDelegationSource.turnId
9096
- ) : null;
9097
- const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
9098
- db,
9099
- workspaceId,
9100
- settings,
9101
- inheritedPersonalConnectionDelegations ? {
9102
- personalConnectionDelegations: inheritedPersonalConnectionDelegations
9103
- } : { subjectId: grant.subjectId }
9104
- );
9105
- const personalConnectionDelegations = await freezePersonalConnectionDelegations({
9106
- db,
9688
+ }
9689
+ if (error instanceof SessionCreateIdempotencyConflictError) {
9690
+ throw new HTTPException11(409, { message: error.message, cause: error });
9691
+ }
9692
+ throw error;
9693
+ }
9694
+ return await withSessionCreateUsageRecording({
9695
+ deps,
9696
+ grant,
9107
9697
  workspaceId,
9108
- settings: runtimeSettings,
9109
- tools: existingSession.tools,
9110
- resources: [...existingSession.resources, ...requestedResources],
9111
- source: connectionDelegationSource,
9112
- targetSessionId: sessionId,
9113
- googleDrivePublicationEnabled: existingSession.firstPartyMcpTools.includes("editable_artifact_export") && existingSession.firstPartyMcpTools.includes("editable_artifact_export_status") && (!existingSession.firstPartyMcpPermissions?.length || existingSession.firstPartyMcpPermissions.includes("artifacts:read") && existingSession.firstPartyMcpPermissions.includes("artifacts:publish")),
9114
- atlassianEnabled: existingSession.firstPartyMcpTools.some((tool) => tool.startsWith("atlassian_")) && (!existingSession.firstPartyMcpPermissions?.length || existingSession.firstPartyMcpPermissions.includes("connections:read")),
9115
- ...input.connectionAuthorities ? { authoritySelections: input.connectionAuthorities } : {}
9698
+ startMode: payload.startMode,
9699
+ origin: creationInitiator.actor ? "system" : "user",
9700
+ createOutcome
9116
9701
  });
9117
- const { accepted, turn, draft, receipt: receipt2, routing, interruptionCount, replay } = await postUserMessageTurn({
9118
- db,
9119
- bus,
9120
- workflowClient,
9121
- settings,
9122
- accountId: grant.accountId,
9123
- workspaceId,
9702
+ }
9703
+ function reportSessionUsageRecordingFailure(_error) {
9704
+ console.warn(
9705
+ "[sessions] usage recording failed after committed session create; returning committed outcome",
9706
+ {
9707
+ errorClass: "UsageRecordingError",
9708
+ errorCode: "session_create_usage_recording_failed",
9709
+ origin: "core"
9710
+ }
9711
+ );
9712
+ }
9713
+ async function createSessionForRequest(deps, grant, workspaceId, rawPayload, authorization) {
9714
+ return (await createSessionForRequestWithOutcome(deps, grant, workspaceId, rawPayload, authorization)).session;
9715
+ }
9716
+ function sessionPromptBoundaryRequestHash(input) {
9717
+ return `prompt-boundary-v1:${canonicalSessionCommandHash({
9718
+ delivery: input.delivery,
9719
+ controlEtag: input.controlEtag,
9720
+ expectedDraftRevision: input.expectedDraftRevision,
9721
+ text: input.text,
9722
+ annotations: input.annotations,
9723
+ modelContext: input.modelContext,
9724
+ resources: input.resources,
9725
+ composerDraftResourcesProvided: input.composerDraftResources !== void 0,
9726
+ composerDraftResources: input.composerDraftResources ?? [],
9727
+ model: input.model,
9728
+ reasoningEffort: input.reasoningEffort,
9729
+ latencyMode: input.latencyMode,
9730
+ source: input.source,
9731
+ mcpCredentialUpdates: input.mcpCredentialUpdates,
9732
+ connectionAuthorities: input.connectionAuthorities ?? [],
9733
+ personalResourceAttachment: input.personalResourceAttachment ?? null,
9734
+ ...input.commandActor.type === "service" ? {
9735
+ serviceInitiator: {
9736
+ subjectId: input.commandActor.subjectId,
9737
+ subjectLabel: input.commandActor.subjectLabel ?? null,
9738
+ context: input.commandActor.context ?? {}
9739
+ }
9740
+ } : {}
9741
+ })}`;
9742
+ }
9743
+ async function acceptSessionUserMessageWithOutcome(deps, grant, workspaceId, sessionId, input) {
9744
+ const { db, bus, workflowClient, objectStorage } = deps;
9745
+ const delegatedServiceInitiator = serviceInitiatorForGrant(grant);
9746
+ const delivery = input.delivery ?? "send";
9747
+ const source = delegatedServiceInitiator || input.origin === "operator" ? "api" : "user";
9748
+ const commandActor = delegatedServiceInitiator ? {
9749
+ type: "service",
9750
+ subjectId: delegatedServiceInitiator.initiator.subjectId,
9751
+ ...delegatedServiceInitiator.initiator.label ? { subjectLabel: delegatedServiceInitiator.initiator.label } : {},
9752
+ context: delegatedServiceInitiator.context
9753
+ } : { type: "human", subjectId: grant.subjectId };
9754
+ await requireSessionAuthorization(deps, grant, {
9124
9755
  sessionId,
9756
+ operation: delivery === "steer" ? "session.steer" : "session.append",
9757
+ surface: "core"
9758
+ });
9759
+ const requestedResources = normalizeResources(input.resources ?? []);
9760
+ const composerDraftResources = input.composerDraftResources ? normalizeResources(input.composerDraftResources) : void 0;
9761
+ const boundaryRequestHash = input.clientEventId ? sessionPromptBoundaryRequestHash({
9762
+ delivery,
9763
+ controlEtag: input.controlEtag ?? null,
9764
+ expectedDraftRevision: input.expectedDraftRevision ?? null,
9125
9765
  text: input.text,
9126
- annotations,
9766
+ annotations: input.annotations ?? [],
9127
9767
  modelContext: input.modelContext ?? null,
9128
9768
  resources: requestedResources,
9129
9769
  ...composerDraftResources ? { composerDraftResources } : {},
9130
9770
  model: input.model ?? null,
9131
9771
  reasoningEffort: input.reasoningEffort ?? null,
9132
9772
  latencyMode: input.latencyMode ?? null,
9133
- reasoningEffortFallback: sessionReasoningEffort,
9134
- turnExecutionPolicy,
9135
- mcpCredentialUpdates,
9136
- personalConnectionDelegations,
9773
+ source,
9774
+ mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
9775
+ ...input.connectionAuthorities ? { connectionAuthorities: input.connectionAuthorities } : {},
9137
9776
  ...input.personalResourceAttachment ? { personalResourceAttachment: input.personalResourceAttachment } : {},
9138
- delivery: input.delivery ?? "send",
9139
- origin: delegatedServiceInitiator ? "operator" : input.origin ?? "human",
9140
- actor: grant.subjectId,
9141
- ...grant.subjectLabel ? { actorLabel: grant.subjectLabel } : {},
9142
- ...delegatedServiceInitiator ? {
9143
- commandActor: {
9144
- type: "service",
9145
- subjectId: delegatedServiceInitiator.initiator.subjectId,
9146
- ...delegatedServiceInitiator.initiator.label ? { subjectLabel: delegatedServiceInitiator.initiator.label } : {},
9147
- context: delegatedServiceInitiator.context
9777
+ commandActor
9778
+ }) : null;
9779
+ if (input.clientEventId && boundaryRequestHash) {
9780
+ const replay = await withWorkspaceSubjectSessionActivityRls(
9781
+ db,
9782
+ workspaceId,
9783
+ grant.subjectId,
9784
+ async (scopedDb) => await replaySubmittedHumanPromptFromBoundaryReceipt(scopedDb, {
9785
+ workspaceId,
9786
+ sessionId,
9787
+ subjectId: grant.subjectId,
9788
+ actor: commandActor,
9789
+ operationKey: input.clientEventId,
9790
+ delivery,
9791
+ boundaryRequestHash,
9792
+ expectedDraftRevision: input.expectedDraftRevision ?? null
9793
+ })
9794
+ );
9795
+ if (replay) {
9796
+ return finalizePostUserMessageTurn(
9797
+ {
9798
+ db,
9799
+ bus,
9800
+ workflowClient,
9801
+ accountId: grant.accountId,
9802
+ workspaceId,
9803
+ sessionId,
9804
+ delivery,
9805
+ ...deps.schedulePromptPostCommit ? { schedulePostCommit: deps.schedulePromptPostCommit } : {}
9806
+ },
9807
+ replay
9808
+ );
9809
+ }
9810
+ }
9811
+ try {
9812
+ await requireAtomicPersonalResourceAttachment(
9813
+ deps,
9814
+ input.authorization,
9815
+ workspaceId,
9816
+ input.personalResourceAttachment,
9817
+ true
9818
+ );
9819
+ const existingSession = await requireSession2(db, workspaceId, sessionId);
9820
+ const settings = await resolveWorkspaceModelBoundarySettings(
9821
+ deps,
9822
+ grant,
9823
+ workspaceId,
9824
+ [input.model ?? existingSession.model],
9825
+ existingSession.model
9826
+ );
9827
+ if (settings !== deps.settings) {
9828
+ deps = {
9829
+ ...deps,
9830
+ catalogSourceSettings: deps.catalogSourceSettings ?? deps.settings,
9831
+ settings
9832
+ };
9833
+ }
9834
+ const requestedModel = canonicalConfiguredModel(settings, input.model ?? null) ?? null;
9835
+ const effectiveModel = canonicalConfiguredModel(settings, requestedModel ?? existingSession.model) ?? null;
9836
+ if (effectiveModel === null) {
9837
+ throw new Error("effective follow-up model unexpectedly resolved to null");
9838
+ }
9839
+ await assertWorkspaceModelPolicyAllows(db, settings, workspaceId, requestedModel);
9840
+ try {
9841
+ assertSessionAllowsProductModel(existingSession, effectiveModel);
9842
+ } catch (error) {
9843
+ if (error instanceof CodexCompactionV2ProviderLockedError) {
9844
+ throw new HTTPException11(422, { message: error.message, cause: error });
9148
9845
  }
9149
- } : {},
9150
- ...input.controlEtag !== void 0 ? { controlEtag: input.controlEtag } : {},
9151
- ...input.expectedDraftRevision !== void 0 ? { expectedDraftRevision: input.expectedDraftRevision } : {},
9152
- ...input.clientEventId ? { clientEventId: input.clientEventId } : {},
9153
- recordAgentRunUsage: true,
9154
- ...deps.schedulePromptPostCommit ? { schedulePostCommit: deps.schedulePromptPostCommit } : {}
9155
- });
9156
- return { accepted, turn, draft, receipt: receipt2, routing, interruptionCount, replay };
9846
+ throw error;
9847
+ }
9848
+ const sessionReasoningEffort = existingSession.reasoningEffort;
9849
+ const effectiveReasoningEffort = input.reasoningEffort ?? sessionReasoningEffort;
9850
+ const sessionLatencyMode = existingSession.latencyMode;
9851
+ const effectiveLatencyMode = input.latencyMode ?? sessionLatencyMode;
9852
+ const turnExecutionPolicy = resolveTurnExecutionPolicyV1(settings, {
9853
+ modelId: effectiveModel,
9854
+ requestedModelId: input.model ?? null,
9855
+ modelSource: input.model == null ? "session" : "explicit",
9856
+ reasoningEffort: effectiveReasoningEffort,
9857
+ reasoningSource: input.reasoningEffort == null ? "session" : "explicit",
9858
+ latencyMode: effectiveLatencyMode,
9859
+ latencyModeSource: input.latencyMode == null ? "session" : "explicit"
9860
+ });
9861
+ if (composerDraftResources) {
9862
+ const acceptedResources = new Set(requestedResources.map((resource) => stableJson4(resource)));
9863
+ const unacceptedDraftResource = composerDraftResources.find(
9864
+ (resource) => !acceptedResources.has(stableJson4(resource))
9865
+ );
9866
+ if (unacceptedDraftResource) {
9867
+ throw new HTTPException11(422, {
9868
+ message: "composer draft resources must be included in the accepted resource set"
9869
+ });
9870
+ }
9871
+ }
9872
+ const annotations = await validateSubmittedTimelineAnnotations(
9873
+ db,
9874
+ workspaceId,
9875
+ sessionId,
9876
+ input.annotations ?? []
9877
+ );
9878
+ await requireLimit(deps, {
9879
+ accountId: grant.accountId,
9880
+ workspaceId,
9881
+ action: "agent_run:create",
9882
+ quantity: 1,
9883
+ model: effectiveModel
9884
+ });
9885
+ if (requestedResources.some((resource) => resource.kind === "file") && !objectStorage) {
9886
+ throw new HTTPException11(503, {
9887
+ message: "object storage is not configured"
9888
+ });
9889
+ }
9890
+ await validateFileResources(
9891
+ db,
9892
+ grant.accountId,
9893
+ workspaceId,
9894
+ grant.subjectId,
9895
+ requestedResources
9896
+ );
9897
+ await validateGitHubRepositorySelection(db, workspaceId, [
9898
+ ...existingSession.resources,
9899
+ ...requestedResources
9900
+ ]);
9901
+ const mcpCredentialUpdates = validateSessionMcpCredentialUpdates({
9902
+ settings,
9903
+ grant,
9904
+ session: existingSession,
9905
+ updates: input.mcpCredentialUpdates ?? []
9906
+ });
9907
+ const connectionDelegationSource = personalConnectionDelegationSourceForGrant(grant);
9908
+ const inheritedPersonalConnectionDelegations = connectionDelegationSource.kind === "turn" ? await getSessionTurnPersonalConnectionDelegations2(
9909
+ db,
9910
+ workspaceId,
9911
+ connectionDelegationSource.sessionId,
9912
+ connectionDelegationSource.turnId
9913
+ ) : null;
9914
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
9915
+ db,
9916
+ workspaceId,
9917
+ settings,
9918
+ inheritedPersonalConnectionDelegations ? {
9919
+ personalConnectionDelegations: inheritedPersonalConnectionDelegations
9920
+ } : { subjectId: grant.subjectId }
9921
+ );
9922
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
9923
+ db,
9924
+ workspaceId,
9925
+ settings: runtimeSettings,
9926
+ tools: existingSession.tools,
9927
+ resources: [...existingSession.resources, ...requestedResources],
9928
+ source: connectionDelegationSource,
9929
+ targetSessionId: sessionId,
9930
+ googleDrivePublicationEnabled: existingSession.firstPartyMcpTools.includes("editable_artifact_export") && existingSession.firstPartyMcpTools.includes("editable_artifact_export_status") && (!existingSession.firstPartyMcpPermissions?.length || existingSession.firstPartyMcpPermissions.includes("artifacts:read") && existingSession.firstPartyMcpPermissions.includes("artifacts:publish")),
9931
+ atlassianEnabled: existingSession.firstPartyMcpTools.some((tool) => tool.startsWith("atlassian_")) && (!existingSession.firstPartyMcpPermissions?.length || existingSession.firstPartyMcpPermissions.includes("connections:read")),
9932
+ ...input.connectionAuthorities ? { authoritySelections: input.connectionAuthorities } : {}
9933
+ });
9934
+ const { accepted, turn, draft, receipt: receipt2, routing, interruptionCount, replay } = await postUserMessageTurn({
9935
+ db,
9936
+ bus,
9937
+ workflowClient,
9938
+ settings,
9939
+ accountId: grant.accountId,
9940
+ workspaceId,
9941
+ sessionId,
9942
+ text: input.text,
9943
+ annotations,
9944
+ modelContext: input.modelContext ?? null,
9945
+ resources: requestedResources,
9946
+ ...composerDraftResources ? { composerDraftResources } : {},
9947
+ model: input.model ?? null,
9948
+ reasoningEffort: input.reasoningEffort ?? null,
9949
+ latencyMode: input.latencyMode ?? null,
9950
+ reasoningEffortFallback: sessionReasoningEffort,
9951
+ turnExecutionPolicy,
9952
+ mcpCredentialUpdates,
9953
+ personalConnectionDelegations,
9954
+ ...input.personalResourceAttachment ? { personalResourceAttachment: input.personalResourceAttachment } : {},
9955
+ delivery,
9956
+ origin: source === "api" ? "operator" : "human",
9957
+ actor: grant.subjectId,
9958
+ ...grant.subjectLabel ? { actorLabel: grant.subjectLabel } : {},
9959
+ commandActor,
9960
+ ...boundaryRequestHash ? { boundaryRequestHash } : {},
9961
+ ...input.controlEtag !== void 0 ? { controlEtag: input.controlEtag } : {},
9962
+ ...input.expectedDraftRevision !== void 0 ? { expectedDraftRevision: input.expectedDraftRevision } : {},
9963
+ ...input.clientEventId ? { clientEventId: input.clientEventId } : {},
9964
+ recordAgentRunUsage: true,
9965
+ ...deps.schedulePromptPostCommit ? { schedulePostCommit: deps.schedulePromptPostCommit } : {}
9966
+ });
9967
+ return { accepted, turn, draft, receipt: receipt2, routing, interruptionCount, replay };
9968
+ } catch (error) {
9969
+ if (input.clientEventId && boundaryRequestHash) {
9970
+ const replay = await withWorkspaceSubjectSessionActivityRls(
9971
+ db,
9972
+ workspaceId,
9973
+ grant.subjectId,
9974
+ async (scopedDb) => await replaySubmittedHumanPromptFromBoundaryReceipt(scopedDb, {
9975
+ workspaceId,
9976
+ sessionId,
9977
+ subjectId: grant.subjectId,
9978
+ actor: commandActor,
9979
+ operationKey: input.clientEventId,
9980
+ delivery,
9981
+ boundaryRequestHash,
9982
+ expectedDraftRevision: input.expectedDraftRevision ?? null,
9983
+ serializeOperation: true
9984
+ })
9985
+ );
9986
+ if (replay) {
9987
+ return finalizePostUserMessageTurn(
9988
+ {
9989
+ db,
9990
+ bus,
9991
+ workflowClient,
9992
+ accountId: grant.accountId,
9993
+ workspaceId,
9994
+ sessionId,
9995
+ delivery,
9996
+ ...deps.schedulePromptPostCommit ? { schedulePostCommit: deps.schedulePromptPostCommit } : {}
9997
+ },
9998
+ replay
9999
+ );
10000
+ }
10001
+ }
10002
+ throw error;
10003
+ }
9157
10004
  }
9158
10005
  async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, input) {
9159
10006
  const { accepted, turn, receipt: receipt2, routing, interruptionCount, replay } = await acceptSessionUserMessageWithOutcome(deps, grant, workspaceId, sessionId, input);
@@ -9478,6 +10325,26 @@ function scheduledTaskToolsProvided(rawPayload) {
9478
10325
  agentConfig && typeof agentConfig === "object" && Object.prototype.hasOwnProperty.call(agentConfig, "tools")
9479
10326
  );
9480
10327
  }
10328
+ function workspaceCustomModelCommitGuard(input) {
10329
+ const reference = workspaceCustomModelReference(input.settings, input.modelId);
10330
+ if (!reference) return void 0;
10331
+ return async (tx) => {
10332
+ const active = reference.providerKind === "openrouter" ? await lockActiveWorkspaceOpenRouterCustomModelForAdmission2(tx, {
10333
+ accountId: input.accountId,
10334
+ workspaceId: input.workspaceId,
10335
+ upstreamModelId: reference.upstreamModelId
10336
+ }) : await lockActiveWorkspaceGatewayCustomModelForAdmission2(tx, {
10337
+ accountId: input.accountId,
10338
+ workspaceId: input.workspaceId,
10339
+ upstreamModelId: reference.upstreamModelId
10340
+ });
10341
+ if (!active) {
10342
+ throw new HTTPException12(422, {
10343
+ message: `model is not available: ${input.modelId}`
10344
+ });
10345
+ }
10346
+ };
10347
+ }
9481
10348
  function scheduledConnectionSurfaceEligibility(settings, target) {
9482
10349
  const tools = target?.firstPartyMcpTools ?? resolveFirstPartyMcpToolPolicy2(settings).default;
9483
10350
  const permissions = target?.firstPartyMcpPermissions?.length ? target.firstPartyMcpPermissions : DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2;
@@ -9513,6 +10380,15 @@ async function createValidatedScheduledTask(input) {
9513
10380
  rigId: input.payload.rigId,
9514
10381
  agentConfig
9515
10382
  });
10383
+ if (!knowledgeAction) {
10384
+ await validateScheduledTaskMachineTarget({
10385
+ settings: input.settings,
10386
+ db: input.db,
10387
+ grant: input.grant,
10388
+ runMode: input.payload.runMode,
10389
+ agentConfig
10390
+ });
10391
+ }
9516
10392
  if (!knowledgeAction && input.payload.variableSetId) {
9517
10393
  await validateVariableSetAttachment(
9518
10394
  { settings: input.settings, db: input.db },
@@ -9560,6 +10436,12 @@ async function createValidatedScheduledTask(input) {
9560
10436
  workspaceId: input.grant.workspaceId,
9561
10437
  subjectId: input.grant.subjectId
9562
10438
  });
10439
+ const beforeCreateCommit = !knowledgeAction && input.payload.runMode !== "existing_session" ? workspaceCustomModelCommitGuard({
10440
+ settings: input.settings,
10441
+ accountId: input.grant.accountId,
10442
+ workspaceId: input.grant.workspaceId,
10443
+ modelId: agentConfig.model ?? input.settings.openaiModel
10444
+ }) : void 0;
9563
10445
  return await withScheduledTaskAuthorityWriteErrors(
9564
10446
  () => createScheduledTask(input.db, {
9565
10447
  id,
@@ -9581,7 +10463,8 @@ async function createValidatedScheduledTask(input) {
9581
10463
  targetSessionId: target?.id ?? null,
9582
10464
  variableSetId: input.payload.variableSetId ?? null,
9583
10465
  rigId: input.payload.rigId ?? null,
9584
- metadata: input.payload.metadata
10466
+ metadata: input.payload.metadata,
10467
+ ...beforeCreateCommit ? { beforeCreateCommit } : {}
9585
10468
  })
9586
10469
  );
9587
10470
  }
@@ -9695,6 +10578,59 @@ async function validateScheduledTaskTarget(input) {
9695
10578
  }
9696
10579
  return session;
9697
10580
  }
10581
+ async function validateScheduledTaskMachineTarget(input) {
10582
+ const machineTarget = input.agentConfig.machineTarget;
10583
+ if (!machineTarget) {
10584
+ if (input.runMode !== "existing_session" && (input.agentConfig.sandboxBackend ?? input.settings.sandboxBackend) === "selfhosted") {
10585
+ throw new HTTPException12(422, {
10586
+ message: "self-hosted scheduled tasks require a Connected Machine; select a machine before saving"
10587
+ });
10588
+ }
10589
+ return null;
10590
+ }
10591
+ if (input.runMode === "existing_session") {
10592
+ throw new HTTPException12(422, {
10593
+ message: "machineTarget cannot be used with an existing-session target"
10594
+ });
10595
+ }
10596
+ if (!input.settings.sandboxOwnershipEnabled || !input.settings.sandboxSelfhostedEnabled) {
10597
+ throw new HTTPException12(422, {
10598
+ message: "Connected Machines are not enabled for scheduled tasks in this deployment"
10599
+ });
10600
+ }
10601
+ const access = {
10602
+ accountId: input.grant.accountId,
10603
+ workspaceId: input.grant.workspaceId,
10604
+ subjectId: input.grant.subjectId
10605
+ };
10606
+ const sandbox = await getSandbox4(input.db, access, machineTarget.targetSandboxId);
10607
+ if (!sandbox || sandbox.kind !== "selfhosted" || !sandbox.enrollmentId) {
10608
+ throw new HTTPException12(422, {
10609
+ message: "the selected Connected Machine is unavailable"
10610
+ });
10611
+ }
10612
+ if (sandbox.scope === "user") {
10613
+ throw new HTTPException12(422, {
10614
+ message: "personal Connected Machines cannot run unattended schedules; select a workspace or organization machine"
10615
+ });
10616
+ }
10617
+ const enrollment = input.requireOnline ? await getLiveEnrollmentConnection3(input.db, access, sandbox.enrollmentId) : await getEnrollment3(input.db, access, sandbox.enrollmentId);
10618
+ if (!enrollment || enrollment.status !== "active") {
10619
+ throw new HTTPException12(422, {
10620
+ message: input.requireOnline ? "the selected Connected Machine is offline" : "the selected Connected Machine is unavailable"
10621
+ });
10622
+ }
10623
+ if (input.requireOnline && !enrollment.workspaceRoot) {
10624
+ throw new HTTPException12(422, {
10625
+ message: "the selected Connected Machine has not reported a workspace root; reconnect it with a current agent"
10626
+ });
10627
+ }
10628
+ return {
10629
+ sandboxId: sandbox.id,
10630
+ enrollmentId: sandbox.enrollmentId,
10631
+ sandboxOs: enrollment.os
10632
+ };
10633
+ }
9698
10634
  function scheduledTaskForGrant(task, grant) {
9699
10635
  if (hasPermission(grant.permissions, "sessions:control") || task.targetSessionId === null) {
9700
10636
  return task;
@@ -9854,6 +10790,15 @@ async function validatedScheduledTaskUpdate(input) {
9854
10790
  const nextAgentConfig = update.agentConfig ?? input.existing.agentConfig;
9855
10791
  const authorityTargetChanged = nextRunMode !== input.existing.runMode || nextTargetSessionId !== input.existing.targetSessionId || input.payload.variableSetId !== void 0 && input.payload.variableSetId !== input.existing.variableSetId || input.payload.rigId !== void 0 && input.payload.rigId !== input.existing.rigId;
9856
10792
  const materialExecutionChange = authorityTargetChanged || input.payload.connectionAuthorities !== void 0 || !isDeepStrictEqual(nextAgentConfig, input.existing.agentConfig) || input.payload.action !== void 0 && !isDeepStrictEqual(input.payload.action, input.existing.action) || input.payload.schedule !== void 0 && !isDeepStrictEqual(input.payload.schedule, input.existing.schedule) || input.payload.overlapPolicy !== void 0 && input.payload.overlapPolicy !== input.existing.overlapPolicy || input.payload.metadata !== void 0 && !isDeepStrictEqual(input.payload.metadata, input.existing.metadata) || input.existing.status === "paused" && input.payload.status === "active";
10793
+ if (materialExecutionChange && nextRunMode !== "existing_session") {
10794
+ const beforeUpdateCommit = workspaceCustomModelCommitGuard({
10795
+ settings: input.settings,
10796
+ accountId: input.existing.accountId,
10797
+ workspaceId: input.existing.workspaceId,
10798
+ modelId: nextAgentConfig.model ?? input.settings.openaiModel
10799
+ });
10800
+ if (beforeUpdateCommit) update.beforeUpdateCommit = beforeUpdateCommit;
10801
+ }
9857
10802
  const existingXaiAuthority = await getScheduledTaskXaiProviderAccountAuthoritySnapshot(
9858
10803
  input.db,
9859
10804
  input.existing.workspaceId,
@@ -9966,6 +10911,13 @@ async function validatedScheduledTaskUpdate(input) {
9966
10911
  rigId: input.payload.rigId !== void 0 ? input.payload.rigId : input.existing.rigId,
9967
10912
  agentConfig: update.agentConfig ?? input.existing.agentConfig
9968
10913
  });
10914
+ await validateScheduledTaskMachineTarget({
10915
+ settings: input.settings,
10916
+ db: input.db,
10917
+ grant: input.grant,
10918
+ runMode: nextRunMode,
10919
+ agentConfig: update.agentConfig ?? input.existing.agentConfig
10920
+ });
9969
10921
  if (input.payload.targetSessionId !== void 0 || input.existing.runMode === "existing_session" || nextRunMode === "existing_session" || input.existing.runMode === "reusable_session" && nextRunMode !== "reusable_session") {
9970
10922
  update.targetSessionId = nextTargetSessionId;
9971
10923
  }
@@ -11008,6 +11960,7 @@ function denied(reason) {
11008
11960
 
11009
11961
  // src/domain/memory-slack-delivery.ts
11010
11962
  import {
11963
+ correctWorkspaceMemory,
11011
11964
  enqueueMemorySlackPublication,
11012
11965
  getCurrentMemorySlackPublicationConfiguration,
11013
11966
  getWorkspaceMemorySlackPublicationSnapshot,
@@ -11021,6 +11974,25 @@ async function saveWorkspaceMemoryWithSlackPublication(db, input, publication, e
11021
11974
  return { ...result, slackPublication };
11022
11975
  });
11023
11976
  }
11977
+ async function correctWorkspaceMemoryWithSlackPublication(db, input, publication, embedder) {
11978
+ return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {
11979
+ const result = await correctWorkspaceMemory(scopedDb, input, embedder);
11980
+ if (!publication || result.action !== "superseded" || !result.replacement) {
11981
+ return { ...result, slackPublication: { decision: null, enqueue: null } };
11982
+ }
11983
+ const replacement = await requiredSnapshot(scopedDb, input.workspaceId, result.replacement.id);
11984
+ const slackPublication = await evaluateAndEnqueue(scopedDb, {
11985
+ accountId: input.accountId,
11986
+ workspaceId: input.workspaceId,
11987
+ snapshot: replacement,
11988
+ changeKind: "corrected",
11989
+ relatedMemoryId: result.memory.id,
11990
+ occurredAt: result.replacement.updatedAt,
11991
+ publication
11992
+ });
11993
+ return { ...result, slackPublication };
11994
+ });
11995
+ }
11024
11996
  async function publishSavedMemoryMutation(db, input, result, publication) {
11025
11997
  if (result.updated || result.deduped && !result.superseded) {
11026
11998
  return { decision: null, enqueue: null };
@@ -11405,7 +12377,13 @@ import {
11405
12377
  writeCompanyBrainGovernedProposal
11406
12378
  } from "@opengeni/db";
11407
12379
  import { createHash as createHash7 } from "crypto";
11408
- var DEFAULT_AUTOMATIC_LEARNING_DESTINATIONS = ["preference"];
12380
+ var DEFAULT_AUTOMATIC_LEARNING_DESTINATIONS = ["preference", "instruction_policy"];
12381
+ function dispatchBestEffortGovernedLearningNotification(notify) {
12382
+ try {
12383
+ void notify().catch(() => void 0);
12384
+ } catch {
12385
+ }
12386
+ }
11409
12387
  function createCompanyBrainGovernedWriteRouter(options) {
11410
12388
  const authority = options.authority ?? writeCompanyBrainGovernedProposal;
11411
12389
  return {
@@ -11566,15 +12544,14 @@ function createCompanyBrainLearningPolicyRouter(options) {
11566
12544
  learningFailure: classifyLearningFailure("activation", error)
11567
12545
  });
11568
12546
  }
11569
- try {
11570
- await notifyActivation({
12547
+ dispatchBestEffortGovernedLearningNotification(
12548
+ () => notifyActivation({
11571
12549
  db: options.db,
11572
12550
  receipt: activation,
11573
12551
  sessionId: attempt.sessionId,
11574
12552
  attemptId: attempt.attemptId
11575
- });
11576
- } catch {
11577
- }
12553
+ })
12554
+ );
11578
12555
  return CompanyBrainLearningPolicyRouteReceipt.parse({
11579
12556
  operationId: request.operationId,
11580
12557
  workspaceId: attempt.workspaceId,
@@ -12020,15 +12997,14 @@ function createRememberRouter(options) {
12020
12997
  }
12021
12998
  }
12022
12999
  if (!activation) throw asRememberFailure(lastFailure);
12023
- try {
12024
- await notifyActivation({
13000
+ dispatchBestEffortGovernedLearningNotification(
13001
+ () => notifyActivation({
12025
13002
  db: options.db,
12026
13003
  receipt: activation,
12027
13004
  sessionId: attempt.sessionId,
12028
13005
  attemptId: attempt.attemptId
12029
- });
12030
- } catch {
12031
- }
13006
+ })
13007
+ );
12032
13008
  return RememberConfirmReceipt.parse({
12033
13009
  status: "activated",
12034
13010
  operationId: request.operationId,
@@ -12848,7 +13824,9 @@ function resolveMemberSubjectId(userId) {
12848
13824
  function assertWorkspaceMemberRemovable(input) {
12849
13825
  const { members, subjectId, callerSubjectId } = input;
12850
13826
  if (subjectId === callerSubjectId) {
12851
- throw new HTTPException13(409, { message: "you cannot remove your own membership" });
13827
+ throw new HTTPException13(409, {
13828
+ message: "you cannot remove your own membership"
13829
+ });
12852
13830
  }
12853
13831
  const target = members.find((member) => member.subjectId === subjectId);
12854
13832
  if (!target) {
@@ -12865,9 +13843,28 @@ function assertWorkspaceMemberRemovable(input) {
12865
13843
  }
12866
13844
  }
12867
13845
  }
13846
+ function assertWorkspaceMemberUpdateAllowed(input) {
13847
+ const { members, subjectId, callerSubjectId, nextPermissions } = input;
13848
+ if (subjectId === callerSubjectId) {
13849
+ throw new HTTPException13(409, {
13850
+ message: "you cannot change your own workspace access"
13851
+ });
13852
+ }
13853
+ const target = members.find((member) => member.subjectId === subjectId);
13854
+ if (!target) {
13855
+ throw new HTTPException13(404, { message: "member not found" });
13856
+ }
13857
+ if (memberCanAdminister(target) && !memberCanAdminister({ permissions: nextPermissions }) && !members.some((member) => member.subjectId !== subjectId && memberCanAdminister(member))) {
13858
+ throw new HTTPException13(409, {
13859
+ message: "the workspace must keep at least one administrator"
13860
+ });
13861
+ }
13862
+ }
12868
13863
  function assertWorkspaceDeletable(input) {
12869
13864
  if (input.workspaceCountForAccount <= 1) {
12870
- throw new HTTPException13(409, { message: "cannot delete the account's only workspace" });
13865
+ throw new HTTPException13(409, {
13866
+ message: "cannot delete the account's only workspace"
13867
+ });
12871
13868
  }
12872
13869
  if (input.activeSessionCount > 0) {
12873
13870
  throw new HTTPException13(409, {
@@ -13125,9 +14122,9 @@ import {
13125
14122
  } from "@opengeni/contracts";
13126
14123
  import {
13127
14124
  getNewSessionDraftInTransaction,
13128
- getEnrollment as getEnrollment3,
14125
+ getEnrollment as getEnrollment4,
13129
14126
  getRig as getRig6,
13130
- getSandbox as getSandbox4,
14127
+ getSandbox as getSandbox5,
13131
14128
  getVariableSet as getVariableSet4,
13132
14129
  NewSessionDraftAccessError,
13133
14130
  newSessionDraftToolsProvided,
@@ -13220,8 +14217,8 @@ async function hydrateNewSessionDraft(deps, grant, workspaceId, row) {
13220
14217
  if (!rig?.activeVersion) delete options.rigId;
13221
14218
  }
13222
14219
  if (options.targetSandboxId) {
13223
- const sandbox = await getSandbox4(deps.db, workspaceId, options.targetSandboxId);
13224
- const enrollment = sandbox?.enrollmentId ? await getEnrollment3(deps.db, workspaceId, sandbox.enrollmentId) : null;
14220
+ const sandbox = await getSandbox5(deps.db, workspaceId, options.targetSandboxId);
14221
+ const enrollment = sandbox?.enrollmentId ? await getEnrollment4(deps.db, workspaceId, sandbox.enrollmentId) : null;
13225
14222
  if (!sandbox || sandbox.kind !== "selfhosted" || !enrollment || enrollment.status !== "active") {
13226
14223
  delete options.targetSandboxId;
13227
14224
  delete options.workingDir;
@@ -14118,6 +15115,7 @@ async function saveHumanComposerDraft(deps, context, input) {
14118
15115
  // src/application/user-resource-grants.ts
14119
15116
  import {
14120
15117
  issueSelfUserResourceGrant,
15118
+ issueSelfLocalConnectionUseGrant,
14121
15119
  listSelfUserResourceAuthorities,
14122
15120
  revokeSelfUserResourceGrant,
14123
15121
  sessionTenancyProductActivated as sessionTenancyProductActivated3,
@@ -14144,7 +15142,11 @@ async function requireOwnerProductGate(deps, authorization, workspaceId, permiss
14144
15142
  }
14145
15143
  }
14146
15144
  function requireOwnerAuthority(authorization, workspaceId, permissions) {
14147
- requireCanonicalManagedHuman(authorization, workspaceId);
15145
+ if (!authorization.canonicalLocalHumanSession) {
15146
+ requireCanonicalManagedHuman(authorization, workspaceId);
15147
+ } else if (!authorization.contextIntegrity || authorization.authenticatedSubjectId !== authorization.grant.subjectId || authorization.grant.workspaceId !== workspaceId) {
15148
+ throw new SessionTenancyManagedHumanRequiredError();
15149
+ }
14148
15150
  for (const permission of permissions) requirePermission(authorization.grant, permission);
14149
15151
  }
14150
15152
  async function listManagedHumanUserResourceAuthorities(deps, authorization, workspaceId, input) {
@@ -14161,6 +15163,23 @@ async function listManagedHumanUserResourceAuthorities(deps, authorization, work
14161
15163
  }
14162
15164
  async function issueManagedHumanUserResourceGrant(deps, authorization, workspaceId, authorityId, request, authorizationSurface = "core") {
14163
15165
  const modePermissions = request.mode === "session" ? ["sessions:control"] : ["sessions:create"];
15166
+ if (authorization.canonicalLocalHumanSession) {
15167
+ requireOwnerAuthority(authorization, workspaceId, [
15168
+ ...ISSUE_PERMISSIONS[request.resourceKind],
15169
+ "sessions:create"
15170
+ ]);
15171
+ if (request.resourceKind !== "connection" || request.mode !== "always") {
15172
+ throw new SessionTenancyManagedHumanRequiredError();
15173
+ }
15174
+ return await issueSelfLocalConnectionUseGrant(deps.db, {
15175
+ accountId: authorization.grant.accountId,
15176
+ workspaceId,
15177
+ subjectId: authorization.grant.subjectId,
15178
+ authorityId,
15179
+ context: request.context,
15180
+ workspaceSharedAcknowledged: request.workspaceSharedAcknowledged
15181
+ });
15182
+ }
14164
15183
  await requireOwnerProductGate(deps, authorization, workspaceId, [
14165
15184
  ...ISSUE_PERMISSIONS[request.resourceKind],
14166
15185
  ...modePermissions
@@ -14280,6 +15299,7 @@ export {
14280
15299
  MEMORY_SLACK_PROJECTION_MAX_UTF8_BYTES,
14281
15300
  MEMORY_SLACK_PROJECTION_VERSION,
14282
15301
  MEMORY_SLACK_SUMMARY_MAX_UTF8_BYTES,
15302
+ MODEL_CREDENTIAL_READINESS_OBSERVATION_MAX_AGE_MS,
14283
15303
  ManagedAuthActorLeaseOutcomeUnknownError,
14284
15304
  MathEditableArtifactOutboxRandom,
14285
15305
  OPENGENI_PR_REVIEW_AGENT_INSTRUCTIONS,
@@ -14317,6 +15337,7 @@ export {
14317
15337
  acceptSessionUserMessage,
14318
15338
  acceptSessionUserMessageWithOutcome,
14319
15339
  accessGrantAuthorizationFromContext,
15340
+ accountScopedApiKeyWorkspaceAuthority,
14320
15341
  activateRigVersionForApi,
14321
15342
  apiIntegrationsMatchingDelegations,
14322
15343
  appendRigSetupCommand,
@@ -14344,6 +15365,7 @@ export {
14344
15365
  assertVideoGenerationTransition,
14345
15366
  assertWorkspaceDeletable,
14346
15367
  assertWorkspaceMemberRemovable,
15368
+ assertWorkspaceMemberUpdateAllowed,
14347
15369
  assertWorkspaceModelPolicyAllows,
14348
15370
  authorizedAtlassianConnectionsForGrant,
14349
15371
  authorizedSocialConnectionsForGrant,
@@ -14374,6 +15396,7 @@ export {
14374
15396
  controlHumanSessionWorkstreamWithOutcome,
14375
15397
  controlHumanWorkspace,
14376
15398
  conversationDeliveryNextAction,
15399
+ correctWorkspaceMemoryWithSlackPublication,
14377
15400
  createAndStartSession,
14378
15401
  createAndStartSessionWithOutcome,
14379
15402
  createCatalogItem,
@@ -14405,6 +15428,7 @@ export {
14405
15428
  directRetainedProcessMatchesBackend,
14406
15429
  disableCapability,
14407
15430
  discoverMcpRegistryCapabilities,
15431
+ dispatchBestEffortGovernedLearningNotification,
14408
15432
  editHumanQueuePrompt,
14409
15433
  editableArtifactActorKey,
14410
15434
  editableArtifactAuthorizationRevisionPortFromPostgres,
@@ -14442,6 +15466,7 @@ export {
14442
15466
  fikenConnectionMetadata,
14443
15467
  filenameForMimeType,
14444
15468
  forkManagedHumanSession,
15469
+ freezeAgentChildAutomaticTitleInCreatorContext,
14445
15470
  freezePersonalConnectionDelegations,
14446
15471
  getActorNewSessionDraft,
14447
15472
  getAutomationAdapter,
@@ -14465,6 +15490,7 @@ export {
14465
15490
  hasReservedOpenGeniSlackBotSessionMetadata,
14466
15491
  hashEditableArtifactCreateRequest,
14467
15492
  hashEditableArtifactImportRequest,
15493
+ initialAutomaticTitleForSessionStart,
14468
15494
  inlinePackSkillInstall,
14469
15495
  insightsSessionLabel,
14470
15496
  inspectEditableArtifactLiveWireEnvelope,
@@ -14476,6 +15502,9 @@ export {
14476
15502
  isTerminalVideoGenerationState,
14477
15503
  isTrustedScheduledSlackBotSession,
14478
15504
  isUserMember,
15505
+ isWorkspaceCustomModelId,
15506
+ isWorkspaceGatewayCustomModelId,
15507
+ isWorkspaceOpenRouterCustomModelId,
14479
15508
  issueManagedHumanUserResourceGrant,
14480
15509
  legacySandboxRuntimeFromPacks,
14481
15510
  listCapabilityPacks,
@@ -14486,6 +15515,8 @@ export {
14486
15515
  listRigVersionsForApi,
14487
15516
  listWorkspaceCapabilityPacks,
14488
15517
  loadRigDefaultVariableSetEnvironment,
15518
+ managedSessionGroupBackend,
15519
+ managedSessionGroupOs,
14489
15520
  manualScheduledTaskTriggerUsageKey,
14490
15521
  manualScheduledTaskTriggerWorkflowId,
14491
15522
  markManagedAuthRequestActorTransitionApplied,
@@ -14494,6 +15525,7 @@ export {
14494
15525
  mergeResourceRefs,
14495
15526
  mergeRigDefaultVariableSetEnvironment,
14496
15527
  mergeToolRefs,
15528
+ modelFundingForAdmission,
14497
15529
  moveHumanQueuePrompt,
14498
15530
  nativeConnectionCapabilityRecommendations,
14499
15531
  normalizeConversationActor,
@@ -14557,6 +15589,7 @@ export {
14557
15589
  requireAccessGrantAuthorization,
14558
15590
  requireAccountAdminAuthorizationStamp,
14559
15591
  requireAutomationAdapter,
15592
+ requireCanonicalLocalAccountAdministrator,
14560
15593
  requireCanonicalManagedHuman,
14561
15594
  requireEnvironmentEncryption,
14562
15595
  requireFreshAccessGrant,
@@ -14575,6 +15608,7 @@ export {
14575
15608
  requireVariableSetEncryption,
14576
15609
  requireVariableSetForApi,
14577
15610
  resolveCapabilityPack,
15611
+ resolveCatalogSettings,
14578
15612
  resolveChildGoalFromAcceptedSnapshot,
14579
15613
  resolveCodexAppsCredentialIdForRun,
14580
15614
  resolveFikenDefaultCompanySlug,
@@ -14587,8 +15621,11 @@ export {
14587
15621
  resolveSessionSandboxRuntime,
14588
15622
  resolveSessionToolPolicy,
14589
15623
  resolveSkillImport,
15624
+ resolveWorkspaceCatalogSettings,
14590
15625
  resolveWorkspaceLegacyRuntimePacks,
15626
+ resolveWorkspaceModelSelection,
14591
15627
  restoreScheduledTask,
15628
+ retainedProcessBackgroundSettlement,
14592
15629
  revokeManagedHumanUserResourceGrant,
14593
15630
  rigActorForGrant,
14594
15631
  rigProviderImageBuildRequestId,
@@ -14653,6 +15690,7 @@ export {
14653
15690
  validateManagedAuthRequestActorLease,
14654
15691
  validateMcpCapabilityConnection,
14655
15692
  validateOpenGeniSlackBotConnectionSelection,
15693
+ validateScheduledTaskMachineTarget,
14656
15694
  validateScheduledTaskTarget,
14657
15695
  validateToolRefs,
14658
15696
  validateToolRefsForSessionPolicy,
@@ -14672,6 +15710,7 @@ export {
14672
15710
  withScheduledTaskAuthorityWriteErrors,
14673
15711
  withWorkspaceDefaultMcpTools,
14674
15712
  workflowIdForSession,
15713
+ workspaceCustomModelReference,
14675
15714
  workspaceSessionToolPolicyDefaultServerIds,
14676
15715
  workspaceSessionToolPolicyServerIds,
14677
15716
  wrapChannelABoxWithRouting