@opengeni/db 0.3.0 → 0.4.1

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.
@@ -2,7 +2,7 @@ import { SessionEventType, Permission, CapabilityKind, CapabilitySource, Schedul
2
2
  import { environmentsEncryptionKeyBytes, Settings } from '@opengeni/config';
3
3
  import { refreshCodexToken, CodexTokenSnapshot, CodexUsagePayload } from '@opengeni/codex';
4
4
  import { PgDatabase } from 'drizzle-orm/pg-core';
5
- import { s as schema, e as enrollmentOsValues, a as enrollmentExposureValues, d as deviceEnrollmentStatusValues, b as enrollmentStatusValues, c as sandboxKindValues, f as sessionRecordingCodecValues, g as sessionRecordingModeValues, h as sessionRecordingStateValues } from './schema-BI0iqN9U.js';
5
+ import { s as schema, e as enrollmentOsValues, a as enrollmentExposureValues, d as deviceEnrollmentStatusValues, b as enrollmentStatusValues, c as sandboxKindValues, f as sessionRecordingCodecValues, g as sessionRecordingModeValues, h as sessionRecordingStateValues } from './schema-C7Wvjwge.js';
6
6
  import 'drizzle-orm';
7
7
  import './migrate.js';
8
8
 
@@ -998,6 +998,7 @@ declare function createSession(db: Database, input: {
998
998
  sandboxBackend: SandboxBackend;
999
999
  environmentId?: string | null;
1000
1000
  firstPartyMcpPermissions?: Permission[] | null;
1001
+ instructions?: string | null;
1001
1002
  parentSessionId?: string | null;
1002
1003
  createIdempotencyKey?: string | null;
1003
1004
  sandboxGroupId?: string | null;
@@ -1025,6 +1026,7 @@ declare function createSessionWithIdempotencyKey(db: Database, input: {
1025
1026
  sandboxBackend: SandboxBackend;
1026
1027
  environmentId?: string | null;
1027
1028
  firstPartyMcpPermissions?: Permission[] | null;
1029
+ instructions?: string | null;
1028
1030
  parentSessionId?: string | null;
1029
1031
  createIdempotencyKey: string;
1030
1032
  sandboxGroupId?: string | null;
@@ -1432,6 +1434,13 @@ interface LeaseSnapshot {
1432
1434
  resumeState: Record<string, unknown> | null;
1433
1435
  expiresAt: Date;
1434
1436
  }
1437
+ interface LiveModalSandboxLeaseAttribution {
1438
+ leaseId: string;
1439
+ workspaceId: string;
1440
+ sandboxGroupId: string;
1441
+ instanceId: string | null;
1442
+ liveness: SandboxLeaseLiveness;
1443
+ }
1435
1444
  interface AcquireLeaseInput {
1436
1445
  accountId: string;
1437
1446
  workspaceId: string;
@@ -1484,6 +1493,19 @@ declare function commitWarmingToWarm(db: Database, input: {
1484
1493
  committed: boolean;
1485
1494
  lease: LeaseSnapshot | null;
1486
1495
  }>;
1496
+ declare function recordWarmingSandboxCreated(db: Database, input: {
1497
+ accountId: string;
1498
+ workspaceId: string;
1499
+ sandboxGroupId: string;
1500
+ expectedEpoch: number;
1501
+ instanceId: string;
1502
+ resumeBackendId?: string | null;
1503
+ resumeState?: Record<string, unknown> | null;
1504
+ leaseTtlMs: number;
1505
+ }): Promise<{
1506
+ recorded: boolean;
1507
+ lease: LeaseSnapshot | null;
1508
+ }>;
1487
1509
  declare function failWarmingToCold(db: Database, input: {
1488
1510
  accountId: string;
1489
1511
  workspaceId: string;
@@ -1537,6 +1559,9 @@ interface MeterableWarmLease {
1537
1559
  backend: string;
1538
1560
  }
1539
1561
  declare function listMeterableWarmLeases(db: Database): Promise<MeterableWarmLease[]>;
1562
+ declare function countQueuedTurns(db: Database): Promise<number>;
1563
+ declare function countSandboxLeasesByLiveness(db: Database): Promise<Record<SandboxLeaseLiveness, number>>;
1564
+ declare function listLiveModalSandboxLeaseAttributions(db: Database): Promise<LiveModalSandboxLeaseAttribution[]>;
1540
1565
  declare function reArmDrainingLease(db: Database, input: {
1541
1566
  accountId: string;
1542
1567
  workspaceId: string;
@@ -2119,4 +2144,4 @@ type LockedSessionUpdateResult = {
2119
2144
  declare function appendSessionEventsWithLockedSessionUpdate(db: Database, workspaceId: string, sessionId: string, build: (session: Session, context: LockedSessionUpdateContext) => LockedSessionUpdateResult | Promise<LockedSessionUpdateResult>): Promise<SessionEvent[]>;
2120
2145
  declare function sessionSubject(workspaceId: string, sessionId: string): string;
2121
2146
 
2122
- export { type SandboxPtySessionRow as $, type AccrueWarmSecondsResult as A, type BootstrapWorkspaceInput as B, CLEARED_RUN_STATE as C, type Database as D, type EnableCapabilityInstallationInput as E, type EnrollmentExposure as F, type EnrollmentOs as G, type EnrollmentRecord as H, type EnrollmentStatus as I, type ForceDrainResult as J, type GitHubInstallation as K, type GoalContinuationDecision as L, type LeaseHolderKind as M, type LeaseSnapshot as N, type ListSessionEventsOptions as O, MACHINE_METRICS_SERIES_INTERVAL_MS as P, type ProvisionResult, type ProvisionRolesOptions, type MachineMetricsRow as Q, type MachineMetricsSample as R, type MeterableWarmLease as S, type ReapDrainable as T, type RegisterWorkspacePackInput as U, type RlsContext as V, type RlsStrategy as W, SandboxImageConflictError as X, type SandboxKind as Y, type SandboxLeaseLiveness as Z, SandboxLeaseSupersededError as _, type AcquireLeaseInput as a, createSocialConnection as a$, type SandboxRecord as a0, type SessionCodexState as a1, type SessionMcpServerForRun as a2, type SessionRecordingCodec as a3, type SessionRecordingMode as a4, type SessionRecordingRow as a5, type SessionRecordingState as a6, type StreamAcknowledgment as a7, type UpdateQueuedSessionTurnInput as a8, type UpdateScheduledTaskInput as a9, completeFileUpload as aA, confirmDrainCold as aB, consumeDeviceEnrollmentRequest as aC, consumeSessionCompactionRequest as aD, countActiveApiKeysForWorkspace as aE, countActiveSessionHistoryItems as aF, countActiveSessionsForWorkspace as aG, countActiveSessionsUsingEnvironment as aH, countConsecutiveReactiveRotations as aI, countScheduledTasksForWorkspace as aJ, countScheduledTasksUsingEnvironment as aK, countSessionHistoryItems as aL, countTurnSessionHistoryItems as aM, countWorkspaceEnvironments as aN, countWorkspacesForAccount as aO, createApiKey as aP, createDb as aQ, createDeviceEnrollmentRequest as aR, createEnrollment as aS, createFileUpload as aT, createSandbox as aU, createScheduledTask as aV, createScheduledTaskRun as aW, createSession as aX, createSessionGoal as aY, createSessionMcpServers as aZ, createSessionWithIdempotencyKey as a_, type UpdateSessionMcpServerCredentialsInput as aa, type UpdateSessionMcpServerCredentialsResult as ab, type UserLookup as ac, type WakeParentForChildCompletionInput as ad, type WakeParentForChildCompletionResult as ae, type WorkspaceEnvironmentForRun as af, accrueWarmSeconds as ag, acquireLease as ah, allAccountPermissions as ai, allWorkspacePermissions as aj, appendSessionEvents as ak, appendSessionEventsAndUpdateSession as al, appendSessionEventsWithLockedSessionUpdate as am, appendSessionHistoryItems as an, applyContextCompaction as ao, applyCreditDebitUpToBalance as ap, applyCreditLedgerEntry as aq, approveDeviceEnrollmentRequest as ar, bootstrapWorkspace as as, buildCodexTokenResolver as at, cancelQueuedSessionTurn as au, claimNextQueuedTurn as av, clearSessionContext as aw, clearedContextMarkerItem as ax, closePtySession as ay, commitWarmingToWarm as az, type AcquireLeaseResult as b, getWorkspaceEnvironment as b$, createSocialPost as b0, createTurn as b1, createWorkspace as b2, createWorkspaceEnvironment as b3, decryptEnvironmentValue as b4, decryptedCapabilityHeaders as b5, deleteRecording as b6, deleteScheduledTask as b7, deleteWorkspace as b8, deleteWorkspaceEnvironment as b9, getCodexRotationSettings as bA, getDeviceEnrollmentRequestByDeviceCode as bB, getEnrollment as bC, getFile as bD, getFileUpload as bE, getLatestRunState as bF, getManagedAccount as bG, getManagedUserByEmail as bH, getOpenPtySession as bI, getPackInstallation as bJ, getPendingDeviceEnrollmentRequestByUserCode as bK, getPendingDeviceEnrollmentRequestByUserCodeGlobal as bL, getRecording as bM, getSandbox as bN, getSandboxSessionEnvelope as bO, getScheduledTask as bP, getSession as bQ, getSessionByCreateIdempotencyKey as bR, getSessionCodexState as bS, getSessionEvent as bT, getSessionGoal as bU, getSessionHistoryItems as bV, getSessionTurn as bW, getSocialConnection as bX, getStoredCapabilityHeaderCiphertext as bY, getStreamAcknowledgment as bZ, getWorkspace as b_, deleteWorkspaceEnvironmentVariable as ba, deleteWorkspacePack as bb, denyDeviceEnrollmentRequest as bc, disableCapabilityInstallation as bd, disconnectAllCodexAccounts as be, disconnectCodexAccount as bf, enableCapabilityInstallation as bg, enablePackInstallation as bh, encryptEnvironmentValue as bi, enqueueSessionTurn as bj, ensureCodexRotationSettings as bk, ensureManagedAccessForUser as bl, evaluateGoalContinuation as bm, failWarmingToCold as bn, fetchCodexUsageForAccount as bo, finalizeEnrollmentByToken as bp, findActiveApiKeyByHash as bq, finishTurn as br, forceDrainOverLimitViewerOnlyBoxes as bs, getActiveSessionHistoryItems as bt, getAnySessionInGroup as bu, getBillingBalance as bv, getBillingCustomer as bw, getCapabilityCatalogItem as bx, getCapabilityInstallation as by, getCodexCredentialStatus as bz, type ActiveSandboxPointer as c, recordLeaseDataPlaneUrl as c$, getWorkspaceEnvironmentByName as c0, getWorkspaceEnvironmentValuesForRun as c1, getWorkspaceGrant as c2, getWorkspacePack as c3, grantWorkspaceAccess as c4, hasCreditLedgerEntry as c5, heartbeatLeaseHolder as c6, incrementTurnWorkerDeathRedispatches as c7, ingestMachineMetricsSample as c8, insertMachineMetricsSeries as c9, listSocialConnections as cA, listSocialPosts as cB, listUsageEvents as cC, listWorkspaceEnvironments as cD, listWorkspaceMembers as cE, listWorkspacePacks as cF, listWorkspacesForSubject as cG, loadCodexCredentialForRun as cH, loadWorkspaceEnvironmentForRun as cI, markFileUploadFailed as cJ, markStripeWebhookProcessed as cK, mcpServerIdForCapability as cL, nextSessionHistoryPosition as cM, orphanedResultRowIndicesForRepair as cN, persistDrainSnapshot as cO, reArmDrainingLease as cP, readActiveSandbox as cQ, readLease as cR, readMachineMetricsLatest as cS, readMachineMetricsLatestForWorkspace as cT, readMachineMetricsSeries as cU, reapStaleLeaseHolders as cV, reapStaleLeaseHoldersGlobal as cW, recordAuditEvent as cX, recordCodexAccountConnectors as cY, recordCodexAccountUsage as cZ, recordCodexTokenRefresh as c_, insertPtySession as ca, insertRecording as cb, isCodexBilledTurn as cc, isStripeWebhookProcessed as cd, listApiKeys as ce, listCapabilityCatalogItems as cf, listCapabilityInstallations as cg, listCodexAccountStatuses as ch, listDistinctEnvironmentIdsInGroup as ci, listEnabledMcpCapabilityServers as cj, listEnrollments as ck, listGitHubInstallationIdsForWorkspace as cl, listGitHubInstallationsForWorkspace as cm, listMeterableWarmLeases as cn, listOpenPtySessions as co, listPackInstallations as cp, listRecordings as cq, listSandboxes as cr, listScheduledTaskRuns as cs, listScheduledTasks as ct, listSessionEvents as cu, listSessionIdsInGroup as cv, listSessionMcpServerMetadata as cw, listSessionMcpServersForRun as cx, listSessionTurns as cy, listSessions as cz, type AppendEventInput as d, withAccountRls as d$, recordLeaseTerminalDataPlaneUrl as d0, recordSessionActiveCodexCredential as d1, recordStreamAcknowledgment as d2, recordStripeWebhookEvent as d3, recordUsageEvent as d4, registerDbBinding as d5, registerWorkspacePack as d6, releaseLeaseHolder as d7, removeWorkspaceMember as d8, renameCodexAccount as d9, setSessionGoalStatus as dA, setSessionLastInputTokens as dB, setSessionStatus as dC, setTemporalWorkflowId as dD, setWorkspaceEnvironmentVariable as dE, sumUsageQuantity as dF, touchEnrollmentLastSeen as dG, updateCodexRotationSettings as dH, updatePackInstallationStatus as dI, updatePtySessionActivity as dJ, updateQueuedSessionTurn as dK, updateRecording as dL, updateScheduledTask as dM, updateScheduledTaskRun as dN, updateSessionGoal as dO, updateSessionMcpServerCredentials as dP, updateSessionTitle as dQ, updateWorkspace as dR, updateWorkspaceEnvironment as dS, upsertBillingCustomer as dT, upsertCapabilityCatalogItem as dU, upsertCodexSubscriptionCredential as dV, upsertGitHubInstallation as dW, upsertMachineMetricsLatest as dX, upsertSandboxSessionEnvelope as dY, upsertSessionGoal as dZ, wakeParentSessionForChildCompletion as d_, reorderQueuedSessionTurns as da, requestSessionCompaction as db, requeuePreemptedTurn as dc, requireFile as dd, requireScheduledTask as de, requireSession as df, requireSocialConnection as dg, requireWorkspace as dh, revokeApiKey as di, revokeEnrollment as dj, revokeViewer as dk, rlsContextForWorkspace as dl, rlsStrategyFor as dm, sanitizeEventPayload as dn, sanitizeEventString as dp, saveRunState as dq, sessionSubject as dr, setActiveCodexCredential as ds, setActiveSandbox as dt, setCodexCredentialExhausted as du, setCodexCredentialStatus as dv, setEnrollmentHasDisplay as dw, setRlsContext as dx, setSessionCodexPin as dy, setSessionGoalLastContinuationTurn as dz, CODEX_ROTATION_STRATEGIES as e, withRlsContext as e0, withWorkspaceRls as e1, withWorkspaceUsageLock as e2, workspaceCodexSubscriptionActive as e3, type ClearSessionContextResult as f, type CodexAccountStatus as g, type CodexAccountUsageSnapshot as h, type CodexAuthDeps as i, type CodexCredentialForRun as j, type CodexCredentialTokens as k, type CodexRotationSettings as l, type CodexRotationStrategy as m, type CreateCapabilityCatalogItemInput as n, type CreateDbOptions as o, type CreatePackInstallationInput as p, provisionRoles, type CreateScheduledTaskInput as q, type CreateSessionGoalInput as r, type CreateSessionMcpServerInput as s, type CreateSocialConnectionInput as t, type CreateSocialPostInput as u, type DbClient as v, type DeviceEnrollmentRequestRecord as w, type DeviceEnrollmentStatus as x, type EnabledMcpCapabilityServer as y, type EnqueueSessionTurnInput as z };
2147
+ export { SandboxLeaseSupersededError as $, type AccrueWarmSecondsResult as A, type BootstrapWorkspaceInput as B, CLEARED_RUN_STATE as C, type Database as D, type EnableCapabilityInstallationInput as E, type EnrollmentExposure as F, type EnrollmentOs as G, type EnrollmentRecord as H, type EnrollmentStatus as I, type ForceDrainResult as J, type GitHubInstallation as K, type GoalContinuationDecision as L, type LeaseHolderKind as M, type LeaseSnapshot as N, type ListSessionEventsOptions as O, type LiveModalSandboxLeaseAttribution as P, type ProvisionResult, type ProvisionRolesOptions, MACHINE_METRICS_SERIES_INTERVAL_MS as Q, type MachineMetricsRow as R, type MachineMetricsSample as S, type MeterableWarmLease as T, type ReapDrainable as U, type RegisterWorkspacePackInput as V, type RlsContext as W, type RlsStrategy as X, SandboxImageConflictError as Y, type SandboxKind as Z, type SandboxLeaseLiveness as _, type AcquireLeaseInput as a, createSessionGoal as a$, type SandboxPtySessionRow as a0, type SandboxRecord as a1, type SessionCodexState as a2, type SessionMcpServerForRun as a3, type SessionRecordingCodec as a4, type SessionRecordingMode as a5, type SessionRecordingRow as a6, type SessionRecordingState as a7, type StreamAcknowledgment as a8, type UpdateQueuedSessionTurnInput as a9, commitWarmingToWarm as aA, completeFileUpload as aB, confirmDrainCold as aC, consumeDeviceEnrollmentRequest as aD, consumeSessionCompactionRequest as aE, countActiveApiKeysForWorkspace as aF, countActiveSessionHistoryItems as aG, countActiveSessionsForWorkspace as aH, countActiveSessionsUsingEnvironment as aI, countConsecutiveReactiveRotations as aJ, countQueuedTurns as aK, countSandboxLeasesByLiveness as aL, countScheduledTasksForWorkspace as aM, countScheduledTasksUsingEnvironment as aN, countSessionHistoryItems as aO, countTurnSessionHistoryItems as aP, countWorkspaceEnvironments as aQ, countWorkspacesForAccount as aR, createApiKey as aS, createDb as aT, createDeviceEnrollmentRequest as aU, createEnrollment as aV, createFileUpload as aW, createSandbox as aX, createScheduledTask as aY, createScheduledTaskRun as aZ, createSession as a_, type UpdateScheduledTaskInput as aa, type UpdateSessionMcpServerCredentialsInput as ab, type UpdateSessionMcpServerCredentialsResult as ac, type UserLookup as ad, type WakeParentForChildCompletionInput as ae, type WakeParentForChildCompletionResult as af, type WorkspaceEnvironmentForRun as ag, accrueWarmSeconds as ah, acquireLease as ai, allAccountPermissions as aj, allWorkspacePermissions as ak, appendSessionEvents as al, appendSessionEventsAndUpdateSession as am, appendSessionEventsWithLockedSessionUpdate as an, appendSessionHistoryItems as ao, applyContextCompaction as ap, applyCreditDebitUpToBalance as aq, applyCreditLedgerEntry as ar, approveDeviceEnrollmentRequest as as, bootstrapWorkspace as at, buildCodexTokenResolver as au, cancelQueuedSessionTurn as av, claimNextQueuedTurn as aw, clearSessionContext as ax, clearedContextMarkerItem as ay, closePtySession as az, type AcquireLeaseResult as b, getStoredCapabilityHeaderCiphertext as b$, createSessionMcpServers as b0, createSessionWithIdempotencyKey as b1, createSocialConnection as b2, createSocialPost as b3, createTurn as b4, createWorkspace as b5, createWorkspaceEnvironment as b6, decryptEnvironmentValue as b7, decryptedCapabilityHeaders as b8, deleteRecording as b9, getCapabilityCatalogItem as bA, getCapabilityInstallation as bB, getCodexCredentialStatus as bC, getCodexRotationSettings as bD, getDeviceEnrollmentRequestByDeviceCode as bE, getEnrollment as bF, getFile as bG, getFileUpload as bH, getLatestRunState as bI, getManagedAccount as bJ, getManagedUserByEmail as bK, getOpenPtySession as bL, getPackInstallation as bM, getPendingDeviceEnrollmentRequestByUserCode as bN, getPendingDeviceEnrollmentRequestByUserCodeGlobal as bO, getRecording as bP, getSandbox as bQ, getSandboxSessionEnvelope as bR, getScheduledTask as bS, getSession as bT, getSessionByCreateIdempotencyKey as bU, getSessionCodexState as bV, getSessionEvent as bW, getSessionGoal as bX, getSessionHistoryItems as bY, getSessionTurn as bZ, getSocialConnection as b_, deleteScheduledTask as ba, deleteWorkspace as bb, deleteWorkspaceEnvironment as bc, deleteWorkspaceEnvironmentVariable as bd, deleteWorkspacePack as be, denyDeviceEnrollmentRequest as bf, disableCapabilityInstallation as bg, disconnectAllCodexAccounts as bh, disconnectCodexAccount as bi, enableCapabilityInstallation as bj, enablePackInstallation as bk, encryptEnvironmentValue as bl, enqueueSessionTurn as bm, ensureCodexRotationSettings as bn, ensureManagedAccessForUser as bo, evaluateGoalContinuation as bp, failWarmingToCold as bq, fetchCodexUsageForAccount as br, finalizeEnrollmentByToken as bs, findActiveApiKeyByHash as bt, finishTurn as bu, forceDrainOverLimitViewerOnlyBoxes as bv, getActiveSessionHistoryItems as bw, getAnySessionInGroup as bx, getBillingBalance as by, getBillingCustomer as bz, type ActiveSandboxPointer as c, recordAuditEvent as c$, getStreamAcknowledgment as c0, getWorkspace as c1, getWorkspaceEnvironment as c2, getWorkspaceEnvironmentByName as c3, getWorkspaceEnvironmentValuesForRun as c4, getWorkspaceGrant as c5, getWorkspacePack as c6, grantWorkspaceAccess as c7, hasCreditLedgerEntry as c8, heartbeatLeaseHolder as c9, listSessionMcpServerMetadata as cA, listSessionMcpServersForRun as cB, listSessionTurns as cC, listSessions as cD, listSocialConnections as cE, listSocialPosts as cF, listUsageEvents as cG, listWorkspaceEnvironments as cH, listWorkspaceMembers as cI, listWorkspacePacks as cJ, listWorkspacesForSubject as cK, loadCodexCredentialForRun as cL, loadWorkspaceEnvironmentForRun as cM, markFileUploadFailed as cN, markStripeWebhookProcessed as cO, mcpServerIdForCapability as cP, nextSessionHistoryPosition as cQ, orphanedResultRowIndicesForRepair as cR, persistDrainSnapshot as cS, reArmDrainingLease as cT, readActiveSandbox as cU, readLease as cV, readMachineMetricsLatest as cW, readMachineMetricsLatestForWorkspace as cX, readMachineMetricsSeries as cY, reapStaleLeaseHolders as cZ, reapStaleLeaseHoldersGlobal as c_, incrementTurnWorkerDeathRedispatches as ca, ingestMachineMetricsSample as cb, insertMachineMetricsSeries as cc, insertPtySession as cd, insertRecording as ce, isCodexBilledTurn as cf, isStripeWebhookProcessed as cg, listApiKeys as ch, listCapabilityCatalogItems as ci, listCapabilityInstallations as cj, listCodexAccountStatuses as ck, listDistinctEnvironmentIdsInGroup as cl, listEnabledMcpCapabilityServers as cm, listEnrollments as cn, listGitHubInstallationIdsForWorkspace as co, listGitHubInstallationsForWorkspace as cp, listLiveModalSandboxLeaseAttributions as cq, listMeterableWarmLeases as cr, listOpenPtySessions as cs, listPackInstallations as ct, listRecordings as cu, listSandboxes as cv, listScheduledTaskRuns as cw, listScheduledTasks as cx, listSessionEvents as cy, listSessionIdsInGroup as cz, type AppendEventInput as d, upsertGitHubInstallation as d$, recordCodexAccountConnectors as d0, recordCodexAccountUsage as d1, recordCodexTokenRefresh as d2, recordLeaseDataPlaneUrl as d3, recordLeaseTerminalDataPlaneUrl as d4, recordSessionActiveCodexCredential as d5, recordStreamAcknowledgment as d6, recordStripeWebhookEvent as d7, recordUsageEvent as d8, recordWarmingSandboxCreated as d9, setCodexCredentialStatus as dA, setEnrollmentHasDisplay as dB, setRlsContext as dC, setSessionCodexPin as dD, setSessionGoalLastContinuationTurn as dE, setSessionGoalStatus as dF, setSessionLastInputTokens as dG, setSessionStatus as dH, setTemporalWorkflowId as dI, setWorkspaceEnvironmentVariable as dJ, sumUsageQuantity as dK, touchEnrollmentLastSeen as dL, updateCodexRotationSettings as dM, updatePackInstallationStatus as dN, updatePtySessionActivity as dO, updateQueuedSessionTurn as dP, updateRecording as dQ, updateScheduledTask as dR, updateScheduledTaskRun as dS, updateSessionGoal as dT, updateSessionMcpServerCredentials as dU, updateSessionTitle as dV, updateWorkspace as dW, updateWorkspaceEnvironment as dX, upsertBillingCustomer as dY, upsertCapabilityCatalogItem as dZ, upsertCodexSubscriptionCredential as d_, registerDbBinding as da, registerWorkspacePack as db, releaseLeaseHolder as dc, removeWorkspaceMember as dd, renameCodexAccount as de, reorderQueuedSessionTurns as df, requestSessionCompaction as dg, requeuePreemptedTurn as dh, requireFile as di, requireScheduledTask as dj, requireSession as dk, requireSocialConnection as dl, requireWorkspace as dm, revokeApiKey as dn, revokeEnrollment as dp, revokeViewer as dq, rlsContextForWorkspace as dr, rlsStrategyFor as ds, sanitizeEventPayload as dt, sanitizeEventString as du, saveRunState as dv, sessionSubject as dw, setActiveCodexCredential as dx, setActiveSandbox as dy, setCodexCredentialExhausted as dz, CODEX_ROTATION_STRATEGIES as e, upsertMachineMetricsLatest as e0, upsertSandboxSessionEnvelope as e1, upsertSessionGoal as e2, wakeParentSessionForChildCompletion as e3, withAccountRls as e4, withRlsContext as e5, withWorkspaceRls as e6, withWorkspaceUsageLock as e7, workspaceCodexSubscriptionActive as e8, type ClearSessionContextResult as f, type CodexAccountStatus as g, type CodexAccountUsageSnapshot as h, type CodexAuthDeps as i, type CodexCredentialForRun as j, type CodexCredentialTokens as k, type CodexRotationSettings as l, type CodexRotationStrategy as m, type CreateCapabilityCatalogItemInput as n, type CreateDbOptions as o, type CreatePackInstallationInput as p, provisionRoles, type CreateScheduledTaskInput as q, type CreateSessionGoalInput as r, type CreateSessionMcpServerInput as s, type CreateSocialConnectionInput as t, type CreateSocialPostInput as u, type DbClient as v, type DeviceEnrollmentRequestRecord as w, type DeviceEnrollmentStatus as x, type EnabledMcpCapabilityServer as y, type EnqueueSessionTurnInput as z };
@@ -1655,6 +1655,23 @@ declare const sessions: drizzle_orm_pg_core.PgTableWithColumns<{
1655
1655
  identity: undefined;
1656
1656
  generated: undefined;
1657
1657
  }, {}, {}>;
1658
+ instructions: drizzle_orm_pg_core.PgColumn<{
1659
+ name: "instructions";
1660
+ tableName: "sessions";
1661
+ dataType: "string";
1662
+ columnType: "PgText";
1663
+ data: string;
1664
+ driverParam: string;
1665
+ notNull: false;
1666
+ hasDefault: false;
1667
+ isPrimaryKey: false;
1668
+ isAutoincrement: false;
1669
+ hasRuntimeDefault: false;
1670
+ enumValues: [string, ...string[]];
1671
+ baseColumn: never;
1672
+ identity: undefined;
1673
+ generated: undefined;
1674
+ }, {}, {}>;
1658
1675
  resources: drizzle_orm_pg_core.PgColumn<{
1659
1676
  name: "resources";
1660
1677
  tableName: "sessions";
@@ -5322,7 +5339,7 @@ declare const sessionRecordings: drizzle_orm_pg_core.PgTableWithColumns<{
5322
5339
  tableName: "session_recordings";
5323
5340
  dataType: "string";
5324
5341
  columnType: "PgText";
5325
- data: "failed" | "available" | "recording" | "finalizing";
5342
+ data: "recording" | "finalizing" | "available" | "failed";
5326
5343
  driverParam: string;
5327
5344
  notNull: true;
5328
5345
  hasDefault: false;
package/dist/schema.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import 'drizzle-orm';
2
2
  import 'drizzle-orm/pg-core';
3
- export { i as agentRunStates, j as apiKeys, k as auditEvents, l as billingCustomers, m as capabilityCatalogItems, n as capabilityInstallations, o as codexRotationSettings, p as codexSubscriptionCredentials, q as creditLedgerEntries, r as deviceEnrollmentRequests, d as deviceEnrollmentStatusValues, t as documentBases, u as documentChunks, v as documents, a as enrollmentExposureValues, e as enrollmentOsValues, b as enrollmentStatusValues, w as enrollments, x as fileUploads, y as files, z as githubInstallations, A as machineMetricsLatest, B as machineMetricsSeries, C as managedAccounts, D as packInstallations, c as sandboxKindValues, E as sandboxLeaseHolders, F as sandboxLeaseLivenessValues, G as sandboxLeases, H as sandboxPtySessions, I as sandboxSessionEnvelopes, J as sandboxes, K as scheduledTaskRuns, L as scheduledTasks, M as sessionEvents, N as sessionGoals, O as sessionHistoryItems, P as sessionMcpServers, f as sessionRecordingCodecValues, g as sessionRecordingModeValues, h as sessionRecordingStateValues, Q as sessionRecordings, R as sessionTurns, S as sessions, T as socialConnections, U as socialPosts, V as stripeWebhookEvents, W as usageEvents, X as workspaceEnvironmentVariables, Y as workspaceEnvironments, Z as workspaceMemberships, _ as workspacePacks, $ as workspaces } from './schema-BI0iqN9U.js';
3
+ export { i as agentRunStates, j as apiKeys, k as auditEvents, l as billingCustomers, m as capabilityCatalogItems, n as capabilityInstallations, o as codexRotationSettings, p as codexSubscriptionCredentials, q as creditLedgerEntries, r as deviceEnrollmentRequests, d as deviceEnrollmentStatusValues, t as documentBases, u as documentChunks, v as documents, a as enrollmentExposureValues, e as enrollmentOsValues, b as enrollmentStatusValues, w as enrollments, x as fileUploads, y as files, z as githubInstallations, A as machineMetricsLatest, B as machineMetricsSeries, C as managedAccounts, D as packInstallations, c as sandboxKindValues, E as sandboxLeaseHolders, F as sandboxLeaseLivenessValues, G as sandboxLeases, H as sandboxPtySessions, I as sandboxSessionEnvelopes, J as sandboxes, K as scheduledTaskRuns, L as scheduledTasks, M as sessionEvents, N as sessionGoals, O as sessionHistoryItems, P as sessionMcpServers, f as sessionRecordingCodecValues, g as sessionRecordingModeValues, h as sessionRecordingStateValues, Q as sessionRecordings, R as sessionTurns, S as sessions, T as socialConnections, U as socialPosts, V as stripeWebhookEvents, W as usageEvents, X as workspaceEnvironmentVariables, Y as workspaceEnvironments, Z as workspaceMemberships, _ as workspacePacks, $ as workspaces } from './schema-C7Wvjwge.js';
package/dist/schema.js CHANGED
@@ -52,7 +52,7 @@ import {
52
52
  workspaceMemberships,
53
53
  workspacePacks,
54
54
  workspaces
55
- } from "./chunk-NZA6YVN7.js";
55
+ } from "./chunk-T2U4H4Z2.js";
56
56
  import "./chunk-PZ5AY32C.js";
57
57
  export {
58
58
  agentRunStates,
@@ -0,0 +1,92 @@
1
+ -- 0036_modal_lease_orphan_reaper.sql
2
+ -- Modal lease leak hardening:
3
+ -- 1. An expired warming lease with a persisted instance_id is now surfaced as
4
+ -- immediately drainable instead of being reset cold and losing the only DB
5
+ -- pointer to the provider sandbox.
6
+ -- 2. The worker's provider-side Modal orphan sweep gets a SECURITY DEFINER
7
+ -- live-lease attribution read so it can compare Modal tags against current
8
+ -- lease rows across workspaces without disabling FORCE RLS.
9
+
10
+ CREATE OR REPLACE FUNCTION opengeni_private.reap_sandbox_leases(
11
+ p_viewer_holder_ttl_ms bigint,
12
+ p_idle_grace_ms bigint
13
+ )
14
+ RETURNS TABLE (workspace_id uuid, sandbox_group_id uuid, instance_id text, lease_epoch integer)
15
+ LANGUAGE plpgsql
16
+ SECURITY DEFINER
17
+ AS $$
18
+ BEGIN
19
+ DELETE FROM sandbox_lease_holders h
20
+ WHERE h.kind = 'viewer'
21
+ AND h.last_heartbeat_at < now() - make_interval(secs => p_viewer_holder_ttl_ms / 1000.0);
22
+
23
+ UPDATE sandbox_leases L SET
24
+ refcount = c.total,
25
+ turn_holders = c.turns,
26
+ viewer_holders = c.viewers,
27
+ liveness = CASE WHEN L.liveness = 'warm' AND c.total = 0 AND c.turns = 0
28
+ THEN 'draining' ELSE L.liveness END,
29
+ expires_at = CASE WHEN L.liveness = 'warm' AND c.total = 0 AND c.turns = 0
30
+ THEN now() + make_interval(secs => p_idle_grace_ms / 1000.0)
31
+ ELSE L.expires_at END,
32
+ updated_at = now()
33
+ FROM (
34
+ SELECT L2.id,
35
+ (SELECT count(*) FROM sandbox_lease_holders h WHERE h.lease_id = L2.id)::int AS total,
36
+ (SELECT count(*) FROM sandbox_lease_holders h WHERE h.lease_id = L2.id AND h.kind = 'turn')::int AS turns,
37
+ (SELECT count(*) FROM sandbox_lease_holders h WHERE h.lease_id = L2.id AND h.kind = 'viewer')::int AS viewers
38
+ FROM sandbox_leases L2
39
+ ) c
40
+ WHERE L.id = c.id;
41
+
42
+ -- Warming died before provider create returned: no instance was ever tracked.
43
+ UPDATE sandbox_leases AS L SET
44
+ liveness = 'cold', instance_id = NULL,
45
+ resume_backend_id = NULL, resume_state = NULL,
46
+ data_plane_url = NULL, terminal_data_plane_url = NULL, updated_at = now()
47
+ WHERE L.liveness = 'warming' AND L.expires_at < now() AND L.instance_id IS NULL;
48
+
49
+ -- Warming died after provider create returned: keep the instance_id and hand it
50
+ -- to the normal provider termination path in this same sweep.
51
+ UPDATE sandbox_leases AS L SET
52
+ liveness = 'draining',
53
+ refcount = 0,
54
+ turn_holders = 0,
55
+ viewer_holders = 0,
56
+ data_plane_url = NULL,
57
+ terminal_data_plane_url = NULL,
58
+ expires_at = now() - interval '1 millisecond',
59
+ updated_at = now()
60
+ WHERE L.liveness = 'warming' AND L.expires_at < now() AND L.instance_id IS NOT NULL;
61
+
62
+ RETURN QUERY
63
+ SELECT L.workspace_id, L.sandbox_group_id, L.instance_id, L.lease_epoch
64
+ FROM sandbox_leases L
65
+ WHERE L.liveness = 'draining' AND L.expires_at < now() AND L.refcount = 0;
66
+ END;
67
+ $$;
68
+
69
+ CREATE OR REPLACE FUNCTION opengeni_private.list_live_modal_sandbox_leases()
70
+ RETURNS TABLE (
71
+ lease_id uuid,
72
+ workspace_id uuid,
73
+ sandbox_group_id uuid,
74
+ instance_id text,
75
+ liveness text
76
+ )
77
+ LANGUAGE sql
78
+ SECURITY DEFINER
79
+ AS $$
80
+ SELECT L.id, L.workspace_id, L.sandbox_group_id, L.instance_id, L.liveness
81
+ FROM sandbox_leases L
82
+ WHERE L.liveness IN ('warming', 'warm', 'draining')
83
+ AND (L.backend = 'modal' OR L.resume_backend_id = 'modal');
84
+ $$;
85
+
86
+ DO $$
87
+ BEGIN
88
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
89
+ GRANT EXECUTE ON FUNCTION opengeni_private.reap_sandbox_leases(bigint, bigint) TO opengeni_app;
90
+ GRANT EXECUTE ON FUNCTION opengeni_private.list_live_modal_sandbox_leases() TO opengeni_app;
91
+ END IF;
92
+ END $$;
@@ -0,0 +1,18 @@
1
+ -- Per-session agent persona/system instructions.
2
+ --
3
+ -- An optional per-agent-type prompt supplied by an embedding host at session
4
+ -- creation. It rides the SAME system-level instructions channel the
5
+ -- per-workspace agent_instructions rides, composed AFTER the workspace persona
6
+ -- so it refines it for this one session — never as a user-visible timeline
7
+ -- event. NULL means the session carried none, so every existing row keeps its
8
+ -- historical, byte-identical composed instructions after this migration without
9
+ -- a backfill. Org-visible metadata, not a secret.
10
+ ALTER TABLE "sessions"
11
+ ADD COLUMN IF NOT EXISTS "instructions" text;
12
+
13
+ DO $$
14
+ BEGIN
15
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
16
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
17
+ END IF;
18
+ END $$;
@@ -0,0 +1,32 @@
1
+ -- 0038_observability_counts.sql
2
+ -- Cross-workspace aggregate reads for Prometheus gauges. These mirror the
3
+ -- sandbox reaper's SECURITY DEFINER pattern so workers can refresh global
4
+ -- process metrics without disabling FORCE RLS on workspace-scoped tables.
5
+
6
+ CREATE OR REPLACE FUNCTION opengeni_private.count_queued_turns()
7
+ RETURNS bigint
8
+ LANGUAGE sql
9
+ SECURITY DEFINER
10
+ AS $$
11
+ SELECT count(*)::bigint
12
+ FROM session_turns
13
+ WHERE status = 'queued';
14
+ $$;
15
+
16
+ CREATE OR REPLACE FUNCTION opengeni_private.count_sandbox_leases_by_liveness()
17
+ RETURNS TABLE (liveness text, count bigint)
18
+ LANGUAGE sql
19
+ SECURITY DEFINER
20
+ AS $$
21
+ SELECT L.liveness, count(*)::bigint
22
+ FROM sandbox_leases L
23
+ GROUP BY L.liveness;
24
+ $$;
25
+
26
+ DO $$
27
+ BEGIN
28
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
29
+ GRANT EXECUTE ON FUNCTION opengeni_private.count_queued_turns() TO opengeni_app;
30
+ GRANT EXECUTE ON FUNCTION opengeni_private.count_sandbox_leases_by_liveness() TO opengeni_app;
31
+ END IF;
32
+ END $$;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/db",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "OpenGeni persistence: Drizzle schema, RLS-scoped query layer, the SQL migration runner, and role provisioning.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@opengeni/codex": "^0.2.1",
55
- "@opengeni/config": "^0.2.3",
56
- "@opengeni/contracts": "^0.5.0",
55
+ "@opengeni/config": "^0.2.5",
56
+ "@opengeni/contracts": "^0.7.0",
57
57
  "drizzle-orm": "^0.45.2",
58
58
  "postgres": "^3.4.7"
59
59
  },
package/src/index.ts CHANGED
@@ -3274,6 +3274,9 @@ export async function createSession(db: Database, input: {
3274
3274
  sandboxBackend: SandboxBackend;
3275
3275
  environmentId?: string | null;
3276
3276
  firstPartyMcpPermissions?: Permission[] | null;
3277
+ // Per-session agent persona/system instructions (org-visible, not a secret).
3278
+ // Null/omitted ⇒ the session carries none (composed instructions unchanged).
3279
+ instructions?: string | null;
3277
3280
  parentSessionId?: string | null;
3278
3281
  createIdempotencyKey?: string | null;
3279
3282
  // The shared-sandbox group to join. Omit (or null) for a singleton group:
@@ -3301,6 +3304,7 @@ export async function createSession(db: Database, input: {
3301
3304
  sandboxGroupId: input.sandboxGroupId ?? id,
3302
3305
  environmentId: input.environmentId ?? null,
3303
3306
  firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
3307
+ instructions: input.instructions ?? null,
3304
3308
  parentSessionId: input.parentSessionId ?? null,
3305
3309
  createIdempotencyKey: input.createIdempotencyKey ?? null,
3306
3310
  status: "queued",
@@ -3339,6 +3343,8 @@ export async function createSessionWithIdempotencyKey(db: Database, input: {
3339
3343
  sandboxBackend: SandboxBackend;
3340
3344
  environmentId?: string | null;
3341
3345
  firstPartyMcpPermissions?: Permission[] | null;
3346
+ // Per-session agent persona/system instructions (org-visible, not a secret).
3347
+ instructions?: string | null;
3342
3348
  parentSessionId?: string | null;
3343
3349
  createIdempotencyKey: string;
3344
3350
  // The shared-sandbox group to join. Omit (or null) for a singleton group
@@ -3365,6 +3371,7 @@ export async function createSessionWithIdempotencyKey(db: Database, input: {
3365
3371
  sandboxGroupId: input.sandboxGroupId ?? id,
3366
3372
  environmentId: input.environmentId ?? null,
3367
3373
  firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
3374
+ instructions: input.instructions ?? null,
3368
3375
  parentSessionId: input.parentSessionId ?? null,
3369
3376
  createIdempotencyKey: input.createIdempotencyKey,
3370
3377
  status: "queued",
@@ -4481,6 +4488,14 @@ export interface LeaseSnapshot {
4481
4488
  expiresAt: Date;
4482
4489
  }
4483
4490
 
4491
+ export interface LiveModalSandboxLeaseAttribution {
4492
+ leaseId: string;
4493
+ workspaceId: string;
4494
+ sandboxGroupId: string;
4495
+ instanceId: string | null;
4496
+ liveness: SandboxLeaseLiveness;
4497
+ }
4498
+
4484
4499
  export interface AcquireLeaseInput {
4485
4500
  accountId: string;
4486
4501
  workspaceId: string;
@@ -4780,6 +4795,40 @@ export async function commitWarmingToWarm(db: Database, input: {
4780
4795
  });
4781
4796
  }
4782
4797
 
4798
+ // §4.2a — leak-proof create attribution. The spawner calls this immediately
4799
+ // after the provider create returns, before display/readiness/setup work. It
4800
+ // intentionally does NOT bump lease_epoch or mark the lease warm; it only makes
4801
+ // the just-created provider id durable while the row is still warming so a
4802
+ // failure/reaper/provider-side sweep can identify and stop it.
4803
+ export async function recordWarmingSandboxCreated(db: Database, input: {
4804
+ accountId: string;
4805
+ workspaceId: string;
4806
+ sandboxGroupId: string;
4807
+ expectedEpoch: number;
4808
+ instanceId: string;
4809
+ resumeBackendId?: string | null;
4810
+ resumeState?: Record<string, unknown> | null;
4811
+ leaseTtlMs: number;
4812
+ }): Promise<{ recorded: boolean; lease: LeaseSnapshot | null }> {
4813
+ return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId },
4814
+ async (scopedDb) => {
4815
+ const resumeStateJson = input.resumeState == null ? null : JSON.stringify(input.resumeState);
4816
+ const rows = await scopedDb.execute<LeaseRow>(sql`
4817
+ update sandbox_leases set
4818
+ instance_id = ${input.instanceId},
4819
+ resume_backend_id = ${input.resumeBackendId ?? null},
4820
+ resume_state = ${resumeStateJson}::jsonb,
4821
+ expires_at = now() + (${String(input.leaseTtlMs)} || ' milliseconds')::interval,
4822
+ updated_at = now()
4823
+ where workspace_id = ${input.workspaceId} and sandbox_group_id = ${input.sandboxGroupId}
4824
+ and liveness = 'warming' and lease_epoch = ${input.expectedEpoch}
4825
+ returning *
4826
+ `);
4827
+ if (rows.length === 0) return { recorded: false, lease: null };
4828
+ return { recorded: true, lease: mapLeaseRow(rows[0]!) };
4829
+ });
4830
+ }
4831
+
4783
4832
  // §4.3 — caught spawn failure: warming -> cold (W3). Holders are intentionally
4784
4833
  // left intact — the arrival that triggered the spawn still wants a box, so the
4785
4834
  // next acquireLease re-CAS cold->warming.
@@ -4962,15 +5011,34 @@ export async function reapStaleLeaseHolders(db: Database, input: {
4962
5011
  where L.id = c.id and L.workspace_id = ${input.workspaceId}
4963
5012
  `);
4964
5013
 
4965
- // (c) WARMING-death: a 'warming' row whose LEASE TTL lapsed = an uncaught
4966
- // spawner death. Reset to cold so a queued turn can re-acquire and re-spawn.
5014
+ // (c1) WARMING-death before provider create returned: no instance_id was
5015
+ // ever persisted, so there is no provider box to stop. Reset to cold so a
5016
+ // queued turn can re-acquire and re-spawn.
4967
5017
  const warmingReset = await tx.execute<{ id: string }>(sql`
4968
5018
  update sandbox_leases set
4969
5019
  liveness = 'cold', instance_id = null,
4970
5020
  resume_backend_id = null, resume_state = null,
4971
5021
  data_plane_url = null, terminal_data_plane_url = null, updated_at = now()
4972
5022
  where workspace_id = ${input.workspaceId}
4973
- and liveness = 'warming' and expires_at < now()
5023
+ and liveness = 'warming' and expires_at < now() and instance_id is null
5024
+ returning id
5025
+ `);
5026
+
5027
+ // (c2) WARMING-death after provider create returned: instance_id is known,
5028
+ // so do NOT drop it. Convert to immediately-drainable so the caller's
5029
+ // provider terminate path stops the box before the lease goes cold.
5030
+ const warmingDrain = await tx.execute<{ id: string }>(sql`
5031
+ update sandbox_leases set
5032
+ liveness = 'draining',
5033
+ refcount = 0,
5034
+ turn_holders = 0,
5035
+ viewer_holders = 0,
5036
+ data_plane_url = null,
5037
+ terminal_data_plane_url = null,
5038
+ expires_at = now() - interval '1 millisecond',
5039
+ updated_at = now()
5040
+ where workspace_id = ${input.workspaceId}
5041
+ and liveness = 'warming' and expires_at < now() and instance_id is not null
4974
5042
  returning id
4975
5043
  `);
4976
5044
 
@@ -4985,7 +5053,7 @@ export async function reapStaleLeaseHolders(db: Database, input: {
4985
5053
 
4986
5054
  return {
4987
5055
  reapedViewers: reaped.length,
4988
- warmingReset: warmingReset.length,
5056
+ warmingReset: warmingReset.length + warmingDrain.length,
4989
5057
  drained: drainable.map((r) => ({
4990
5058
  workspaceId: input.workspaceId,
4991
5059
  sandboxGroupId: r.sandbox_group_id,
@@ -5045,6 +5113,54 @@ export async function listMeterableWarmLeases(db: Database): Promise<MeterableWa
5045
5113
  }));
5046
5114
  }
5047
5115
 
5116
+ export async function countQueuedTurns(db: Database): Promise<number> {
5117
+ const rows = await rawRows<{ count: number | string }>(db, sql`
5118
+ select opengeni_private.count_queued_turns() as count
5119
+ `);
5120
+ return Number(rows[0]?.count ?? 0);
5121
+ }
5122
+
5123
+ export async function countSandboxLeasesByLiveness(db: Database): Promise<Record<SandboxLeaseLiveness, number>> {
5124
+ const counts: Record<SandboxLeaseLiveness, number> = {
5125
+ cold: 0,
5126
+ warming: 0,
5127
+ warm: 0,
5128
+ draining: 0,
5129
+ };
5130
+ const rows = await rawRows<{ liveness: SandboxLeaseLiveness; count: number | string }>(db, sql`
5131
+ select liveness, count
5132
+ from opengeni_private.count_sandbox_leases_by_liveness()
5133
+ `);
5134
+ for (const row of rows) {
5135
+ if (row.liveness in counts) {
5136
+ counts[row.liveness] = Number(row.count);
5137
+ }
5138
+ }
5139
+ return counts;
5140
+ }
5141
+
5142
+ // Cross-workspace live Modal lease read for the provider-side orphan sweep. The
5143
+ // SECURITY DEFINER function is the sanctioned RLS bypass; see migration 0036.
5144
+ export async function listLiveModalSandboxLeaseAttributions(db: Database): Promise<LiveModalSandboxLeaseAttribution[]> {
5145
+ const rows = await rawRows<{
5146
+ lease_id: string;
5147
+ workspace_id: string;
5148
+ sandbox_group_id: string;
5149
+ instance_id: string | null;
5150
+ liveness: SandboxLeaseLiveness;
5151
+ }>(db, sql`
5152
+ select lease_id, workspace_id, sandbox_group_id, instance_id, liveness
5153
+ from opengeni_private.list_live_modal_sandbox_leases()
5154
+ `);
5155
+ return rows.map((r) => ({
5156
+ leaseId: r.lease_id,
5157
+ workspaceId: r.workspace_id,
5158
+ sandboxGroupId: r.sandbox_group_id,
5159
+ instanceId: r.instance_id,
5160
+ liveness: r.liveness,
5161
+ }));
5162
+ }
5163
+
5048
5164
  // §4.7 — explicit re-arm seam (D1). acquireLease already re-arms a draining
5049
5165
  // lease inline; this is the standalone version for callers that learn a holder
5050
5166
  // is wanted during the grace window without going through acquireLease first.
@@ -7618,6 +7734,7 @@ function mapSession(row: typeof schema.sessions.$inferSelect, mcpServers: Sessio
7618
7734
  initialMessage: row.initialMessage,
7619
7735
  title: row.title ?? null,
7620
7736
  titleSource: (row.titleSource as "user" | "agent" | null) ?? null,
7737
+ instructions: row.instructions ?? null,
7621
7738
  resources: row.resources as ResourceRef[],
7622
7739
  tools: row.tools as ToolRef[],
7623
7740
  metadata: row.metadata,
package/src/schema.ts CHANGED
@@ -187,6 +187,13 @@ export const sessions = pgTable("sessions", {
187
187
  initialMessage: text("initial_message").notNull(),
188
188
  title: text("title"),
189
189
  titleSource: text("title_source"),
190
+ // Per-session agent persona/system instructions supplied at create (the
191
+ // per-agent-type prompt lever for embedding hosts). NULL ⇒ the session
192
+ // carried none, so the composed agent instructions are byte-identical to a
193
+ // workspace-only persona (no backfill, no behavior change for existing rows).
194
+ // Composed system-level AFTER the workspace agentInstructions; never emitted
195
+ // as a timeline event.
196
+ instructions: text("instructions"),
190
197
  resources: jsonb("resources").$type<unknown[]>().notNull().default([]),
191
198
  tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
192
199
  metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),