@opengeni/db 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-57MLICFR.js +121 -0
- package/dist/chunk-57MLICFR.js.map +1 -0
- package/dist/chunk-OGCE6O2X.js +52 -0
- package/dist/chunk-OGCE6O2X.js.map +1 -0
- package/dist/chunk-PSX56ZTL.js +1093 -0
- package/dist/chunk-PSX56ZTL.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5165 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate.d.ts +40 -0
- package/dist/migrate.js +10 -0
- package/dist/migrate.js.map +1 -0
- package/dist/provision-roles.d.ts +2063 -0
- package/dist/provision-roles.js +8 -0
- package/dist/provision-roles.js.map +1 -0
- package/dist/schema-CaeZQAJQ.d.ts +9705 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.js +110 -0
- package/dist/schema.js.map +1 -0
- package/drizzle/0000_initial.sql +179 -0
- package/drizzle/0001_workspace_auth_billing.sql +590 -0
- package/drizzle/0002_packs_and_social.sql +99 -0
- package/drizzle/0003_capability_catalog.sql +73 -0
- package/drizzle/0004_workspace_environments.sql +65 -0
- package/drizzle/0005_session_goals.sql +45 -0
- package/drizzle/0006_workspace_packs.sql +31 -0
- package/drizzle/0007_session_history_items.sql +66 -0
- package/drizzle/0008_session_first_party_mcp_permissions.sql +5 -0
- package/drizzle/0009_goal_sessions_first_party_goals_manage.sql +34 -0
- package/drizzle/0010_session_parent_linkage.sql +30 -0
- package/drizzle/0011_context_compaction.sql +33 -0
- package/drizzle/0012_compaction_summary_fractional_position.sql +19 -0
- package/drizzle/0013_session_compact_requested.sql +16 -0
- package/drizzle/0014_repair_orphaned_function_call_results.sql +125 -0
- package/drizzle/0015_workspace_agent_instructions.sql +17 -0
- package/drizzle/0016_session_create_idempotency.sql +27 -0
- package/drizzle/0017_sandbox_leases.sql +313 -0
- package/drizzle/0018_sandbox_os.sql +89 -0
- package/drizzle/0019_session_stream_acknowledgments.sql +94 -0
- package/drizzle/0020_session_recordings.sql +88 -0
- package/drizzle/0021_sandbox_pty_sessions.sql +70 -0
- package/drizzle/0022_sandbox_lease_terminal_url.sql +32 -0
- package/drizzle/0023_session_title.sql +19 -0
- package/drizzle/0024_codex_subscription_credentials.sql +51 -0
- package/drizzle/0024_sandboxes_enrollments_metrics.sql +262 -0
- package/drizzle/0025_device_enrollment_requests.sql +142 -0
- package/drizzle/0026_device_enrollment_user_code_resolver.sql +47 -0
- package/drizzle/0027_session_working_dir.sql +24 -0
- package/drizzle/0028_codex_multi_account.sql +85 -0
- package/drizzle/0029_session_history_item_producer.sql +31 -0
- package/drizzle/0030_agent_run_state_frozen_codex.sql +35 -0
- package/drizzle/0031_codex_usage_cache.sql +21 -0
- package/drizzle/0032_codex_account_cooldown.sql +18 -0
- package/drizzle/0033_codex_connector_cache.sql +20 -0
- package/drizzle/0034_sandbox_lease_image.sql +21 -0
- package/drizzle/meta/_journal.json +167 -0
- package/package.json +66 -0
- package/src/codex-token-resolver.ts +247 -0
- package/src/environment-crypto.ts +51 -0
- package/src/event-payload-sanitizer.ts +89 -0
- package/src/index.ts +7776 -0
- package/src/migrate.ts +95 -0
- package/src/provision-roles.ts +198 -0
- package/src/schema.ts +1110 -0
|
@@ -0,0 +1,2063 @@
|
|
|
1
|
+
import { SessionEventType, Permission, CapabilityKind, CapabilitySource, ScheduledTaskStatus, ScheduledTaskScheduleSpec, ScheduledTaskRunMode, ScheduledTaskOverlapPolicy, ScheduledTaskAgentConfig, SessionGoalCreatedBy, SocialProvider, SocialConnectionStatus, SessionTurnSource, ResourceRef, ToolRef, ReasoningEffort, SandboxBackend, SessionGoal, CapabilityPack, SessionTurn, SessionEvent, SessionStatus, Session, BillingBalance, AccessContext, FileAsset, ApiKey, ScheduledTask, ScheduledTaskTriggerType, ScheduledTaskRun, SandboxOs, SocialConnection, SocialPost, Workspace, WorkspaceEnvironment, CapabilityInstallation, PackInstallation, SessionTurnStatus, CapabilityCatalogItem, FileUploadStatus, ManagedAccount, AccessGrant, WorkspaceRegisteredPack, UsageEvent, WorkspaceMember, SessionGoalStatus, WorkspaceEnvironmentVariableMetadata, PackInstallationStatus, ScheduledTaskRunStatus } from '@opengeni/contracts';
|
|
2
|
+
import { environmentsEncryptionKeyBytes, Settings } from '@opengeni/config';
|
|
3
|
+
import { refreshCodexToken, CodexTokenSnapshot, CodexUsagePayload } from '@opengeni/codex';
|
|
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-CaeZQAJQ.js';
|
|
6
|
+
import 'drizzle-orm';
|
|
7
|
+
import './migrate.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Encrypts one workspace environment variable value with AES-256-GCM under an
|
|
11
|
+
* operator key held outside Postgres. Output format: `v1:<b64 iv>:<b64 ciphertext||tag>`.
|
|
12
|
+
*/
|
|
13
|
+
declare function encryptEnvironmentValue(key: Uint8Array, plaintext: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Decrypts a stored `v1:` value. Error messages never echo plaintext or
|
|
16
|
+
* ciphertext: unknown versions throw "unsupported environment value format",
|
|
17
|
+
* auth-tag mismatches throw "environment value decryption failed".
|
|
18
|
+
*/
|
|
19
|
+
declare function decryptEnvironmentValue(key: Uint8Array, stored: string): string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Last line of defense against a session event crashing a whole turn.
|
|
23
|
+
*
|
|
24
|
+
* Postgres `text`/`jsonb` cannot store a NUL byte (U+0000) nor lone UTF-16
|
|
25
|
+
* surrogates. Raw exec output routinely carries both -- chrome/crashpad logs,
|
|
26
|
+
* `cat` of a binary, random bytes -- and the worker persists that output verbatim
|
|
27
|
+
* inside `agent.toolCall.output` / `sandbox.command.output` event payloads. When
|
|
28
|
+
* such a payload reaches `INSERT INTO session_events`, the driver rejects it
|
|
29
|
+
* ("Failed query: insert into session_events") and the turn dies.
|
|
30
|
+
*
|
|
31
|
+
* `sanitizeEventPayload` deep-walks any payload value (objects, arrays, nested)
|
|
32
|
+
* and, for every string, strips NUL and rewrites invalid/lone UTF-16 surrogates
|
|
33
|
+
* to the Unicode replacement char (U+FFFD), so the result is always valid UTF-8
|
|
34
|
+
* that jsonb can store. It is cheap and total: only strings are touched, and only
|
|
35
|
+
* the two disallowed classes of code unit -- no meaningful text is lost, no
|
|
36
|
+
* truncation (truncation is handled elsewhere).
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Strip NUL and repair invalid/lone UTF-16 surrogates in a single string.
|
|
40
|
+
* Returns the input unchanged (same reference) when it is already clean, so the
|
|
41
|
+
* common case allocates nothing.
|
|
42
|
+
*/
|
|
43
|
+
declare function sanitizeEventString(value: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Deep-walk a session event payload and sanitize every string value. Mirrors the
|
|
46
|
+
* shape of the worker redaction deep-walk: objects, arrays, and nested
|
|
47
|
+
* combinations are traversed; non-string leaves pass through untouched. Object
|
|
48
|
+
* keys are sanitized too -- they are jsonb-constrained the same as values.
|
|
49
|
+
*/
|
|
50
|
+
declare function sanitizeEventPayload<T>(payload: T): T;
|
|
51
|
+
|
|
52
|
+
type ProvisionResult = {
|
|
53
|
+
appRole: string | null;
|
|
54
|
+
temporalRole: string | null;
|
|
55
|
+
temporalDatabases: string[];
|
|
56
|
+
schema: string;
|
|
57
|
+
rlsStrategy: RlsStrategy;
|
|
58
|
+
};
|
|
59
|
+
type ProvisionRolesOptions = {
|
|
60
|
+
/**
|
|
61
|
+
* The schema OpenGeni's tables live in. The app-role GRANTs target this
|
|
62
|
+
* schema + `opengeni_private`. Defaults to `public` (standalone).
|
|
63
|
+
*/
|
|
64
|
+
targetSchema?: string;
|
|
65
|
+
/**
|
|
66
|
+
* RLS posture (Step I). `"force"` (default) provisions the non-owner
|
|
67
|
+
* `opengeni_app` login role and GRANTs it table DML in the target schema —
|
|
68
|
+
* the role OpenGeni connects as under FORCE-RLS. `"scoped"` SKIPS the app-role
|
|
69
|
+
* provisioning entirely: the embedded host runs OpenGeni's queries over a role
|
|
70
|
+
* IT owns/manages (typically the schema owner), so OpenGeni neither creates
|
|
71
|
+
* nor grants the `opengeni_app` role. Temporal-role provisioning is unaffected
|
|
72
|
+
* by strategy.
|
|
73
|
+
*/
|
|
74
|
+
rlsStrategy?: RlsStrategy;
|
|
75
|
+
appRole?: string;
|
|
76
|
+
appPassword?: string;
|
|
77
|
+
temporalRole?: string;
|
|
78
|
+
temporalPassword?: string;
|
|
79
|
+
temporalDatabases?: string[];
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* SDK entry point (Step I): provision the OpenGeni database roles + grants over
|
|
83
|
+
* a host-supplied admin connection. This is the named, parameterized form of the
|
|
84
|
+
* historical env-driven `provision-roles` script (which still works as a CLI via
|
|
85
|
+
* the `import.meta.main` block at the bottom — it just reads env into these
|
|
86
|
+
* options).
|
|
87
|
+
*
|
|
88
|
+
* STANDALONE (default): `provisionRoles(adminConnection)` with no options →
|
|
89
|
+
* `targetSchema: "public"`, `rlsStrategy: "force"`, reads `opengeni_app` creds
|
|
90
|
+
* from env. Byte-for-byte the historical script behavior.
|
|
91
|
+
*
|
|
92
|
+
* EMBEDDED: `provisionRoles(adminConnection, { targetSchema, rlsStrategy })` lets
|
|
93
|
+
* a host provision the app role over a dedicated schema (force) OR skip the
|
|
94
|
+
* app role entirely and own the connection role itself (scoped).
|
|
95
|
+
*/
|
|
96
|
+
declare function provisionRoles(adminConnection: string, options?: ProvisionRolesOptions): Promise<ProvisionResult>;
|
|
97
|
+
|
|
98
|
+
type CodexAuthDeps = {
|
|
99
|
+
loadCredential: typeof loadCodexCredentialForRun;
|
|
100
|
+
recordRefresh: typeof recordCodexTokenRefresh;
|
|
101
|
+
setStatus: typeof setCodexCredentialStatus;
|
|
102
|
+
refresh: typeof refreshCodexToken;
|
|
103
|
+
encrypt: typeof encryptEnvironmentValue;
|
|
104
|
+
keyBytes: typeof environmentsEncryptionKeyBytes;
|
|
105
|
+
};
|
|
106
|
+
declare function buildCodexTokenResolver(db: Database, settings: Settings, workspaceId: string, credentialId: string, deps?: CodexAuthDeps): {
|
|
107
|
+
getToken: () => Promise<CodexTokenSnapshot>;
|
|
108
|
+
refresh: () => Promise<CodexTokenSnapshot>;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* THE single per-account usage path both the api route and an (optional) worker
|
|
112
|
+
* poll call, so the refresh discipline and the cache-write can never drift.
|
|
113
|
+
*
|
|
114
|
+
* 1. resolve a REFRESHING bearer for THIS account (proactive staleness refresh,
|
|
115
|
+
* single-flight, (id,version) CAS-persist) — this is what stops an idle
|
|
116
|
+
* account's expired JWT from 401-ing the usage read.
|
|
117
|
+
* 2. fetch GET /wham/usage with that bearer.
|
|
118
|
+
* 3. normalize (§3) into the P2/P3 contract.
|
|
119
|
+
* 4. on any windows present, write the five usage-cache columns (the TTL clock).
|
|
120
|
+
*
|
|
121
|
+
* A refresh that stamps needs_relogin returns { status:"error", reason } and never
|
|
122
|
+
* hits the provider; a transient refresh error returns a plain error payload.
|
|
123
|
+
*/
|
|
124
|
+
declare function fetchCodexUsageForAccount(db: Database, settings: Settings, workspaceId: string, credentialId: string): Promise<CodexUsagePayload>;
|
|
125
|
+
|
|
126
|
+
type Database = PgDatabase<any, typeof schema>;
|
|
127
|
+
type DbClient = {
|
|
128
|
+
db: Database;
|
|
129
|
+
close: () => Promise<void>;
|
|
130
|
+
};
|
|
131
|
+
type RlsContext = {
|
|
132
|
+
accountId: string;
|
|
133
|
+
workspaceId?: string | null;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* RLS posture for the connection OpenGeni's query layer runs over (Step I, §7.7).
|
|
137
|
+
*
|
|
138
|
+
* - `"force"` (DEFAULT — today's standalone behavior, byte-for-byte): OpenGeni
|
|
139
|
+
* connects as a NON-OWNER role (`opengeni_app`) and every table carries
|
|
140
|
+
* `FORCE ROW LEVEL SECURITY`, so the workspace/account GUCs set by
|
|
141
|
+
* `setRlsContext` are the ONLY thing that admits rows — even the table owner
|
|
142
|
+
* is subject to RLS. This is the Fork-A isolation guarantee.
|
|
143
|
+
* - `"scoped"` (embedded Fork-B opt-in): the host runs OpenGeni's queries over a
|
|
144
|
+
* role that OWNS the dedicated schema (RLS need not be forced for that role),
|
|
145
|
+
* relying on the host's own tenant boundary. OpenGeni STILL emits the
|
|
146
|
+
* `set_config('opengeni.account_id'/'workspace_id', …)` GUCs defensively on
|
|
147
|
+
* every scoped query, so the application query path is byte-identical between
|
|
148
|
+
* the two strategies and the app code is RLS-mode-agnostic. The strategy is a
|
|
149
|
+
* declared posture (consumed by `provisionRoles` and as a documented
|
|
150
|
+
* invariant), NOT a query-path branch — there is deliberately no `if
|
|
151
|
+
* (strategy === …)` anywhere in the helpers below. Picking `"scoped"` does not
|
|
152
|
+
* relax any GUC; it only changes which DB role the host provisions/connects as
|
|
153
|
+
* and asserts that the host accepts owning the isolation boundary.
|
|
154
|
+
*/
|
|
155
|
+
type RlsStrategy = "force" | "scoped";
|
|
156
|
+
/**
|
|
157
|
+
* Resolve a host-IdP/Better-Auth user *identifier* by email. Injected via
|
|
158
|
+
* `createDb({ userLookup })` (Step I). UNSET → today's raw parameterized select
|
|
159
|
+
* against Better Auth's `auth_users` table (see `getManagedUserByEmail`), which
|
|
160
|
+
* relies on the postgres-js array-shaped `db.execute` result. An embedded host
|
|
161
|
+
* whose identity lives elsewhere (a different IdP table, a different driver, or
|
|
162
|
+
* a non-`auth_users` user store) injects this closure so OpenGeni never touches
|
|
163
|
+
* `auth_users` directly. Returns the user id, or null when no such user exists.
|
|
164
|
+
*/
|
|
165
|
+
type UserLookup = (db: Database, email: string) => Promise<string | null>;
|
|
166
|
+
type CreateDbOptions = {
|
|
167
|
+
/**
|
|
168
|
+
* The Postgres `search_path` for this connection (Step I, §7.8 runtime half).
|
|
169
|
+
* UNSET → today's behavior: NO `search_path` startup parameter is sent, so the
|
|
170
|
+
* server default applies (`public` for standalone, where every table + the
|
|
171
|
+
* `vector` extension + `gen_random_uuid()` live). For an embedded dedicated
|
|
172
|
+
* schema, pass e.g. `"opengeni,opengeni_private,public"` — postgres-js sends
|
|
173
|
+
* it as a per-session startup parameter (the supported, query-param-free way;
|
|
174
|
+
* URL `?search_path=` is IGNORED by postgres-js). Keep `public` LAST so the
|
|
175
|
+
* `vector` type and `gen_random_uuid()` (which live in `public` on the
|
|
176
|
+
* pgvector image) still resolve — the SPIKE-1 live footgun.
|
|
177
|
+
*/
|
|
178
|
+
searchPath?: string;
|
|
179
|
+
/** RLS posture; defaults to `"force"` (today's standalone). */
|
|
180
|
+
rlsStrategy?: RlsStrategy;
|
|
181
|
+
/** Host-provided user-by-email resolver; unset → today's raw `auth_users` query. */
|
|
182
|
+
userLookup?: UserLookup;
|
|
183
|
+
/** postgres-js pool size; defaults to today's `10`. */
|
|
184
|
+
max?: number;
|
|
185
|
+
};
|
|
186
|
+
/** The strategy bound to a handle (or the `"force"` default). */
|
|
187
|
+
declare function rlsStrategyFor(db: Database): RlsStrategy;
|
|
188
|
+
declare function createDb(databaseUrl: string, options?: CreateDbOptions): DbClient;
|
|
189
|
+
/**
|
|
190
|
+
* Register a host's `rlsStrategy`/`userLookup` against an externally-constructed
|
|
191
|
+
* `Database` handle (e.g. one the embedded host built from its own driver and
|
|
192
|
+
* injected, rather than via `createDb`). Lets the same WeakMap-backed lookups
|
|
193
|
+
* work for injected handles. Standalone never calls this (it uses `createDb`).
|
|
194
|
+
*/
|
|
195
|
+
declare function registerDbBinding(db: Database, binding: {
|
|
196
|
+
rlsStrategy?: RlsStrategy;
|
|
197
|
+
userLookup?: UserLookup;
|
|
198
|
+
}): void;
|
|
199
|
+
declare function setRlsContext(db: Database, context: RlsContext): Promise<void>;
|
|
200
|
+
declare function withRlsContext<T>(db: Database, context: RlsContext, fn: (db: Database) => Promise<T>): Promise<T>;
|
|
201
|
+
declare function rlsContextForWorkspace(db: Database, workspaceId: string): Promise<RlsContext>;
|
|
202
|
+
declare function withWorkspaceRls<T>(db: Database, workspaceId: string, fn: (db: Database) => Promise<T>): Promise<T>;
|
|
203
|
+
declare function withWorkspaceUsageLock<T>(db: Database, workspaceId: string, fn: (db: Database) => Promise<T>): Promise<T>;
|
|
204
|
+
declare function withAccountRls<T>(db: Database, accountId: string, fn: (db: Database) => Promise<T>): Promise<T>;
|
|
205
|
+
declare const allWorkspacePermissions: Permission[];
|
|
206
|
+
declare const allAccountPermissions: Permission[];
|
|
207
|
+
type BootstrapWorkspaceInput = {
|
|
208
|
+
accountExternalSource: string;
|
|
209
|
+
accountExternalId: string;
|
|
210
|
+
accountName: string;
|
|
211
|
+
workspaceExternalSource: string;
|
|
212
|
+
workspaceExternalId: string;
|
|
213
|
+
workspaceName: string;
|
|
214
|
+
subjectId: string;
|
|
215
|
+
subjectLabel?: string;
|
|
216
|
+
accountPermissions?: Permission[];
|
|
217
|
+
workspacePermissions?: Permission[];
|
|
218
|
+
};
|
|
219
|
+
declare function bootstrapWorkspace(db: Database, input: BootstrapWorkspaceInput): Promise<AccessContext>;
|
|
220
|
+
declare function ensureManagedAccessForUser(db: Database, input: {
|
|
221
|
+
userId: string;
|
|
222
|
+
email: string;
|
|
223
|
+
name: string;
|
|
224
|
+
}): Promise<AccessContext>;
|
|
225
|
+
declare function getWorkspace(db: Database, workspaceId: string): Promise<Workspace | null>;
|
|
226
|
+
declare function getManagedAccount(db: Database, accountId: string): Promise<ManagedAccount | null>;
|
|
227
|
+
declare function requireWorkspace(db: Database, workspaceId: string): Promise<Workspace>;
|
|
228
|
+
declare function listWorkspacesForSubject(db: Database, subjectId: string, limit?: number): Promise<Workspace[]>;
|
|
229
|
+
declare function countWorkspacesForAccount(db: Database, accountId: string): Promise<number>;
|
|
230
|
+
declare function createWorkspace(db: Database, input: {
|
|
231
|
+
accountId: string;
|
|
232
|
+
name: string;
|
|
233
|
+
slug?: string | null;
|
|
234
|
+
externalSource?: string | null;
|
|
235
|
+
externalId?: string | null;
|
|
236
|
+
agentInstructions?: string | null;
|
|
237
|
+
}): Promise<Workspace>;
|
|
238
|
+
declare function grantWorkspaceAccess(db: Database, input: {
|
|
239
|
+
accountId: string;
|
|
240
|
+
workspaceId: string;
|
|
241
|
+
subjectId: string;
|
|
242
|
+
subjectLabel?: string;
|
|
243
|
+
role?: string;
|
|
244
|
+
permissions: Permission[];
|
|
245
|
+
}): Promise<void>;
|
|
246
|
+
declare function updateWorkspace(db: Database, workspaceId: string, input: {
|
|
247
|
+
name?: string;
|
|
248
|
+
slug?: string | null;
|
|
249
|
+
agentInstructions?: string | null;
|
|
250
|
+
}): Promise<Workspace>;
|
|
251
|
+
declare function getWorkspaceGrant(db: Database, subjectId: string, workspaceId: string): Promise<AccessGrant | null>;
|
|
252
|
+
declare function listWorkspaceMembers(db: Database, workspaceId: string): Promise<WorkspaceMember[]>;
|
|
253
|
+
declare function removeWorkspaceMember(db: Database, workspaceId: string, subjectId: string): Promise<boolean>;
|
|
254
|
+
/**
|
|
255
|
+
* Resolve a managed user email to its user id.
|
|
256
|
+
*
|
|
257
|
+
* STANDALONE (default, unchanged): the `auth_users` table is owned by Better
|
|
258
|
+
* Auth and is NOT in the Drizzle schema, so this runs the raw parameterized
|
|
259
|
+
* select below — matching emails case-insensitively, returning the id or null.
|
|
260
|
+
*
|
|
261
|
+
* EMBEDDED (Step I `userLookup` port): when the handle was built via
|
|
262
|
+
* `createDb({ userLookup })` (or registered with `registerDbBinding`), this
|
|
263
|
+
* delegates to the host's resolver instead — so a host whose identity lives in
|
|
264
|
+
* a different IdP/table/driver never forces OpenGeni to touch `auth_users`. The
|
|
265
|
+
* raw query also assumes the postgres-js array-shaped `db.execute` result; the
|
|
266
|
+
* port is the cross-driver escape hatch for that too.
|
|
267
|
+
*
|
|
268
|
+
* Used to add an already-registered user to a workspace; email invites for
|
|
269
|
+
* unknown users are deferred.
|
|
270
|
+
*/
|
|
271
|
+
declare function getManagedUserByEmail(db: Database, email: string): Promise<string | null>;
|
|
272
|
+
declare function deleteWorkspace(db: Database, workspaceId: string): Promise<void>;
|
|
273
|
+
declare function createApiKey(db: Database, input: {
|
|
274
|
+
accountId: string;
|
|
275
|
+
workspaceId?: string | null;
|
|
276
|
+
name: string;
|
|
277
|
+
prefix: string;
|
|
278
|
+
keyHash: string;
|
|
279
|
+
permissions: Permission[];
|
|
280
|
+
expiresAt?: Date | null;
|
|
281
|
+
}): Promise<ApiKey>;
|
|
282
|
+
declare function listApiKeys(db: Database, workspaceId: string): Promise<ApiKey[]>;
|
|
283
|
+
declare function countActiveApiKeysForWorkspace(db: Database, workspaceId: string): Promise<number>;
|
|
284
|
+
declare function revokeApiKey(db: Database, workspaceId: string, apiKeyId: string): Promise<ApiKey>;
|
|
285
|
+
declare function findActiveApiKeyByHash(db: Database, keyHash: string): Promise<ApiKey | null>;
|
|
286
|
+
type GitHubInstallation = {
|
|
287
|
+
id: string;
|
|
288
|
+
accountId: string;
|
|
289
|
+
workspaceId: string;
|
|
290
|
+
installationId: number;
|
|
291
|
+
accountLogin: string | null;
|
|
292
|
+
accountType: string | null;
|
|
293
|
+
createdAt: string;
|
|
294
|
+
updatedAt: string;
|
|
295
|
+
};
|
|
296
|
+
declare function upsertGitHubInstallation(db: Database, input: {
|
|
297
|
+
accountId: string;
|
|
298
|
+
workspaceId: string;
|
|
299
|
+
installationId: number;
|
|
300
|
+
accountLogin?: string | null;
|
|
301
|
+
accountType?: string | null;
|
|
302
|
+
}): Promise<GitHubInstallation>;
|
|
303
|
+
declare function listGitHubInstallationsForWorkspace(db: Database, workspaceId: string): Promise<GitHubInstallation[]>;
|
|
304
|
+
declare function listGitHubInstallationIdsForWorkspace(db: Database, workspaceId: string): Promise<number[]>;
|
|
305
|
+
declare function recordUsageEvent(db: Database, input: {
|
|
306
|
+
accountId: string;
|
|
307
|
+
workspaceId: string;
|
|
308
|
+
subjectId?: string | null;
|
|
309
|
+
eventType: string;
|
|
310
|
+
quantity: number;
|
|
311
|
+
unit: string;
|
|
312
|
+
sourceResourceType?: string | null;
|
|
313
|
+
sourceResourceId?: string | null;
|
|
314
|
+
idempotencyKey: string;
|
|
315
|
+
occurredAt?: Date;
|
|
316
|
+
}): Promise<UsageEvent>;
|
|
317
|
+
declare function listUsageEvents(db: Database, input: {
|
|
318
|
+
accountId: string;
|
|
319
|
+
workspaceId?: string;
|
|
320
|
+
limit?: number;
|
|
321
|
+
}): Promise<UsageEvent[]>;
|
|
322
|
+
declare function sumUsageQuantity(db: Database, input: {
|
|
323
|
+
accountId?: string;
|
|
324
|
+
workspaceId?: string;
|
|
325
|
+
eventType: string;
|
|
326
|
+
since?: Date;
|
|
327
|
+
}): Promise<number>;
|
|
328
|
+
declare function applyCreditLedgerEntry(db: Database, input: {
|
|
329
|
+
accountId: string;
|
|
330
|
+
workspaceId?: string | null;
|
|
331
|
+
type: string;
|
|
332
|
+
amountMicros: number;
|
|
333
|
+
sourceType?: string | null;
|
|
334
|
+
sourceId?: string | null;
|
|
335
|
+
idempotencyKey: string;
|
|
336
|
+
metadata?: Record<string, unknown>;
|
|
337
|
+
occurredAt?: Date;
|
|
338
|
+
}): Promise<BillingBalance>;
|
|
339
|
+
declare function applyCreditDebitUpToBalance(db: Database, input: {
|
|
340
|
+
accountId: string;
|
|
341
|
+
workspaceId?: string | null;
|
|
342
|
+
type: string;
|
|
343
|
+
requestedAmountMicros: number;
|
|
344
|
+
sourceType?: string | null;
|
|
345
|
+
sourceId?: string | null;
|
|
346
|
+
idempotencyKey: string;
|
|
347
|
+
metadata?: Record<string, unknown>;
|
|
348
|
+
occurredAt?: Date;
|
|
349
|
+
}): Promise<{
|
|
350
|
+
balance: BillingBalance;
|
|
351
|
+
debitedMicros: number;
|
|
352
|
+
}>;
|
|
353
|
+
declare function hasCreditLedgerEntry(db: Database, accountId: string, idempotencyKey: string): Promise<boolean>;
|
|
354
|
+
declare function getBillingCustomer(db: Database, accountId: string, provider?: string): Promise<{
|
|
355
|
+
accountId: string;
|
|
356
|
+
provider: string;
|
|
357
|
+
providerCustomerId: string;
|
|
358
|
+
email: string | null;
|
|
359
|
+
} | null>;
|
|
360
|
+
declare function upsertBillingCustomer(db: Database, input: {
|
|
361
|
+
accountId: string;
|
|
362
|
+
provider?: string;
|
|
363
|
+
providerCustomerId: string;
|
|
364
|
+
email?: string | null;
|
|
365
|
+
}): Promise<void>;
|
|
366
|
+
declare function recordStripeWebhookEvent(db: Database, input: {
|
|
367
|
+
id: string;
|
|
368
|
+
type: string;
|
|
369
|
+
livemode: boolean;
|
|
370
|
+
payload: unknown;
|
|
371
|
+
}): Promise<boolean>;
|
|
372
|
+
declare function isStripeWebhookProcessed(db: Database, id: string): Promise<boolean>;
|
|
373
|
+
declare function markStripeWebhookProcessed(db: Database, id: string): Promise<void>;
|
|
374
|
+
declare function getBillingBalance(db: Database, accountId: string): Promise<BillingBalance>;
|
|
375
|
+
declare function countScheduledTasksForWorkspace(db: Database, workspaceId: string): Promise<number>;
|
|
376
|
+
type AppendEventInput = {
|
|
377
|
+
type: SessionEventType;
|
|
378
|
+
payload?: unknown;
|
|
379
|
+
clientEventId?: string;
|
|
380
|
+
turnId?: string | null;
|
|
381
|
+
producerId?: string;
|
|
382
|
+
producerSeq?: number;
|
|
383
|
+
occurredAt?: Date;
|
|
384
|
+
};
|
|
385
|
+
type CreateScheduledTaskInput = {
|
|
386
|
+
id?: string;
|
|
387
|
+
accountId: string;
|
|
388
|
+
workspaceId: string;
|
|
389
|
+
name: string;
|
|
390
|
+
status: ScheduledTaskStatus;
|
|
391
|
+
schedule: ScheduledTaskScheduleSpec;
|
|
392
|
+
temporalScheduleId: string;
|
|
393
|
+
runMode: ScheduledTaskRunMode;
|
|
394
|
+
overlapPolicy: ScheduledTaskOverlapPolicy;
|
|
395
|
+
agentConfig: ScheduledTaskAgentConfig;
|
|
396
|
+
environmentId?: string | null;
|
|
397
|
+
metadata: Record<string, unknown>;
|
|
398
|
+
};
|
|
399
|
+
type UpdateScheduledTaskInput = Partial<{
|
|
400
|
+
name: string;
|
|
401
|
+
status: ScheduledTaskStatus;
|
|
402
|
+
schedule: ScheduledTaskScheduleSpec;
|
|
403
|
+
runMode: ScheduledTaskRunMode;
|
|
404
|
+
overlapPolicy: ScheduledTaskOverlapPolicy;
|
|
405
|
+
agentConfig: ScheduledTaskAgentConfig;
|
|
406
|
+
reusableSessionId: string | null;
|
|
407
|
+
environmentId: string | null;
|
|
408
|
+
metadata: Record<string, unknown>;
|
|
409
|
+
}>;
|
|
410
|
+
type CreatePackInstallationInput = {
|
|
411
|
+
accountId: string;
|
|
412
|
+
workspaceId: string;
|
|
413
|
+
packId: string;
|
|
414
|
+
metadata?: Record<string, unknown>;
|
|
415
|
+
};
|
|
416
|
+
type RegisterWorkspacePackInput = {
|
|
417
|
+
accountId: string;
|
|
418
|
+
workspaceId: string;
|
|
419
|
+
pack: CapabilityPack;
|
|
420
|
+
};
|
|
421
|
+
type CreateSocialConnectionInput = {
|
|
422
|
+
accountId: string;
|
|
423
|
+
workspaceId: string;
|
|
424
|
+
provider: SocialProvider;
|
|
425
|
+
accountHandle: string;
|
|
426
|
+
accountName?: string | null;
|
|
427
|
+
externalAccountId?: string | null;
|
|
428
|
+
status: SocialConnectionStatus;
|
|
429
|
+
scopes?: string[];
|
|
430
|
+
credentialRef?: string | null;
|
|
431
|
+
tokenMetadata?: Record<string, unknown>;
|
|
432
|
+
metadata?: Record<string, unknown>;
|
|
433
|
+
};
|
|
434
|
+
type CreateSocialPostInput = {
|
|
435
|
+
accountId: string;
|
|
436
|
+
workspaceId: string;
|
|
437
|
+
connectionId: string;
|
|
438
|
+
externalPostId?: string | null;
|
|
439
|
+
url?: string | null;
|
|
440
|
+
authorHandle?: string | null;
|
|
441
|
+
text: string;
|
|
442
|
+
publishedAt: Date;
|
|
443
|
+
metrics?: Record<string, number>;
|
|
444
|
+
raw?: Record<string, unknown>;
|
|
445
|
+
};
|
|
446
|
+
type CreateCapabilityCatalogItemInput = {
|
|
447
|
+
accountId: string;
|
|
448
|
+
workspaceId: string;
|
|
449
|
+
id: string;
|
|
450
|
+
kind: Exclude<CapabilityKind, "pack">;
|
|
451
|
+
source: CapabilitySource;
|
|
452
|
+
name: string;
|
|
453
|
+
description?: string | null;
|
|
454
|
+
category?: string;
|
|
455
|
+
tags?: string[];
|
|
456
|
+
homepageUrl?: string | null;
|
|
457
|
+
endpointUrl?: string | null;
|
|
458
|
+
installUrl?: string | null;
|
|
459
|
+
authModel?: string | null;
|
|
460
|
+
metadata?: Record<string, unknown>;
|
|
461
|
+
};
|
|
462
|
+
type EnableCapabilityInstallationInput = {
|
|
463
|
+
accountId: string;
|
|
464
|
+
workspaceId: string;
|
|
465
|
+
capabilityId: string;
|
|
466
|
+
kind: CapabilityKind;
|
|
467
|
+
config?: Record<string, unknown>;
|
|
468
|
+
metadata?: Record<string, unknown>;
|
|
469
|
+
};
|
|
470
|
+
type EnabledMcpCapabilityServer = {
|
|
471
|
+
capabilityId: string;
|
|
472
|
+
id: string;
|
|
473
|
+
name: string;
|
|
474
|
+
url: string;
|
|
475
|
+
allowedTools?: string[];
|
|
476
|
+
timeoutMs?: number;
|
|
477
|
+
cacheToolsList?: boolean;
|
|
478
|
+
/**
|
|
479
|
+
* Credential request headers stored encrypted at enable time
|
|
480
|
+
* (AES-256-GCM under the workspace-environments key). Decrypted only at
|
|
481
|
+
* the runtime boundary that builds the MCP client; never exposed by the
|
|
482
|
+
* capability API surface.
|
|
483
|
+
*/
|
|
484
|
+
headersEncrypted?: Record<string, string>;
|
|
485
|
+
};
|
|
486
|
+
type EnqueueSessionTurnInput = {
|
|
487
|
+
accountId: string;
|
|
488
|
+
workspaceId: string;
|
|
489
|
+
sessionId: string;
|
|
490
|
+
triggerEventId: string;
|
|
491
|
+
temporalWorkflowId: string;
|
|
492
|
+
source: SessionTurnSource;
|
|
493
|
+
prompt: string;
|
|
494
|
+
resources: ResourceRef[];
|
|
495
|
+
tools: ToolRef[];
|
|
496
|
+
model: string;
|
|
497
|
+
reasoningEffort: ReasoningEffort;
|
|
498
|
+
sandboxBackend: SandboxBackend;
|
|
499
|
+
metadata: Record<string, unknown>;
|
|
500
|
+
};
|
|
501
|
+
type UpdateQueuedSessionTurnInput = Partial<{
|
|
502
|
+
prompt: string;
|
|
503
|
+
resources: ResourceRef[];
|
|
504
|
+
tools: ToolRef[];
|
|
505
|
+
model: string;
|
|
506
|
+
reasoningEffort: ReasoningEffort;
|
|
507
|
+
sandboxBackend: SandboxBackend;
|
|
508
|
+
metadata: Record<string, unknown>;
|
|
509
|
+
}>;
|
|
510
|
+
declare function createFileUpload(db: Database, input: {
|
|
511
|
+
accountId: string;
|
|
512
|
+
workspaceId: string;
|
|
513
|
+
fileId: string;
|
|
514
|
+
filename: string;
|
|
515
|
+
safeFilename: string;
|
|
516
|
+
contentType: string;
|
|
517
|
+
sizeBytes: number;
|
|
518
|
+
sha256?: string | null;
|
|
519
|
+
bucket: string;
|
|
520
|
+
objectKey: string;
|
|
521
|
+
expiresAt: Date;
|
|
522
|
+
}): Promise<{
|
|
523
|
+
file: FileAsset;
|
|
524
|
+
uploadId: string;
|
|
525
|
+
expiresAt: string;
|
|
526
|
+
}>;
|
|
527
|
+
declare function getFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset | null>;
|
|
528
|
+
declare function requireFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset>;
|
|
529
|
+
declare function getFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<{
|
|
530
|
+
id: string;
|
|
531
|
+
status: FileUploadStatus;
|
|
532
|
+
expiresAt: Date;
|
|
533
|
+
file: FileAsset;
|
|
534
|
+
} | null>;
|
|
535
|
+
declare function completeFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<FileAsset>;
|
|
536
|
+
declare function markFileUploadFailed(db: Database, workspaceId: string, uploadId: string, fileId: string): Promise<void>;
|
|
537
|
+
declare function enablePackInstallation(db: Database, input: CreatePackInstallationInput): Promise<PackInstallation>;
|
|
538
|
+
declare function listPackInstallations(db: Database, workspaceId: string): Promise<PackInstallation[]>;
|
|
539
|
+
declare function getPackInstallation(db: Database, workspaceId: string, packId: string): Promise<PackInstallation | null>;
|
|
540
|
+
declare function updatePackInstallationStatus(db: Database, workspaceId: string, packId: string, status: PackInstallationStatus): Promise<PackInstallation>;
|
|
541
|
+
declare function registerWorkspacePack(db: Database, input: RegisterWorkspacePackInput): Promise<{
|
|
542
|
+
pack: WorkspaceRegisteredPack;
|
|
543
|
+
created: boolean;
|
|
544
|
+
}>;
|
|
545
|
+
declare function listWorkspacePacks(db: Database, workspaceId: string): Promise<WorkspaceRegisteredPack[]>;
|
|
546
|
+
declare function getWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<WorkspaceRegisteredPack | null>;
|
|
547
|
+
declare function deleteWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<boolean>;
|
|
548
|
+
declare function upsertCapabilityCatalogItem(db: Database, input: CreateCapabilityCatalogItemInput): Promise<CapabilityCatalogItem>;
|
|
549
|
+
declare function listCapabilityCatalogItems(db: Database, workspaceId: string): Promise<CapabilityCatalogItem[]>;
|
|
550
|
+
declare function getCapabilityCatalogItem(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityCatalogItem | null>;
|
|
551
|
+
declare function enableCapabilityInstallation(db: Database, input: EnableCapabilityInstallationInput): Promise<CapabilityInstallation>;
|
|
552
|
+
declare function disableCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation>;
|
|
553
|
+
declare function listCapabilityInstallations(db: Database, workspaceId: string): Promise<CapabilityInstallation[]>;
|
|
554
|
+
declare function getCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation | null>;
|
|
555
|
+
declare function listEnabledMcpCapabilityServers(db: Database, workspaceId: string): Promise<EnabledMcpCapabilityServer[]>;
|
|
556
|
+
/**
|
|
557
|
+
* Decrypts an enabled capability MCP's stored credential headers. Returns
|
|
558
|
+
* null when the server has none, and "unavailable" when headers exist but
|
|
559
|
+
* cannot be recovered (missing key or failed decryption) — in which case the
|
|
560
|
+
* server must be skipped rather than connected without credentials.
|
|
561
|
+
*/
|
|
562
|
+
declare function decryptedCapabilityHeaders(server: EnabledMcpCapabilityServer, encryptionKey: Uint8Array | null): Record<string, string> | null | "unavailable";
|
|
563
|
+
/**
|
|
564
|
+
* Returns the encrypted credential-header map stored on a capability
|
|
565
|
+
* installation, or null when none is stored. This is the only read path for
|
|
566
|
+
* the ciphertext besides listEnabledMcpCapabilityServers; the generic
|
|
567
|
+
* installation mapping redacts it to header names.
|
|
568
|
+
*/
|
|
569
|
+
declare function getStoredCapabilityHeaderCiphertext(db: Database, workspaceId: string, capabilityId: string): Promise<Record<string, string> | null>;
|
|
570
|
+
declare function mcpServerIdForCapability(capabilityId: string, metadata?: Record<string, unknown>): string;
|
|
571
|
+
declare function createSocialConnection(db: Database, input: CreateSocialConnectionInput): Promise<SocialConnection>;
|
|
572
|
+
declare function listSocialConnections(db: Database, workspaceId: string, limit?: number): Promise<SocialConnection[]>;
|
|
573
|
+
declare function getSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection | null>;
|
|
574
|
+
declare function requireSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection>;
|
|
575
|
+
declare function createSocialPost(db: Database, input: CreateSocialPostInput): Promise<SocialPost>;
|
|
576
|
+
declare function listSocialPosts(db: Database, options: {
|
|
577
|
+
workspaceId: string;
|
|
578
|
+
connectionIds?: string[];
|
|
579
|
+
since?: Date;
|
|
580
|
+
limit?: number;
|
|
581
|
+
}): Promise<SocialPost[]>;
|
|
582
|
+
declare function createScheduledTask(db: Database, input: CreateScheduledTaskInput): Promise<ScheduledTask>;
|
|
583
|
+
declare function updateScheduledTask(db: Database, workspaceId: string, taskId: string, input: UpdateScheduledTaskInput): Promise<ScheduledTask>;
|
|
584
|
+
declare function getScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask | null>;
|
|
585
|
+
declare function requireScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask>;
|
|
586
|
+
declare function listScheduledTasks(db: Database, workspaceId: string, limit?: number): Promise<ScheduledTask[]>;
|
|
587
|
+
declare function deleteScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<void>;
|
|
588
|
+
declare function createScheduledTaskRun(db: Database, input: {
|
|
589
|
+
workspaceId: string;
|
|
590
|
+
taskId: string;
|
|
591
|
+
triggerType: ScheduledTaskTriggerType;
|
|
592
|
+
scheduledAt?: Date | null;
|
|
593
|
+
firedAt?: Date;
|
|
594
|
+
}): Promise<ScheduledTaskRun>;
|
|
595
|
+
declare function updateScheduledTaskRun(db: Database, workspaceId: string, runId: string, input: Partial<{
|
|
596
|
+
status: ScheduledTaskRunStatus;
|
|
597
|
+
sessionId: string | null;
|
|
598
|
+
triggerEventId: string | null;
|
|
599
|
+
error: string | null;
|
|
600
|
+
}>): Promise<ScheduledTaskRun>;
|
|
601
|
+
declare function listScheduledTaskRuns(db: Database, workspaceId: string, taskId: string, limit?: number): Promise<ScheduledTaskRun[]>;
|
|
602
|
+
declare function createWorkspaceEnvironment(db: Database, input: {
|
|
603
|
+
accountId: string;
|
|
604
|
+
workspaceId: string;
|
|
605
|
+
name: string;
|
|
606
|
+
description?: string | null;
|
|
607
|
+
variables?: Array<{
|
|
608
|
+
name: string;
|
|
609
|
+
valueEncrypted: string;
|
|
610
|
+
}>;
|
|
611
|
+
}): Promise<WorkspaceEnvironment>;
|
|
612
|
+
declare function listWorkspaceEnvironments(db: Database, workspaceId: string): Promise<WorkspaceEnvironment[]>;
|
|
613
|
+
declare function getWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<WorkspaceEnvironment | null>;
|
|
614
|
+
declare function getWorkspaceEnvironmentByName(db: Database, workspaceId: string, name: string): Promise<WorkspaceEnvironment | null>;
|
|
615
|
+
declare function updateWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string, input: {
|
|
616
|
+
name?: string;
|
|
617
|
+
description?: string | null;
|
|
618
|
+
}): Promise<WorkspaceEnvironment>;
|
|
619
|
+
declare function deleteWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<boolean>;
|
|
620
|
+
declare function countWorkspaceEnvironments(db: Database, workspaceId: string): Promise<number>;
|
|
621
|
+
declare function countScheduledTasksUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number>;
|
|
622
|
+
declare function countActiveSessionsUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number>;
|
|
623
|
+
declare function setWorkspaceEnvironmentVariable(db: Database, input: {
|
|
624
|
+
accountId: string;
|
|
625
|
+
workspaceId: string;
|
|
626
|
+
environmentId: string;
|
|
627
|
+
name: string;
|
|
628
|
+
valueEncrypted: string;
|
|
629
|
+
}): Promise<WorkspaceEnvironmentVariableMetadata>;
|
|
630
|
+
declare function deleteWorkspaceEnvironmentVariable(db: Database, workspaceId: string, environmentId: string, name: string): Promise<boolean>;
|
|
631
|
+
/**
|
|
632
|
+
* The ONLY helper that selects value_encrypted. Used exclusively by the worker
|
|
633
|
+
* activity that materializes a sandbox for a run whose session carries an
|
|
634
|
+
* environment attachment. Do not call from API routes: values are write-only.
|
|
635
|
+
*/
|
|
636
|
+
declare function getWorkspaceEnvironmentValuesForRun(db: Database, workspaceId: string, environmentId: string): Promise<{
|
|
637
|
+
environment: {
|
|
638
|
+
id: string;
|
|
639
|
+
name: string;
|
|
640
|
+
description: string | null;
|
|
641
|
+
};
|
|
642
|
+
values: Record<string, string>;
|
|
643
|
+
} | null>;
|
|
644
|
+
type WorkspaceEnvironmentForRun = {
|
|
645
|
+
id: string;
|
|
646
|
+
name: string;
|
|
647
|
+
description: string | null;
|
|
648
|
+
values: Record<string, string>;
|
|
649
|
+
};
|
|
650
|
+
/**
|
|
651
|
+
* Load and decrypt the workspace environment attached to a run's session. SHARED
|
|
652
|
+
* by the worker TURN path (apps/worker agent-turn) AND the API-direct ATTACH paths
|
|
653
|
+
* (viewer / Channel-A / desktop / terminal) so a box first warmed by an attach is
|
|
654
|
+
* created with the SAME decrypted workspace-environment values the turn declares —
|
|
655
|
+
* the box-manifest env must match the agent-manifest env or the SDK's
|
|
656
|
+
* `validateNoEnvironmentDelta` throws when the agent injects its manifest into the
|
|
657
|
+
* resumed non-owned box.
|
|
658
|
+
*
|
|
659
|
+
* `environmentId === null` is the unattached path: zero DB work and behavior
|
|
660
|
+
* byte-identical to deployments without this feature. Attached runs fail closed: a
|
|
661
|
+
* missing key or a deleted environment throws (names/ids only in messages) instead
|
|
662
|
+
* of silently running without the secrets the run expects.
|
|
663
|
+
*/
|
|
664
|
+
declare function loadWorkspaceEnvironmentForRun(db: Database, settings: Settings, workspaceId: string, environmentId: string | null): Promise<WorkspaceEnvironmentForRun | null>;
|
|
665
|
+
type CodexCredentialTokens = {
|
|
666
|
+
accessToken: string;
|
|
667
|
+
refreshToken: string;
|
|
668
|
+
idToken: string;
|
|
669
|
+
};
|
|
670
|
+
type CodexCredentialForRun = {
|
|
671
|
+
id: string;
|
|
672
|
+
version: number;
|
|
673
|
+
workspaceId: string;
|
|
674
|
+
tokens: CodexCredentialTokens;
|
|
675
|
+
chatgptAccountId: string | null;
|
|
676
|
+
scopes: string | null;
|
|
677
|
+
planType: string | null;
|
|
678
|
+
isFedramp: boolean;
|
|
679
|
+
expiresAt: Date | null;
|
|
680
|
+
lastRefreshAt: Date | null;
|
|
681
|
+
status: string;
|
|
682
|
+
lastError: string | null;
|
|
683
|
+
};
|
|
684
|
+
/**
|
|
685
|
+
* Login / rotation write (multi-account P1). Caller passes the PRE-encrypted
|
|
686
|
+
* credential blob. Keyed on the composite partial index (workspace, chatgpt
|
|
687
|
+
* account): re-connecting the SAME ChatGPT account updates that row in place
|
|
688
|
+
* (re-asserts account_id, bumps version); connecting a NEW account inserts a new
|
|
689
|
+
* row. Returns the row id + whether it was newly inserted. The route — not this
|
|
690
|
+
* accessor — auto-activates a brand-new first account and ensures the
|
|
691
|
+
* rotation-settings row exists.
|
|
692
|
+
*/
|
|
693
|
+
declare function upsertCodexSubscriptionCredential(db: Database, input: {
|
|
694
|
+
accountId: string;
|
|
695
|
+
workspaceId: string;
|
|
696
|
+
credentialEncrypted: string;
|
|
697
|
+
chatgptAccountId: string | null;
|
|
698
|
+
scopes: string | null;
|
|
699
|
+
planType: string | null;
|
|
700
|
+
isFedramp: boolean;
|
|
701
|
+
expiresAt: Date | null;
|
|
702
|
+
lastRefreshAt: Date | null;
|
|
703
|
+
accountEmail?: string | null;
|
|
704
|
+
label?: string | null;
|
|
705
|
+
}): Promise<{
|
|
706
|
+
id: string;
|
|
707
|
+
isNew: boolean;
|
|
708
|
+
}>;
|
|
709
|
+
/**
|
|
710
|
+
* The ONLY decrypt-read accessor. Fails closed. Never call from an API route that
|
|
711
|
+
* returns the result.
|
|
712
|
+
*
|
|
713
|
+
* The run's account is the resolved pin-or-active credential id, not LIMIT 1: the
|
|
714
|
+
* caller (worker) resolves the effective credential id and passes it here so a
|
|
715
|
+
* pinned session loads its SPECIFIC account. RLS still constrains the row to the
|
|
716
|
+
* workspace; an unknown/disconnected id returns null → the caller treats it as
|
|
717
|
+
* "needs relogin / re-pick".
|
|
718
|
+
*/
|
|
719
|
+
declare function loadCodexCredentialForRun(db: Database, settings: Settings, workspaceId: string, credentialId: string): Promise<CodexCredentialForRun | null>;
|
|
720
|
+
/**
|
|
721
|
+
* Persist rotated tokens after a successful refresh. Caller pre-encrypts.
|
|
722
|
+
*
|
|
723
|
+
* COMPARE-AND-SET (P1-c): the write is guarded by the (id, version) the resolver
|
|
724
|
+
* loaded. If a disconnect→reconnect replaced/rotated the row between the load and
|
|
725
|
+
* this write, the guard matches 0 rows and we DO NOT clobber the freshly
|
|
726
|
+
* reconnected credential with tokens from the now-defunct family. Returns true
|
|
727
|
+
* iff the guarded row was updated; false means "credential changed under me —
|
|
728
|
+
* the rotation is moot, drop it."
|
|
729
|
+
*/
|
|
730
|
+
declare function recordCodexTokenRefresh(db: Database, input: {
|
|
731
|
+
id: string;
|
|
732
|
+
version: number;
|
|
733
|
+
workspaceId: string;
|
|
734
|
+
credentialEncrypted: string;
|
|
735
|
+
expiresAt: Date | null;
|
|
736
|
+
lastRefreshAt: Date;
|
|
737
|
+
}): Promise<boolean>;
|
|
738
|
+
/**
|
|
739
|
+
* Surface a permanent or transient failure on a SPECIFIC credential row.
|
|
740
|
+
*
|
|
741
|
+
* COMPARE-AND-SET (P1-c): the status is stamped only if the row STILL matches the
|
|
742
|
+
* (id, version) the resolver loaded. This stops a refresh that began before a
|
|
743
|
+
* disconnect→reconnect (or a manual account switch) from stamping `needs_relogin`
|
|
744
|
+
* on the brand-new, good credential — with N accounts per workspace a
|
|
745
|
+
* workspace-wide write would be flat-out wrong (it would scribble on every
|
|
746
|
+
* account). Returns true iff the guarded row was updated.
|
|
747
|
+
*/
|
|
748
|
+
declare function setCodexCredentialStatus(db: Database, workspaceId: string, status: "active" | "needs_relogin" | "error", lastError: string | null, target: {
|
|
749
|
+
id: string;
|
|
750
|
+
version: number;
|
|
751
|
+
}): Promise<boolean>;
|
|
752
|
+
/**
|
|
753
|
+
* Metadata-only read for API routes, repointed to the per-workspace ACTIVE
|
|
754
|
+
* credential. NEVER selects credential_encrypted.
|
|
755
|
+
*
|
|
756
|
+
* Reads codex_rotation_settings.active_credential_id and joins the credential by
|
|
757
|
+
* id (deterministic). If the pointer is NULL but credentials exist (the
|
|
758
|
+
* mid-disconnect window), it falls back to the most-recently-connected row and
|
|
759
|
+
* lazily repairs the pointer so the next read is deterministic. The returned
|
|
760
|
+
* `credentialId` is the active row's id (null when no credential exists at all).
|
|
761
|
+
*/
|
|
762
|
+
declare function getCodexCredentialStatus(db: Database, workspaceId: string): Promise<{
|
|
763
|
+
connected: boolean;
|
|
764
|
+
credentialId: string | null;
|
|
765
|
+
chatgptAccountId: string | null;
|
|
766
|
+
scopes: string | null;
|
|
767
|
+
planType: string | null;
|
|
768
|
+
status: string;
|
|
769
|
+
expiresAt: Date | null;
|
|
770
|
+
lastRefreshAt: Date | null;
|
|
771
|
+
lastError: string | null;
|
|
772
|
+
} | null>;
|
|
773
|
+
/**
|
|
774
|
+
* Single source of truth for "this workspace has an ACTIVE ChatGPT/Codex
|
|
775
|
+
* subscription connected AND the feature is enabled for this deployment."
|
|
776
|
+
*
|
|
777
|
+
* This is the SAME condition `settingsWithCodexCredential` (worker) uses to
|
|
778
|
+
* decide whether to inject the synthetic codex-subscription provider, so billing
|
|
779
|
+
* and provider-injection cannot drift. Metadata-only read (never the secret).
|
|
780
|
+
*/
|
|
781
|
+
declare function workspaceCodexSubscriptionActive(db: Database, settings: Pick<Settings, "codexSubscriptionEnabled">, workspaceId: string): Promise<boolean>;
|
|
782
|
+
/**
|
|
783
|
+
* CANONICAL "is this a Codex-billed turn?" predicate.
|
|
784
|
+
*
|
|
785
|
+
* True iff: the turn's model is a `codex/<slug>` id (`isCodexBilledModel`) AND
|
|
786
|
+
* the deployment flag is on AND the workspace has an ACTIVE credential. A true
|
|
787
|
+
* result means the turn is paid by the USER's ChatGPT/Codex plan and MUST consume
|
|
788
|
+
* ZERO OpenGeni credits: callers skip the credit-balance / model-cost / token
|
|
789
|
+
* gates and skip OpenGeni pricing + credit debit.
|
|
790
|
+
*
|
|
791
|
+
* The prefix ALONE never returns true: an unconnected user typing `codex/...`
|
|
792
|
+
* gets the normal gates (and the worker fails the turn for a missing credential),
|
|
793
|
+
* so there is no free/uncapped-run bypass.
|
|
794
|
+
*/
|
|
795
|
+
declare function isCodexBilledTurn(input: {
|
|
796
|
+
db: Database;
|
|
797
|
+
settings: Pick<Settings, "codexSubscriptionEnabled">;
|
|
798
|
+
workspaceId: string;
|
|
799
|
+
model: string | null | undefined;
|
|
800
|
+
/**
|
|
801
|
+
* Precomputed `workspaceCodexSubscriptionActive` result (P2-b). When the caller
|
|
802
|
+
* already resolved the active flag for provider injection, pass it here so the
|
|
803
|
+
* billed-turn predicate and the routing overlay read the credential ONCE and
|
|
804
|
+
* cannot disagree across a concurrent disconnect/reconnect — a drift that would
|
|
805
|
+
* either wrongly debit OpenGeni credits for a ChatGPT-paid turn or the inverse.
|
|
806
|
+
*/
|
|
807
|
+
active?: boolean;
|
|
808
|
+
}): Promise<boolean>;
|
|
809
|
+
type CodexAccountStatus = {
|
|
810
|
+
id: string;
|
|
811
|
+
chatgptAccountId: string | null;
|
|
812
|
+
label: string | null;
|
|
813
|
+
accountEmail: string | null;
|
|
814
|
+
planType: string | null;
|
|
815
|
+
status: string;
|
|
816
|
+
isActive: boolean;
|
|
817
|
+
expiresAt: Date | null;
|
|
818
|
+
lastRefreshAt: Date | null;
|
|
819
|
+
lastError: string | null;
|
|
820
|
+
primaryUsedPercent: number | null;
|
|
821
|
+
primaryResetAt: Date | null;
|
|
822
|
+
secondaryUsedPercent: number | null;
|
|
823
|
+
secondaryResetAt: Date | null;
|
|
824
|
+
usageCheckedAt: Date | null;
|
|
825
|
+
exhaustedUntil: Date | null;
|
|
826
|
+
connectorNamespaces: string[] | null;
|
|
827
|
+
connectorsCheckedAt: Date | null;
|
|
828
|
+
};
|
|
829
|
+
/**
|
|
830
|
+
* Metadata-only list of every connected Codex account in the workspace, for the
|
|
831
|
+
* accounts UI + the worker's selection resolver. NEVER decrypts. `isActive` marks
|
|
832
|
+
* the workspace active pointer. Ordered by created_at ASC (stable list order).
|
|
833
|
+
*/
|
|
834
|
+
declare function listCodexAccountStatuses(db: Database, workspaceId: string): Promise<CodexAccountStatus[]>;
|
|
835
|
+
/** The P2 usage-cache snapshot written by the refreshing usage wrapper. */
|
|
836
|
+
type CodexAccountUsageSnapshot = {
|
|
837
|
+
primaryUsedPercent: number | null;
|
|
838
|
+
primaryResetAt: Date | null;
|
|
839
|
+
secondaryUsedPercent: number | null;
|
|
840
|
+
secondaryResetAt: Date | null;
|
|
841
|
+
checkedAt: Date;
|
|
842
|
+
};
|
|
843
|
+
/**
|
|
844
|
+
* Cache-write for P2 quota bars: persist the five plaintext usage columns on a
|
|
845
|
+
* SPECIFIC credential row. NEVER touches credential_encrypted. RLS-scoped, guarded
|
|
846
|
+
* by (id, workspace_id) so it can only write a row the workspace owns. Returns true
|
|
847
|
+
* iff a row was updated (false ⇒ the credential was disconnected under us — the
|
|
848
|
+
* snapshot is moot, drop it). This is the only writer of the usage_checked_at TTL
|
|
849
|
+
* clock that `listCodexAccountStatuses` reads back.
|
|
850
|
+
*/
|
|
851
|
+
declare function recordCodexAccountUsage(db: Database, workspaceId: string, credentialId: string, snapshot: CodexAccountUsageSnapshot): Promise<boolean>;
|
|
852
|
+
type CodexRotationSettings = {
|
|
853
|
+
activeCredentialId: string | null;
|
|
854
|
+
rotationEnabled: boolean;
|
|
855
|
+
rotationStrategy: string;
|
|
856
|
+
};
|
|
857
|
+
/** The per-workspace rotation/active-pointer row (null when none exists yet). */
|
|
858
|
+
declare function getCodexRotationSettings(db: Database, workspaceId: string): Promise<CodexRotationSettings | null>;
|
|
859
|
+
/** Idempotently ensure the per-workspace rotation-settings row exists. */
|
|
860
|
+
declare function ensureCodexRotationSettings(db: Database, accountId: string, workspaceId: string): Promise<void>;
|
|
861
|
+
/**
|
|
862
|
+
* THE manual-switch primitive (workspace scope). Validates the credential id
|
|
863
|
+
* belongs to the workspace, then one-cell UPDATEs active_credential_id. Returns
|
|
864
|
+
* false if the id is unknown (so the route can 404).
|
|
865
|
+
*/
|
|
866
|
+
declare function setActiveCodexCredential(db: Database, workspaceId: string, credentialId: string): Promise<boolean>;
|
|
867
|
+
/**
|
|
868
|
+
* P3 rotation cooldown writer: stamp `exhausted_until` on a SPECIFIC credential row so the
|
|
869
|
+
* rotation engine treats it as cooling-down (capped) until `until`. Pass `until = null` to
|
|
870
|
+
* clear the cooldown. Modeled EXACTLY on recordCodexAccountUsage: RLS-scoped, guarded by
|
|
871
|
+
* (id, workspace_id), and — critically — NO `version` bump and NO `updatedAt` touch, so it can
|
|
872
|
+
* never race the (id, version) token-refresh CAS in recordCodexTokenRefresh / setCodexCredentialStatus.
|
|
873
|
+
* Returns true iff a row was updated (false ⇒ the credential was disconnected under us).
|
|
874
|
+
*/
|
|
875
|
+
declare function setCodexCredentialExhausted(db: Database, workspaceId: string, credentialId: string, until: Date | null): Promise<boolean>;
|
|
876
|
+
/**
|
|
877
|
+
* P3 reactive-rotation boundedness (Finding 1b): the number of CONSECUTIVE rotated
|
|
878
|
+
* 429-failover turns since the session last had a SUCCESSFUL turn. Counts
|
|
879
|
+
* `turn.failed` events carrying the `rotated` marker that occurred AFTER the most
|
|
880
|
+
* recent `turn.completed` event (the natural reset anchor — any successful turn
|
|
881
|
+
* moves the anchor past every prior failover, so the streak resets to 0). The
|
|
882
|
+
* reactive 429 catch consults this to bound its otherwise-0-delay re-dispatch:
|
|
883
|
+
* once the streak exceeds ~(connected accounts + margin) the path degrades to a
|
|
884
|
+
* fixed positive idle instead of another hot re-dispatch (invariant 4: NO THRASH),
|
|
885
|
+
* covering the double-fault where a cooldown write did not persist AND the 429
|
|
886
|
+
* carried no usage headers. Derived from persisted events so it is correct across
|
|
887
|
+
* the Temporal re-dispatch (each failover is a NEW turn, but its event survives).
|
|
888
|
+
*/
|
|
889
|
+
declare function countConsecutiveReactiveRotations(db: Database, workspaceId: string, sessionId: string): Promise<number>;
|
|
890
|
+
/**
|
|
891
|
+
* P4 connector-set cache writer: persist the set of ORIGINAL-dotted connector
|
|
892
|
+
* namespaces a SPECIFIC credential exposes via codex_apps (+ the freshness clock).
|
|
893
|
+
* Modeled byte-for-byte on recordCodexAccountUsage / setCodexCredentialExhausted:
|
|
894
|
+
* RLS-scoped, guarded by (id, workspace_id), and — critically — NO `version` bump and
|
|
895
|
+
* NO `updatedAt` touch, so it can never race the (id, version) token-refresh CAS.
|
|
896
|
+
*
|
|
897
|
+
* The CALLER must only invoke this with a NON-EMPTY set: codex_apps connects
|
|
898
|
+
* best-effort (a transient failure yields an empty tools/list), and overwriting a
|
|
899
|
+
* known non-empty set with [] would falsely "drop" coverage on a flaky turn. A
|
|
900
|
+
* genuinely connector-less account stays null (the ranker treats null as unknown).
|
|
901
|
+
* Returns true iff a row was updated (false ⇒ the credential was disconnected under us).
|
|
902
|
+
*/
|
|
903
|
+
declare function recordCodexAccountConnectors(db: Database, workspaceId: string, credentialId: string, namespaces: string[]): Promise<boolean>;
|
|
904
|
+
/** The supported rotation strategies (P3). */
|
|
905
|
+
declare const CODEX_ROTATION_STRATEGIES: readonly ["most_remaining", "round_robin", "drain_then_next"];
|
|
906
|
+
type CodexRotationStrategy = (typeof CODEX_ROTATION_STRATEGIES)[number];
|
|
907
|
+
/**
|
|
908
|
+
* P3 rotation-settings write path: one-cell UPDATE of `rotation_enabled` and/or
|
|
909
|
+
* `rotation_strategy` on the per-workspace row. Validates the strategy enum (rejects unknown).
|
|
910
|
+
* Guarded by workspaceId; ensureCodexRotationSettings guarantees the row exists. Returns the
|
|
911
|
+
* effective settings after the patch (null when no row exists yet — caller should ensure first).
|
|
912
|
+
*/
|
|
913
|
+
declare function updateCodexRotationSettings(db: Database, workspaceId: string, patch: {
|
|
914
|
+
rotationEnabled?: boolean;
|
|
915
|
+
rotationStrategy?: CodexRotationStrategy;
|
|
916
|
+
}): Promise<CodexRotationSettings | null>;
|
|
917
|
+
/** P1 rename (label only); P3 widens to rotation fields. */
|
|
918
|
+
declare function renameCodexAccount(db: Database, workspaceId: string, credentialId: string, label: string | null): Promise<boolean>;
|
|
919
|
+
type SessionCodexState = {
|
|
920
|
+
pinnedCredentialId: string | null;
|
|
921
|
+
lastCredentialId: string | null;
|
|
922
|
+
};
|
|
923
|
+
/** The session's pin + last-ran-on Codex account (drives the worker resolver + indicator). */
|
|
924
|
+
declare function getSessionCodexState(db: Database, workspaceId: string, sessionId: string): Promise<SessionCodexState | null>;
|
|
925
|
+
/**
|
|
926
|
+
* Per-session pin (manual override). pinnedCredentialId === null clears the pin
|
|
927
|
+
* (follow the workspace active). Validates the id belongs to the workspace when
|
|
928
|
+
* non-null. Returns false if the session is unknown or the id is invalid.
|
|
929
|
+
*/
|
|
930
|
+
declare function setSessionCodexPin(db: Database, workspaceId: string, sessionId: string, pinnedCredentialId: string | null): Promise<boolean>;
|
|
931
|
+
/** Written by the worker at the turn boundary; drives the in-session indicator. */
|
|
932
|
+
declare function recordSessionActiveCodexCredential(db: Database, workspaceId: string, sessionId: string, credentialId: string): Promise<void>;
|
|
933
|
+
/**
|
|
934
|
+
* Disconnect ONE account. DELETE WHERE id = credentialId AND workspace_id. If it
|
|
935
|
+
* was the active pointer, the FK ON DELETE SET NULL clears it; this fn then
|
|
936
|
+
* re-picks the most-recently-connected remaining account as active, atomically in
|
|
937
|
+
* the same RLS txn. Returns whether a row was removed + the new active id.
|
|
938
|
+
*/
|
|
939
|
+
declare function disconnectCodexAccount(db: Database, workspaceId: string, credentialId: string): Promise<{
|
|
940
|
+
removed: boolean;
|
|
941
|
+
newActiveCredentialId: string | null;
|
|
942
|
+
}>;
|
|
943
|
+
/** Legacy "disconnect all" (old workspace-wide behavior). Returns rows removed. */
|
|
944
|
+
declare function disconnectAllCodexAccounts(db: Database, workspaceId: string): Promise<number>;
|
|
945
|
+
declare function recordAuditEvent(db: Database, input: {
|
|
946
|
+
accountId: string;
|
|
947
|
+
workspaceId?: string | null;
|
|
948
|
+
subjectId?: string | null;
|
|
949
|
+
action: string;
|
|
950
|
+
targetType?: string | null;
|
|
951
|
+
targetId?: string | null;
|
|
952
|
+
metadata?: Record<string, unknown>;
|
|
953
|
+
}): Promise<void>;
|
|
954
|
+
declare function createSession(db: Database, input: {
|
|
955
|
+
accountId: string;
|
|
956
|
+
workspaceId: string;
|
|
957
|
+
initialMessage: string;
|
|
958
|
+
resources: ResourceRef[];
|
|
959
|
+
tools?: ToolRef[];
|
|
960
|
+
metadata: Record<string, unknown>;
|
|
961
|
+
model: string;
|
|
962
|
+
sandboxBackend: SandboxBackend;
|
|
963
|
+
environmentId?: string | null;
|
|
964
|
+
firstPartyMcpPermissions?: Permission[] | null;
|
|
965
|
+
parentSessionId?: string | null;
|
|
966
|
+
createIdempotencyKey?: string | null;
|
|
967
|
+
sandboxGroupId?: string | null;
|
|
968
|
+
sandboxOs?: SandboxOs;
|
|
969
|
+
}): Promise<Session>;
|
|
970
|
+
/**
|
|
971
|
+
* Inserts a session under a workspace-scoped CREATE idempotency key, collapsing
|
|
972
|
+
* a concurrent race on the same key to a single row. On the unique-violation
|
|
973
|
+
* the conflicting insert does nothing (`onConflictDoNothing` on the partial
|
|
974
|
+
* unique index) and the now-existing winning row is fetched and returned, so
|
|
975
|
+
* two near-simultaneous creates with the same key yield ONE session and both
|
|
976
|
+
* callers see the same id. `created` distinguishes the winner (true: this call
|
|
977
|
+
* inserted and must run the rest of the start flow) from the loser/dup (false:
|
|
978
|
+
* the row already existed and must be returned as-is).
|
|
979
|
+
*/
|
|
980
|
+
declare function createSessionWithIdempotencyKey(db: Database, input: {
|
|
981
|
+
accountId: string;
|
|
982
|
+
workspaceId: string;
|
|
983
|
+
initialMessage: string;
|
|
984
|
+
resources: ResourceRef[];
|
|
985
|
+
tools?: ToolRef[];
|
|
986
|
+
metadata: Record<string, unknown>;
|
|
987
|
+
model: string;
|
|
988
|
+
sandboxBackend: SandboxBackend;
|
|
989
|
+
environmentId?: string | null;
|
|
990
|
+
firstPartyMcpPermissions?: Permission[] | null;
|
|
991
|
+
parentSessionId?: string | null;
|
|
992
|
+
createIdempotencyKey: string;
|
|
993
|
+
sandboxGroupId?: string | null;
|
|
994
|
+
sandboxOs?: SandboxOs;
|
|
995
|
+
}): Promise<{
|
|
996
|
+
session: Session;
|
|
997
|
+
created: boolean;
|
|
998
|
+
}>;
|
|
999
|
+
declare function getSessionByCreateIdempotencyKey(db: Database, workspaceId: string, createIdempotencyKey: string): Promise<Session | null>;
|
|
1000
|
+
declare function getSession(db: Database, workspaceId: string, sessionId: string): Promise<Session | null>;
|
|
1001
|
+
/**
|
|
1002
|
+
* Resolve ANY session that belongs to a shared-sandbox group (addendum 05 §D.3,
|
|
1003
|
+
* stress (e)). Used by the create-session `sandbox:{groupId}` join path to (1)
|
|
1004
|
+
* prove the group exists and (2) inherit its box's (backend, os).
|
|
1005
|
+
*
|
|
1006
|
+
* `workspaceId` is a MANDATORY access boundary, NOT optional: the group uuid is
|
|
1007
|
+
* caller-supplied, so the workspace filter (inside RLS) is what forbids a
|
|
1008
|
+
* cross-workspace join — a foreign group returns null → the caller 404s. The
|
|
1009
|
+
* group uuid itself is never an authorization boundary. Returns the first member
|
|
1010
|
+
* session (any one suffices to read the shared box's backend/os); null when the
|
|
1011
|
+
* group has no session in this workspace.
|
|
1012
|
+
*/
|
|
1013
|
+
declare function getAnySessionInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Session | null>;
|
|
1014
|
+
/**
|
|
1015
|
+
* The DISTINCT environmentIds across a group's member sessions (workspace-
|
|
1016
|
+
* scoped; null = no environment attached). The env-aware create check compares
|
|
1017
|
+
* a joiner against EVERY member — an arbitrary single member (getAnySessionInGroup)
|
|
1018
|
+
* makes the compatibility verdict nondeterministic for legacy env-blind groups
|
|
1019
|
+
* whose members carry mixed environmentIds.
|
|
1020
|
+
*/
|
|
1021
|
+
declare function listDistinctEnvironmentIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Array<string | null>>;
|
|
1022
|
+
declare function listSessions(db: Database, workspaceId: string, limit?: number): Promise<Session[]>;
|
|
1023
|
+
/**
|
|
1024
|
+
* Count sessions still attached to a live Temporal workflow: queued, running,
|
|
1025
|
+
* or awaiting an approval (requires_action). idle has no running execution and
|
|
1026
|
+
* failed/cancelled are terminal, so neither blocks a workspace delete. The
|
|
1027
|
+
* delete path uses this to refuse (409) while a session could still be running
|
|
1028
|
+
* in Temporal, since there is no clean session-terminate to call first.
|
|
1029
|
+
*/
|
|
1030
|
+
declare function countActiveSessionsForWorkspace(db: Database, workspaceId: string): Promise<number>;
|
|
1031
|
+
declare function requireSession(db: Database, workspaceId: string, sessionId: string): Promise<Session>;
|
|
1032
|
+
declare function listSessionEvents(db: Database, workspaceId: string, sessionId: string, after?: number, limit?: number): Promise<SessionEvent[]>;
|
|
1033
|
+
declare function getSessionEvent(db: Database, workspaceId: string, eventId: string): Promise<SessionEvent | null>;
|
|
1034
|
+
declare function getLatestRunState(db: Database, workspaceId: string, sessionId: string): Promise<{
|
|
1035
|
+
id: string;
|
|
1036
|
+
serializedRunState: string;
|
|
1037
|
+
pendingApprovals: unknown[];
|
|
1038
|
+
frozenCodexCredentialId: string | null;
|
|
1039
|
+
} | null>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Append conversation items (verbatim SDK AgentInputItems) to the session's
|
|
1042
|
+
* history. Idempotent on (workspace, session, position): concurrent or
|
|
1043
|
+
* repeated writers (streaming writes + turn-end reconciliation) converge
|
|
1044
|
+
* instead of duplicating.
|
|
1045
|
+
*/
|
|
1046
|
+
declare function appendSessionHistoryItems(db: Database, input: {
|
|
1047
|
+
accountId: string;
|
|
1048
|
+
workspaceId: string;
|
|
1049
|
+
sessionId: string;
|
|
1050
|
+
turnId?: string | null;
|
|
1051
|
+
producerCodexCredentialId?: string | null;
|
|
1052
|
+
items: Array<{
|
|
1053
|
+
position: number;
|
|
1054
|
+
item: Record<string, unknown>;
|
|
1055
|
+
}>;
|
|
1056
|
+
}): Promise<void>;
|
|
1057
|
+
declare function getSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{
|
|
1058
|
+
position: number;
|
|
1059
|
+
item: Record<string, unknown>;
|
|
1060
|
+
}>>;
|
|
1061
|
+
/**
|
|
1062
|
+
* The LIVE conversation-truth read path: only active rows, position-ordered.
|
|
1063
|
+
* After a client-side context compaction this returns [active summary,
|
|
1064
|
+
* ...active recent tail]; with no compaction yet it equals
|
|
1065
|
+
* getSessionHistoryItems. The model-facing read path uses this so superseded
|
|
1066
|
+
* (summarized-away) prefix rows are excluded while the full transcript stays in
|
|
1067
|
+
* the table as an audit trail.
|
|
1068
|
+
*/
|
|
1069
|
+
declare function getActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{
|
|
1070
|
+
position: number;
|
|
1071
|
+
item: Record<string, unknown>;
|
|
1072
|
+
producerCodexCredentialId: string | null;
|
|
1073
|
+
}>>;
|
|
1074
|
+
/**
|
|
1075
|
+
* Count of ACTIVE (live, model-facing) history rows for a session. This is the
|
|
1076
|
+
* length of the history the next turn is seeded from — the dual-write slice
|
|
1077
|
+
* index — which after a compaction is far smaller than the total persisted-row
|
|
1078
|
+
* count (countSessionHistoryItems still includes the superseded prefix).
|
|
1079
|
+
*/
|
|
1080
|
+
declare function countActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number>;
|
|
1081
|
+
/**
|
|
1082
|
+
* Pure TypeScript SPEC for the one-time orphan repair (migration 0014),
|
|
1083
|
+
* mirroring its SQL WHERE clause so the deletion rule is unit-testable without a
|
|
1084
|
+
* database. Given the ACTIVE history rows of a single session in position order,
|
|
1085
|
+
* returns the indices of the orphaned tool-call RESULT rows the repair deletes.
|
|
1086
|
+
*
|
|
1087
|
+
* An orphan is a result-type row (function_call_result / computer_call_result /
|
|
1088
|
+
* shell_call_output / apply_patch_call_output) with no matching CALL of the
|
|
1089
|
+
* paired type, same correlation id (camelCase `callId` OR snake_case `call_id`),
|
|
1090
|
+
* at a STRICTLY EARLIER position in the same session. This is exactly the
|
|
1091
|
+
* session-bricking row the Responses API 400s on ("No tool call found for
|
|
1092
|
+
* function call output").
|
|
1093
|
+
*
|
|
1094
|
+
* DANGLING CALLS (a call with no result yet) are intentionally NOT returned: a
|
|
1095
|
+
* call awaiting a not-yet-settled result is valid, not corruption. Only unpaired
|
|
1096
|
+
* results are removed.
|
|
1097
|
+
*
|
|
1098
|
+
* EXISTENCE, not consumption: like the migration's `NOT EXISTS (... earlier
|
|
1099
|
+
* call ...)`, a result is kept whenever ANY earlier matching call exists. A
|
|
1100
|
+
* second result that re-uses a call_id already settled earlier is therefore NOT
|
|
1101
|
+
* flagged here (a matching call still exists before it) — this conservative
|
|
1102
|
+
* choice matches the SQL exactly and never deletes a row whose call is present;
|
|
1103
|
+
* the read-path sanitizer (which consumes calls one-for-one) still drops such a
|
|
1104
|
+
* rare duplicate in-memory, so the model request stays valid regardless.
|
|
1105
|
+
*
|
|
1106
|
+
* Callers pass rows already ordered by position. The earlier-position test is
|
|
1107
|
+
* by array order (the SQL orders by the numeric position column, which the read
|
|
1108
|
+
* path also orders by), so identical inputs yield identical decisions.
|
|
1109
|
+
*/
|
|
1110
|
+
declare function orphanedResultRowIndicesForRepair(activeRowsInPositionOrder: ReadonlyArray<{
|
|
1111
|
+
item: Record<string, unknown>;
|
|
1112
|
+
}>): number[];
|
|
1113
|
+
/**
|
|
1114
|
+
* Apply a client-side context compaction as an atomic, audit-preserving write:
|
|
1115
|
+
*
|
|
1116
|
+
* - supersede (set active=false) every active row whose position lies in
|
|
1117
|
+
* [0, boundaryPosition) — i.e. the summarized prefix — EXCLUDING the tail.
|
|
1118
|
+
* Rows are never deleted.
|
|
1119
|
+
* - insert ONE active synthetic summary row at `summaryPosition` (a FRACTIONAL
|
|
1120
|
+
* position — boundaryPosition - 0.5 — that sorts immediately before the kept
|
|
1121
|
+
* tail and collides with NO existing row, so no real prefix row is ever
|
|
1122
|
+
* overwritten). Idempotent on position: a retry that finds the summary row
|
|
1123
|
+
* already there does not duplicate it (it only re-activates the existing
|
|
1124
|
+
* summary row at that fractional position) and — crucially — never mutates
|
|
1125
|
+
* the real row at boundaryPosition - 1.
|
|
1126
|
+
*
|
|
1127
|
+
* The caller computes the boundary from the orphan-safe planner so no tool-call
|
|
1128
|
+
* pair straddles the cut. `summaryPosition` must be < boundaryPosition (between
|
|
1129
|
+
* the last superseded prefix row and the kept tail), guaranteeing it sorts
|
|
1130
|
+
* before the tail. Because positions are whole numbers and summaries are
|
|
1131
|
+
* half-steps, the summary's fractional position can never equal a real row.
|
|
1132
|
+
*/
|
|
1133
|
+
declare function applyContextCompaction(db: Database, input: {
|
|
1134
|
+
accountId: string;
|
|
1135
|
+
workspaceId: string;
|
|
1136
|
+
sessionId: string;
|
|
1137
|
+
turnId?: string | null;
|
|
1138
|
+
/** Active prefix rows with position < boundaryPosition get superseded. */
|
|
1139
|
+
boundaryPosition: number;
|
|
1140
|
+
/** Fractional position for the new summary row (must be < boundaryPosition). */
|
|
1141
|
+
summaryPosition: number;
|
|
1142
|
+
summaryItem: Record<string, unknown>;
|
|
1143
|
+
}): Promise<void>;
|
|
1144
|
+
/**
|
|
1145
|
+
* The next free WHOLE-NUMBER history position for a session: one past the
|
|
1146
|
+
* largest existing position (active or superseded), floored so the synthetic
|
|
1147
|
+
* summary's fractional half-step never shifts the count. The dual-write
|
|
1148
|
+
* watermark uses this to append new rows at fresh absolute positions, decoupled
|
|
1149
|
+
* from the in-memory history length (which, after a compaction, is far shorter
|
|
1150
|
+
* than the total persisted-row count and so cannot serve as the next position).
|
|
1151
|
+
*/
|
|
1152
|
+
declare function nextSessionHistoryPosition(db: Database, workspaceId: string, sessionId: string): Promise<number>;
|
|
1153
|
+
/**
|
|
1154
|
+
* Record the actual input-token count of the most recent turn's final model
|
|
1155
|
+
* call, for the next turn's pre-read compaction trigger.
|
|
1156
|
+
*/
|
|
1157
|
+
declare function setSessionLastInputTokens(db: Database, workspaceId: string, sessionId: string, lastInputTokens: number): Promise<void>;
|
|
1158
|
+
/**
|
|
1159
|
+
* The neutral marker written by clearSessionContext as the sole active history
|
|
1160
|
+
* row. It keeps getActiveSessionHistoryItems().length > 0 so the items read
|
|
1161
|
+
* path (run-input.ts messageInput) stays selected and never falls through to
|
|
1162
|
+
* the getLatestRunState blob — that fallback is the resurrection vector a clear
|
|
1163
|
+
* must defeat. A plain user message is a valid, sanitizer-clean item.
|
|
1164
|
+
*/
|
|
1165
|
+
declare function clearedContextMarkerItem(): Record<string, unknown>;
|
|
1166
|
+
/**
|
|
1167
|
+
* The sentinel serializedRunState written by clearSessionContext, re-exported
|
|
1168
|
+
* from @opengeni/contracts so the writer (here) and the readers (run-input /
|
|
1169
|
+
* runtime) share one definition. It is audit-honest (carries no prior
|
|
1170
|
+
* conversation) and is NOT a real Agents-SDK run state — it has no
|
|
1171
|
+
* `$schemaVersion`/history, so `RunState.fromString` throws on it.
|
|
1172
|
+
*
|
|
1173
|
+
* Both run-state read paths therefore guard against it explicitly via
|
|
1174
|
+
* {@link isClearedRunStateBlob}:
|
|
1175
|
+
* - the message path (run-input messageInput) honors it in BOTH items and
|
|
1176
|
+
* run_state history modes — in items mode the boundary marker keeps the
|
|
1177
|
+
* active read non-empty so the blob is never reached, and in run_state mode
|
|
1178
|
+
* the sentinel is recognized and treated as a fresh empty start;
|
|
1179
|
+
* - the approval path is additionally refused by the API for mid-turn /
|
|
1180
|
+
* requires_action sessions, so it never sees the sentinel.
|
|
1181
|
+
* Stored so getLatestRunState (the run_state-source read path) reflects the
|
|
1182
|
+
* clear instead of resurrecting the pre-clear blob.
|
|
1183
|
+
*/
|
|
1184
|
+
declare const CLEARED_RUN_STATE: string;
|
|
1185
|
+
type ClearSessionContextResult = {
|
|
1186
|
+
/** Active history rows superseded (active=true -> false). */
|
|
1187
|
+
supersededItems: number;
|
|
1188
|
+
/** Position of the inserted neutral boundary marker. */
|
|
1189
|
+
markerPosition: number;
|
|
1190
|
+
/** stateVersion of the fresh cleared run-state row. */
|
|
1191
|
+
runStateVersion: number;
|
|
1192
|
+
};
|
|
1193
|
+
/**
|
|
1194
|
+
* Clear a session's conversation context in ONE transaction, audit-preserving
|
|
1195
|
+
* and idempotent. Defeats the RunState-fallback resurrection on BOTH model read
|
|
1196
|
+
* paths:
|
|
1197
|
+
*
|
|
1198
|
+
* (a) supersede every active session_history_items row (active=true -> false).
|
|
1199
|
+
* Nothing is deleted — the full transcript stays as an audit trail, same
|
|
1200
|
+
* pattern as applyContextCompaction.
|
|
1201
|
+
* (b) insert ONE active neutral boundary marker at max(position)+1 so the
|
|
1202
|
+
* active read path returns length 1 (not 0) and run-input.ts stays on the
|
|
1203
|
+
* items route, away from the getLatestRunState blob (the bug).
|
|
1204
|
+
* (c) insert a fresh agent_run_states row (stateVersion = max+1) with an empty
|
|
1205
|
+
* cleared blob and pendingApprovals:[], so getLatestRunState (approval /
|
|
1206
|
+
* run_state-source read path) also reflects the clear.
|
|
1207
|
+
*
|
|
1208
|
+
* Also resets last_input_tokens to 0 so the next turn's compaction trigger
|
|
1209
|
+
* starts fresh against the now-short context.
|
|
1210
|
+
*
|
|
1211
|
+
* Idempotent: a re-run supersedes the (now sole, already-marker) active row,
|
|
1212
|
+
* inserts another marker at the next position, and another cleared run-state.
|
|
1213
|
+
* The post-conditions (one active marker row, latest run-state cleared) hold.
|
|
1214
|
+
*/
|
|
1215
|
+
declare function clearSessionContext(db: Database, input: {
|
|
1216
|
+
accountId: string;
|
|
1217
|
+
workspaceId: string;
|
|
1218
|
+
sessionId: string;
|
|
1219
|
+
}): Promise<ClearSessionContextResult>;
|
|
1220
|
+
declare function countSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number>;
|
|
1221
|
+
/**
|
|
1222
|
+
* Set the operator /compact request flag. The worker honors it before the next
|
|
1223
|
+
* turn (forced client-side compaction) and clears it. Idempotent: repeated
|
|
1224
|
+
* requests collapse to one pending compaction.
|
|
1225
|
+
*/
|
|
1226
|
+
declare function requestSessionCompaction(db: Database, workspaceId: string, sessionId: string): Promise<void>;
|
|
1227
|
+
/**
|
|
1228
|
+
* Atomically consume the /compact request flag: clear it and report whether it
|
|
1229
|
+
* was set. The worker calls this pre-turn; only the call that observed `true`
|
|
1230
|
+
* runs the forced compaction, so concurrent turns can't double-compact.
|
|
1231
|
+
*/
|
|
1232
|
+
declare function consumeSessionCompactionRequest(db: Database, workspaceId: string, sessionId: string): Promise<boolean>;
|
|
1233
|
+
/**
|
|
1234
|
+
* Number of conversation-truth items a specific turn persisted. The
|
|
1235
|
+
* worker-death requeue path uses this to decide whether the re-dispatched
|
|
1236
|
+
* turn must enter through a resume notice (its partial progress is already
|
|
1237
|
+
* part of conversation truth, so replaying the original trigger would hand
|
|
1238
|
+
* the model duplicate input) or can replay its original trigger cleanly.
|
|
1239
|
+
*/
|
|
1240
|
+
declare function countTurnSessionHistoryItems(db: Database, workspaceId: string, turnId: string): Promise<number>;
|
|
1241
|
+
/**
|
|
1242
|
+
* Persist the session's sandbox recovery descriptor (the small versioned
|
|
1243
|
+
* envelope used to reattach / snapshot-restore / rebuild the sandbox),
|
|
1244
|
+
* decoupled from the RunState blob.
|
|
1245
|
+
*/
|
|
1246
|
+
declare function upsertSandboxSessionEnvelope(db: Database, input: {
|
|
1247
|
+
accountId: string;
|
|
1248
|
+
workspaceId: string;
|
|
1249
|
+
sessionId: string;
|
|
1250
|
+
envelope: Record<string, unknown>;
|
|
1251
|
+
}): Promise<void>;
|
|
1252
|
+
declare function getSandboxSessionEnvelope(db: Database, workspaceId: string, sessionId: string): Promise<Record<string, unknown> | null>;
|
|
1253
|
+
type SessionRecordingState = (typeof sessionRecordingStateValues)[number];
|
|
1254
|
+
type SessionRecordingMode = (typeof sessionRecordingModeValues)[number];
|
|
1255
|
+
type SessionRecordingCodec = (typeof sessionRecordingCodecValues)[number];
|
|
1256
|
+
type SessionRecordingRow = {
|
|
1257
|
+
id: string;
|
|
1258
|
+
workspaceId: string;
|
|
1259
|
+
sessionId: string;
|
|
1260
|
+
turnId: string | null;
|
|
1261
|
+
state: SessionRecordingState;
|
|
1262
|
+
mode: SessionRecordingMode;
|
|
1263
|
+
codec: SessionRecordingCodec;
|
|
1264
|
+
storageKey: string | null;
|
|
1265
|
+
sizeBytes: number | null;
|
|
1266
|
+
durationSeconds: number | null;
|
|
1267
|
+
width: number;
|
|
1268
|
+
height: number;
|
|
1269
|
+
reason: string | null;
|
|
1270
|
+
createdAt: Date;
|
|
1271
|
+
finalizedAt: Date | null;
|
|
1272
|
+
};
|
|
1273
|
+
declare function insertRecording(db: Database, input: {
|
|
1274
|
+
id: string;
|
|
1275
|
+
accountId: string;
|
|
1276
|
+
workspaceId: string;
|
|
1277
|
+
sessionId: string;
|
|
1278
|
+
turnId?: string | null;
|
|
1279
|
+
mode: SessionRecordingMode;
|
|
1280
|
+
codec: SessionRecordingCodec;
|
|
1281
|
+
width: number;
|
|
1282
|
+
height: number;
|
|
1283
|
+
reason?: string | null;
|
|
1284
|
+
}): Promise<SessionRecordingRow>;
|
|
1285
|
+
declare function updateRecording(db: Database, input: {
|
|
1286
|
+
accountId: string;
|
|
1287
|
+
workspaceId: string;
|
|
1288
|
+
recordingId: string;
|
|
1289
|
+
state: SessionRecordingState;
|
|
1290
|
+
storageKey?: string | null;
|
|
1291
|
+
sizeBytes?: number | null;
|
|
1292
|
+
durationSeconds?: number | null;
|
|
1293
|
+
reason?: string | null;
|
|
1294
|
+
finalized?: boolean;
|
|
1295
|
+
}): Promise<SessionRecordingRow | null>;
|
|
1296
|
+
/**
|
|
1297
|
+
* Hard-delete a recording row. Used to DISCARD an on-turn recording that captured
|
|
1298
|
+
* NO computer-use activity (a plain text turn): the row was inserted at
|
|
1299
|
+
* `beginRecording` (state "recording") but the turn never drove the desktop, so it
|
|
1300
|
+
* is removed entirely rather than surfaced as a phantom recording or a failure. No
|
|
1301
|
+
* other table FK-references session_recordings, so the delete is self-contained.
|
|
1302
|
+
*/
|
|
1303
|
+
declare function deleteRecording(db: Database, input: {
|
|
1304
|
+
accountId: string;
|
|
1305
|
+
workspaceId: string;
|
|
1306
|
+
recordingId: string;
|
|
1307
|
+
}): Promise<void>;
|
|
1308
|
+
declare function getRecording(db: Database, workspaceId: string, recordingId: string): Promise<SessionRecordingRow | null>;
|
|
1309
|
+
declare function listRecordings(db: Database, workspaceId: string, sessionId: string): Promise<SessionRecordingRow[]>;
|
|
1310
|
+
type SandboxPtySessionRow = {
|
|
1311
|
+
id: string;
|
|
1312
|
+
accountId: string;
|
|
1313
|
+
workspaceId: string;
|
|
1314
|
+
sessionId: string;
|
|
1315
|
+
execSessionId: number | null;
|
|
1316
|
+
leaseEpoch: number;
|
|
1317
|
+
cols: number;
|
|
1318
|
+
rows: number;
|
|
1319
|
+
shell: string;
|
|
1320
|
+
cwd: string;
|
|
1321
|
+
status: "open" | "closed";
|
|
1322
|
+
openedBy: string;
|
|
1323
|
+
lastInputAt: string;
|
|
1324
|
+
createdAt: string;
|
|
1325
|
+
closedAt: string | null;
|
|
1326
|
+
};
|
|
1327
|
+
declare function insertPtySession(db: Database, input: {
|
|
1328
|
+
id: string;
|
|
1329
|
+
accountId: string;
|
|
1330
|
+
workspaceId: string;
|
|
1331
|
+
sessionId: string;
|
|
1332
|
+
execSessionId?: number | null;
|
|
1333
|
+
leaseEpoch: number;
|
|
1334
|
+
cols: number;
|
|
1335
|
+
rows: number;
|
|
1336
|
+
shell: string;
|
|
1337
|
+
cwd: string;
|
|
1338
|
+
openedBy: string;
|
|
1339
|
+
}): Promise<SandboxPtySessionRow>;
|
|
1340
|
+
/** Read an OPEN PTY row by ptyId. Returns null when absent or already closed. */
|
|
1341
|
+
declare function getOpenPtySession(db: Database, workspaceId: string, ptyId: string): Promise<SandboxPtySessionRow | null>;
|
|
1342
|
+
/** Stamp the SDK exec-session id (known only after the open exec yields a still-
|
|
1343
|
+
* running process) + refresh the input-activity TTL. */
|
|
1344
|
+
declare function updatePtySessionActivity(db: Database, input: {
|
|
1345
|
+
accountId: string;
|
|
1346
|
+
workspaceId: string;
|
|
1347
|
+
ptyId: string;
|
|
1348
|
+
execSessionId?: number | null;
|
|
1349
|
+
cols?: number;
|
|
1350
|
+
rows?: number;
|
|
1351
|
+
}): Promise<SandboxPtySessionRow | null>;
|
|
1352
|
+
/** Mark a PTY closed (idempotent — a double close on a closed row is a no-op). */
|
|
1353
|
+
declare function closePtySession(db: Database, input: {
|
|
1354
|
+
accountId: string;
|
|
1355
|
+
workspaceId: string;
|
|
1356
|
+
ptyId: string;
|
|
1357
|
+
}): Promise<SandboxPtySessionRow | null>;
|
|
1358
|
+
/** List a session's OPEN PTYs (reattach + reap). */
|
|
1359
|
+
declare function listOpenPtySessions(db: Database, workspaceId: string, sessionId: string): Promise<SandboxPtySessionRow[]>;
|
|
1360
|
+
type SandboxLeaseLiveness = "cold" | "warming" | "warm" | "draining";
|
|
1361
|
+
type LeaseHolderKind = "turn" | "viewer";
|
|
1362
|
+
interface LeaseSnapshot {
|
|
1363
|
+
id: string;
|
|
1364
|
+
sandboxGroupId: string;
|
|
1365
|
+
liveness: SandboxLeaseLiveness;
|
|
1366
|
+
refcount: number;
|
|
1367
|
+
turnHolders: number;
|
|
1368
|
+
viewerHolders: number;
|
|
1369
|
+
instanceId: string | null;
|
|
1370
|
+
backend: string;
|
|
1371
|
+
os: string;
|
|
1372
|
+
image: string | null;
|
|
1373
|
+
dataPlaneUrl: string | null;
|
|
1374
|
+
terminalDataPlaneUrl: string | null;
|
|
1375
|
+
leaseEpoch: number;
|
|
1376
|
+
resumeBackendId: string | null;
|
|
1377
|
+
resumeState: Record<string, unknown> | null;
|
|
1378
|
+
expiresAt: Date;
|
|
1379
|
+
}
|
|
1380
|
+
interface AcquireLeaseInput {
|
|
1381
|
+
accountId: string;
|
|
1382
|
+
workspaceId: string;
|
|
1383
|
+
sandboxGroupId: string;
|
|
1384
|
+
kind: LeaseHolderKind;
|
|
1385
|
+
holderId: string;
|
|
1386
|
+
subjectId?: string | null;
|
|
1387
|
+
backend: string;
|
|
1388
|
+
os?: string;
|
|
1389
|
+
image?: string | null;
|
|
1390
|
+
leaseTtlMs: number;
|
|
1391
|
+
expectedEpoch?: number;
|
|
1392
|
+
}
|
|
1393
|
+
type AcquireLeaseResult = {
|
|
1394
|
+
role: "spawner";
|
|
1395
|
+
lease: LeaseSnapshot;
|
|
1396
|
+
} | {
|
|
1397
|
+
role: "attached";
|
|
1398
|
+
lease: LeaseSnapshot;
|
|
1399
|
+
} | {
|
|
1400
|
+
role: "rearmed";
|
|
1401
|
+
lease: LeaseSnapshot;
|
|
1402
|
+
} | {
|
|
1403
|
+
role: "fenced";
|
|
1404
|
+
lease: LeaseSnapshot;
|
|
1405
|
+
};
|
|
1406
|
+
declare class SandboxLeaseSupersededError extends Error {
|
|
1407
|
+
readonly sandboxGroupId: string;
|
|
1408
|
+
readonly leaseEpoch: number;
|
|
1409
|
+
constructor(sandboxGroupId: string, leaseEpoch: number);
|
|
1410
|
+
}
|
|
1411
|
+
declare class SandboxImageConflictError extends Error {
|
|
1412
|
+
readonly sandboxGroupId: string;
|
|
1413
|
+
readonly currentImage: string;
|
|
1414
|
+
readonly requestedImage: string;
|
|
1415
|
+
constructor(sandboxGroupId: string, currentImage: string, requestedImage: string);
|
|
1416
|
+
}
|
|
1417
|
+
declare function acquireLease(db: Database, input: AcquireLeaseInput): Promise<AcquireLeaseResult>;
|
|
1418
|
+
declare function commitWarmingToWarm(db: Database, input: {
|
|
1419
|
+
accountId: string;
|
|
1420
|
+
workspaceId: string;
|
|
1421
|
+
sandboxGroupId: string;
|
|
1422
|
+
expectedEpoch: number;
|
|
1423
|
+
instanceId: string;
|
|
1424
|
+
dataPlaneUrl?: string | null;
|
|
1425
|
+
resumeBackendId?: string | null;
|
|
1426
|
+
resumeState?: Record<string, unknown> | null;
|
|
1427
|
+
leaseTtlMs: number;
|
|
1428
|
+
}): Promise<{
|
|
1429
|
+
committed: boolean;
|
|
1430
|
+
lease: LeaseSnapshot | null;
|
|
1431
|
+
}>;
|
|
1432
|
+
declare function failWarmingToCold(db: Database, input: {
|
|
1433
|
+
accountId: string;
|
|
1434
|
+
workspaceId: string;
|
|
1435
|
+
sandboxGroupId: string;
|
|
1436
|
+
expectedEpoch: number;
|
|
1437
|
+
}): Promise<void>;
|
|
1438
|
+
declare function releaseLeaseHolder(db: Database, input: {
|
|
1439
|
+
accountId: string;
|
|
1440
|
+
workspaceId: string;
|
|
1441
|
+
sandboxGroupId: string;
|
|
1442
|
+
kind: LeaseHolderKind;
|
|
1443
|
+
holderId: string;
|
|
1444
|
+
idleGraceMs: number;
|
|
1445
|
+
}): Promise<{
|
|
1446
|
+
liveness: SandboxLeaseLiveness;
|
|
1447
|
+
refcount: number;
|
|
1448
|
+
} | null>;
|
|
1449
|
+
declare function heartbeatLeaseHolder(db: Database, input: {
|
|
1450
|
+
accountId: string;
|
|
1451
|
+
workspaceId: string;
|
|
1452
|
+
sandboxGroupId: string;
|
|
1453
|
+
kind: LeaseHolderKind;
|
|
1454
|
+
holderId: string;
|
|
1455
|
+
leaseTtlMs: number;
|
|
1456
|
+
expectedEpoch: number;
|
|
1457
|
+
}): Promise<boolean>;
|
|
1458
|
+
interface ReapDrainable {
|
|
1459
|
+
workspaceId: string;
|
|
1460
|
+
sandboxGroupId: string;
|
|
1461
|
+
instanceId: string | null;
|
|
1462
|
+
leaseEpoch: number;
|
|
1463
|
+
}
|
|
1464
|
+
declare function reapStaleLeaseHolders(db: Database, input: {
|
|
1465
|
+
workspaceId: string;
|
|
1466
|
+
viewerHolderTtlMs: number;
|
|
1467
|
+
idleGraceMs: number;
|
|
1468
|
+
}): Promise<{
|
|
1469
|
+
reapedViewers: number;
|
|
1470
|
+
warmingReset: number;
|
|
1471
|
+
drained: ReapDrainable[];
|
|
1472
|
+
}>;
|
|
1473
|
+
declare function reapStaleLeaseHoldersGlobal(db: Database, input: {
|
|
1474
|
+
viewerHolderTtlMs: number;
|
|
1475
|
+
idleGraceMs: number;
|
|
1476
|
+
}): Promise<ReapDrainable[]>;
|
|
1477
|
+
interface MeterableWarmLease {
|
|
1478
|
+
accountId: string;
|
|
1479
|
+
workspaceId: string;
|
|
1480
|
+
sandboxGroupId: string;
|
|
1481
|
+
leaseEpoch: number;
|
|
1482
|
+
backend: string;
|
|
1483
|
+
}
|
|
1484
|
+
declare function listMeterableWarmLeases(db: Database): Promise<MeterableWarmLease[]>;
|
|
1485
|
+
declare function reArmDrainingLease(db: Database, input: {
|
|
1486
|
+
accountId: string;
|
|
1487
|
+
workspaceId: string;
|
|
1488
|
+
sandboxGroupId: string;
|
|
1489
|
+
leaseTtlMs: number;
|
|
1490
|
+
}): Promise<{
|
|
1491
|
+
rearmed: boolean;
|
|
1492
|
+
}>;
|
|
1493
|
+
declare function confirmDrainCold(db: Database, input: {
|
|
1494
|
+
accountId: string;
|
|
1495
|
+
workspaceId: string;
|
|
1496
|
+
sandboxGroupId: string;
|
|
1497
|
+
expectedEpoch: number;
|
|
1498
|
+
}): Promise<{
|
|
1499
|
+
wentCold: boolean;
|
|
1500
|
+
}>;
|
|
1501
|
+
declare function persistDrainSnapshot(db: Database, input: {
|
|
1502
|
+
accountId: string;
|
|
1503
|
+
workspaceId: string;
|
|
1504
|
+
sandboxGroupId: string;
|
|
1505
|
+
expectedEpoch: number;
|
|
1506
|
+
/** base64 of the provider snapshot-ref / tar archive from persistWorkspace().
|
|
1507
|
+
* Pass null to CAS-check without writing (for backends with no persistWorkspace). */
|
|
1508
|
+
workspaceArchive: string | null;
|
|
1509
|
+
}): Promise<{
|
|
1510
|
+
wrote: boolean;
|
|
1511
|
+
priorArchive: string | null;
|
|
1512
|
+
}>;
|
|
1513
|
+
declare function readLease(db: Database, workspaceId: string, sandboxGroupId: string): Promise<LeaseSnapshot | null>;
|
|
1514
|
+
declare function recordLeaseDataPlaneUrl(db: Database, input: {
|
|
1515
|
+
accountId: string;
|
|
1516
|
+
workspaceId: string;
|
|
1517
|
+
sandboxGroupId: string;
|
|
1518
|
+
expectedEpoch: number;
|
|
1519
|
+
dataPlaneUrl: string | null;
|
|
1520
|
+
}): Promise<LeaseSnapshot | null>;
|
|
1521
|
+
declare function recordLeaseTerminalDataPlaneUrl(db: Database, input: {
|
|
1522
|
+
accountId: string;
|
|
1523
|
+
workspaceId: string;
|
|
1524
|
+
sandboxGroupId: string;
|
|
1525
|
+
expectedEpoch: number;
|
|
1526
|
+
terminalDataPlaneUrl: string | null;
|
|
1527
|
+
}): Promise<LeaseSnapshot | null>;
|
|
1528
|
+
type SandboxKind = (typeof sandboxKindValues)[number];
|
|
1529
|
+
type EnrollmentExposure = (typeof enrollmentExposureValues)[number];
|
|
1530
|
+
type EnrollmentStatus = (typeof enrollmentStatusValues)[number];
|
|
1531
|
+
type EnrollmentOs = (typeof enrollmentOsValues)[number];
|
|
1532
|
+
type EnrollmentRecord = {
|
|
1533
|
+
id: string;
|
|
1534
|
+
accountId: string;
|
|
1535
|
+
workspaceId: string;
|
|
1536
|
+
pubkey: string;
|
|
1537
|
+
exposure: EnrollmentExposure;
|
|
1538
|
+
hasDisplay: boolean;
|
|
1539
|
+
allowScreenControl: boolean;
|
|
1540
|
+
status: EnrollmentStatus;
|
|
1541
|
+
os: EnrollmentOs;
|
|
1542
|
+
arch: string;
|
|
1543
|
+
lastSeenAt: string | null;
|
|
1544
|
+
createdAt: string;
|
|
1545
|
+
revokedAt: string | null;
|
|
1546
|
+
updatedAt: string;
|
|
1547
|
+
};
|
|
1548
|
+
type SandboxRecord = {
|
|
1549
|
+
id: string;
|
|
1550
|
+
accountId: string;
|
|
1551
|
+
workspaceId: string;
|
|
1552
|
+
kind: SandboxKind;
|
|
1553
|
+
name: string;
|
|
1554
|
+
enrollmentId: string | null;
|
|
1555
|
+
createdAt: string;
|
|
1556
|
+
updatedAt: string;
|
|
1557
|
+
};
|
|
1558
|
+
declare function createEnrollment(db: Database, input: {
|
|
1559
|
+
accountId: string;
|
|
1560
|
+
workspaceId: string;
|
|
1561
|
+
pubkey: string;
|
|
1562
|
+
exposure?: EnrollmentExposure;
|
|
1563
|
+
hasDisplay?: boolean;
|
|
1564
|
+
allowScreenControl?: boolean;
|
|
1565
|
+
os?: EnrollmentOs;
|
|
1566
|
+
arch?: string;
|
|
1567
|
+
}): Promise<EnrollmentRecord>;
|
|
1568
|
+
declare function getEnrollment(db: Database, workspaceId: string, enrollmentId: string): Promise<EnrollmentRecord | null>;
|
|
1569
|
+
declare function listEnrollments(db: Database, workspaceId: string, options?: {
|
|
1570
|
+
status?: EnrollmentStatus;
|
|
1571
|
+
}): Promise<EnrollmentRecord[]>;
|
|
1572
|
+
declare function revokeEnrollment(db: Database, input: {
|
|
1573
|
+
accountId: string;
|
|
1574
|
+
workspaceId: string;
|
|
1575
|
+
enrollmentId: string;
|
|
1576
|
+
}): Promise<{
|
|
1577
|
+
revoked: boolean;
|
|
1578
|
+
}>;
|
|
1579
|
+
declare function touchEnrollmentLastSeen(db: Database, input: {
|
|
1580
|
+
accountId: string;
|
|
1581
|
+
workspaceId: string;
|
|
1582
|
+
enrollmentId: string;
|
|
1583
|
+
}): Promise<void>;
|
|
1584
|
+
declare function setEnrollmentHasDisplay(db: Database, input: {
|
|
1585
|
+
accountId: string;
|
|
1586
|
+
workspaceId: string;
|
|
1587
|
+
enrollmentId: string;
|
|
1588
|
+
hasDisplay: boolean;
|
|
1589
|
+
}): Promise<{
|
|
1590
|
+
updated: boolean;
|
|
1591
|
+
}>;
|
|
1592
|
+
type DeviceEnrollmentStatus = (typeof deviceEnrollmentStatusValues)[number];
|
|
1593
|
+
type DeviceEnrollmentRequestRecord = {
|
|
1594
|
+
id: string;
|
|
1595
|
+
deviceCode: string;
|
|
1596
|
+
userCode: string;
|
|
1597
|
+
accountId: string;
|
|
1598
|
+
workspaceId: string;
|
|
1599
|
+
pubkey: string;
|
|
1600
|
+
os: EnrollmentOs;
|
|
1601
|
+
arch: string;
|
|
1602
|
+
machineName: string | null;
|
|
1603
|
+
requestedExposure: EnrollmentExposure;
|
|
1604
|
+
canOfferDisplay: boolean;
|
|
1605
|
+
requestsScreenControl: boolean;
|
|
1606
|
+
status: DeviceEnrollmentStatus;
|
|
1607
|
+
approvedBySubjectId: string | null;
|
|
1608
|
+
approvedBySubjectLabel: string | null;
|
|
1609
|
+
allowScreenControl: boolean;
|
|
1610
|
+
approvedAt: string | null;
|
|
1611
|
+
enrollmentId: string | null;
|
|
1612
|
+
sandboxId: string | null;
|
|
1613
|
+
expiresAt: string;
|
|
1614
|
+
createdAt: string;
|
|
1615
|
+
updatedAt: string;
|
|
1616
|
+
};
|
|
1617
|
+
declare function createDeviceEnrollmentRequest(db: Database, input: {
|
|
1618
|
+
accountId: string;
|
|
1619
|
+
workspaceId: string;
|
|
1620
|
+
deviceCode: string;
|
|
1621
|
+
userCode: string;
|
|
1622
|
+
pubkey: string;
|
|
1623
|
+
os?: EnrollmentOs;
|
|
1624
|
+
arch?: string;
|
|
1625
|
+
machineName?: string | null;
|
|
1626
|
+
requestedExposure?: EnrollmentExposure;
|
|
1627
|
+
canOfferDisplay?: boolean;
|
|
1628
|
+
requestsScreenControl?: boolean;
|
|
1629
|
+
expiresAt: Date;
|
|
1630
|
+
}): Promise<DeviceEnrollmentRequestRecord>;
|
|
1631
|
+
declare function getDeviceEnrollmentRequestByDeviceCode(db: Database, deviceCode: string): Promise<DeviceEnrollmentRequestRecord | null>;
|
|
1632
|
+
declare function getPendingDeviceEnrollmentRequestByUserCode(db: Database, workspaceId: string, userCode: string): Promise<DeviceEnrollmentRequestRecord | null>;
|
|
1633
|
+
declare function getPendingDeviceEnrollmentRequestByUserCodeGlobal(db: Database, userCode: string): Promise<DeviceEnrollmentRequestRecord | null>;
|
|
1634
|
+
declare function finalizeEnrollmentByToken(db: Database, input: {
|
|
1635
|
+
accountId: string;
|
|
1636
|
+
workspaceId: string;
|
|
1637
|
+
pubkey: string;
|
|
1638
|
+
hasDisplay: boolean;
|
|
1639
|
+
allowScreenControl: boolean;
|
|
1640
|
+
os: EnrollmentOs;
|
|
1641
|
+
arch: string;
|
|
1642
|
+
sandboxName: string;
|
|
1643
|
+
now?: Date;
|
|
1644
|
+
}): Promise<{
|
|
1645
|
+
enrollment: EnrollmentRecord;
|
|
1646
|
+
sandbox: SandboxRecord;
|
|
1647
|
+
}>;
|
|
1648
|
+
declare function approveDeviceEnrollmentRequest(db: Database, input: {
|
|
1649
|
+
accountId: string;
|
|
1650
|
+
workspaceId: string;
|
|
1651
|
+
requestId: string;
|
|
1652
|
+
allowScreenControl: boolean;
|
|
1653
|
+
approvedBySubjectId: string;
|
|
1654
|
+
approvedBySubjectLabel?: string | null;
|
|
1655
|
+
sandboxName: string;
|
|
1656
|
+
now?: Date;
|
|
1657
|
+
}): Promise<{
|
|
1658
|
+
approved: boolean;
|
|
1659
|
+
enrollment: EnrollmentRecord | null;
|
|
1660
|
+
sandbox: SandboxRecord | null;
|
|
1661
|
+
}>;
|
|
1662
|
+
declare function denyDeviceEnrollmentRequest(db: Database, input: {
|
|
1663
|
+
accountId: string;
|
|
1664
|
+
workspaceId: string;
|
|
1665
|
+
requestId: string;
|
|
1666
|
+
}): Promise<{
|
|
1667
|
+
denied: boolean;
|
|
1668
|
+
}>;
|
|
1669
|
+
declare function consumeDeviceEnrollmentRequest(db: Database, input: {
|
|
1670
|
+
accountId: string;
|
|
1671
|
+
workspaceId: string;
|
|
1672
|
+
requestId: string;
|
|
1673
|
+
}): Promise<{
|
|
1674
|
+
consumed: boolean;
|
|
1675
|
+
}>;
|
|
1676
|
+
declare function createSandbox(db: Database, input: {
|
|
1677
|
+
accountId: string;
|
|
1678
|
+
workspaceId: string;
|
|
1679
|
+
kind: SandboxKind;
|
|
1680
|
+
name: string;
|
|
1681
|
+
enrollmentId?: string | null;
|
|
1682
|
+
}): Promise<SandboxRecord>;
|
|
1683
|
+
declare function getSandbox(db: Database, workspaceId: string, sandboxId: string): Promise<SandboxRecord | null>;
|
|
1684
|
+
declare function listSandboxes(db: Database, workspaceId: string): Promise<SandboxRecord[]>;
|
|
1685
|
+
type ActiveSandboxPointer = {
|
|
1686
|
+
activeSandboxId: string | null;
|
|
1687
|
+
activeEpoch: number;
|
|
1688
|
+
workingDir: string | null;
|
|
1689
|
+
};
|
|
1690
|
+
declare function readActiveSandbox(db: Database, workspaceId: string, sessionId: string): Promise<ActiveSandboxPointer | null>;
|
|
1691
|
+
declare function setActiveSandbox(db: Database, input: {
|
|
1692
|
+
accountId: string;
|
|
1693
|
+
workspaceId: string;
|
|
1694
|
+
sessionId: string;
|
|
1695
|
+
targetSandboxId: string | null;
|
|
1696
|
+
expectedEpoch: number;
|
|
1697
|
+
workingDir?: string | null;
|
|
1698
|
+
}): Promise<{
|
|
1699
|
+
swapped: boolean;
|
|
1700
|
+
pointer: ActiveSandboxPointer | null;
|
|
1701
|
+
}>;
|
|
1702
|
+
type MachineMetricsSample = {
|
|
1703
|
+
cpuPercent?: number | null;
|
|
1704
|
+
load1?: number | null;
|
|
1705
|
+
load5?: number | null;
|
|
1706
|
+
load15?: number | null;
|
|
1707
|
+
memUsedBytes?: number | null;
|
|
1708
|
+
memTotalBytes?: number | null;
|
|
1709
|
+
diskUsedBytes?: number | null;
|
|
1710
|
+
diskTotalBytes?: number | null;
|
|
1711
|
+
gpuUtilPercent?: number | null;
|
|
1712
|
+
gpuMemUsedBytes?: number | null;
|
|
1713
|
+
gpuMemTotalBytes?: number | null;
|
|
1714
|
+
contention?: number | null;
|
|
1715
|
+
sampledAt: Date;
|
|
1716
|
+
};
|
|
1717
|
+
declare function upsertMachineMetricsLatest(db: Database, input: {
|
|
1718
|
+
accountId: string;
|
|
1719
|
+
workspaceId: string;
|
|
1720
|
+
enrollmentId: string;
|
|
1721
|
+
sample: MachineMetricsSample;
|
|
1722
|
+
}): Promise<void>;
|
|
1723
|
+
declare function insertMachineMetricsSeries(db: Database, input: {
|
|
1724
|
+
accountId: string;
|
|
1725
|
+
workspaceId: string;
|
|
1726
|
+
enrollmentId: string;
|
|
1727
|
+
sample: MachineMetricsSample;
|
|
1728
|
+
}): Promise<void>;
|
|
1729
|
+
declare const MACHINE_METRICS_SERIES_INTERVAL_MS = 60000;
|
|
1730
|
+
/**
|
|
1731
|
+
* Ingest ONE sampled metrics point for an enrollment (the M10 ingestion seam):
|
|
1732
|
+
* 1. UPSERT machine_metrics_latest (the "now" row, one per enrollment) — always.
|
|
1733
|
+
* 2. APPEND a machine_metrics_series row only when >= ~1/min has elapsed since
|
|
1734
|
+
* the last series row (downsample) — so the 5s heartbeat cadence does not
|
|
1735
|
+
* flood the history table.
|
|
1736
|
+
* Both happen under the same RLS context. Returns whether a series row was
|
|
1737
|
+
* appended (the downsample decision) so the caller / tests can assert the ~1/min
|
|
1738
|
+
* spacing. A null/absent `sampledAt` on the prior row treats it as "no prior" →
|
|
1739
|
+
* append.
|
|
1740
|
+
*/
|
|
1741
|
+
declare function ingestMachineMetricsSample(db: Database, input: {
|
|
1742
|
+
accountId: string;
|
|
1743
|
+
workspaceId: string;
|
|
1744
|
+
enrollmentId: string;
|
|
1745
|
+
sample: MachineMetricsSample;
|
|
1746
|
+
/** Override the downsample interval (tests). Defaults to ~1/min. */
|
|
1747
|
+
seriesIntervalMs?: number;
|
|
1748
|
+
}): Promise<{
|
|
1749
|
+
latestUpserted: true;
|
|
1750
|
+
seriesAppended: boolean;
|
|
1751
|
+
}>;
|
|
1752
|
+
type MachineMetricsRow = {
|
|
1753
|
+
enrollmentId: string;
|
|
1754
|
+
cpuPercent: number | null;
|
|
1755
|
+
load1: number | null;
|
|
1756
|
+
load5: number | null;
|
|
1757
|
+
load15: number | null;
|
|
1758
|
+
memUsedBytes: number | null;
|
|
1759
|
+
memTotalBytes: number | null;
|
|
1760
|
+
diskUsedBytes: number | null;
|
|
1761
|
+
diskTotalBytes: number | null;
|
|
1762
|
+
gpuUtilPercent: number | null;
|
|
1763
|
+
gpuMemUsedBytes: number | null;
|
|
1764
|
+
gpuMemTotalBytes: number | null;
|
|
1765
|
+
contention: number | null;
|
|
1766
|
+
sampledAt: string;
|
|
1767
|
+
};
|
|
1768
|
+
declare function readMachineMetricsLatest(db: Database, workspaceId: string, enrollmentId: string): Promise<MachineMetricsRow | null>;
|
|
1769
|
+
declare function readMachineMetricsLatestForWorkspace(db: Database, workspaceId: string): Promise<Map<string, MachineMetricsRow>>;
|
|
1770
|
+
declare function readMachineMetricsSeries(db: Database, input: {
|
|
1771
|
+
workspaceId: string;
|
|
1772
|
+
enrollmentId: string;
|
|
1773
|
+
since: Date;
|
|
1774
|
+
limit?: number;
|
|
1775
|
+
}): Promise<MachineMetricsRow[]>;
|
|
1776
|
+
interface StreamAcknowledgment {
|
|
1777
|
+
acknowledgedUnredacted: boolean;
|
|
1778
|
+
acknowledgedShared: boolean;
|
|
1779
|
+
}
|
|
1780
|
+
declare function recordStreamAcknowledgment(db: Database, input: {
|
|
1781
|
+
accountId: string;
|
|
1782
|
+
workspaceId: string;
|
|
1783
|
+
sandboxGroupId: string;
|
|
1784
|
+
subjectId: string;
|
|
1785
|
+
acknowledgeUnredacted: boolean;
|
|
1786
|
+
acknowledgeShared: boolean;
|
|
1787
|
+
}): Promise<StreamAcknowledgment>;
|
|
1788
|
+
declare function getStreamAcknowledgment(db: Database, input: {
|
|
1789
|
+
workspaceId: string;
|
|
1790
|
+
sandboxGroupId: string;
|
|
1791
|
+
subjectId: string;
|
|
1792
|
+
}): Promise<StreamAcknowledgment | null>;
|
|
1793
|
+
declare function listSessionIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<string[]>;
|
|
1794
|
+
declare function revokeViewer(db: Database, input: {
|
|
1795
|
+
accountId: string;
|
|
1796
|
+
workspaceId: string;
|
|
1797
|
+
sandboxGroupId: string;
|
|
1798
|
+
viewerId: string;
|
|
1799
|
+
idleGraceMs: number;
|
|
1800
|
+
}): Promise<{
|
|
1801
|
+
liveness: SandboxLeaseLiveness;
|
|
1802
|
+
refcount: number;
|
|
1803
|
+
} | null>;
|
|
1804
|
+
interface AccrueWarmSecondsResult {
|
|
1805
|
+
/** false when nothing was accrued (epoch fenced / not warm / no elapsed / the
|
|
1806
|
+
* first tick that only seeds the cursor). */
|
|
1807
|
+
accrued: boolean;
|
|
1808
|
+
/** Whole seconds metered this tick (0 when accrued:false). */
|
|
1809
|
+
seconds: number;
|
|
1810
|
+
/** The monotonic tick index this accrual was recorded under. */
|
|
1811
|
+
tick: number;
|
|
1812
|
+
/** usd_micros charged for this tick (0 when rate is 0). */
|
|
1813
|
+
costMicros: number;
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Accrue warm-seconds for the elapsed wall-clock since the lease's last meter
|
|
1817
|
+
* cursor, idempotent on (sandbox_group_id, lease_epoch, tick). EPOCH-FENCED +
|
|
1818
|
+
* liveness-guarded (warm only): a stale-epoch tick or a draining/cold lease is a
|
|
1819
|
+
* no-op, so a superseded writer that re-fires cannot mis-meter. The FIRST tick on
|
|
1820
|
+
* a never-metered lease (last_meter_at IS NULL) only SEEDS the cursor — it
|
|
1821
|
+
* accrues nothing (there is no prior cursor to diff against), matching the
|
|
1822
|
+
* "delta since last tick" contract. warmRateMicrosPerSecond > 0 also records a
|
|
1823
|
+
* sandbox.warm_cost event (cost = seconds x rate) AND debits the same micros from
|
|
1824
|
+
* the credit balance via applyCreditDebitUpToBalance (the model-cost precedent),
|
|
1825
|
+
* idempotent on the SAME (group, epoch, tick) key. The usage event is the
|
|
1826
|
+
* REQUESTED cost; the ledger is the ACTUAL debit (they legitimately differ when
|
|
1827
|
+
* balance is low — M2). Set debitCredits:false to meter without debiting.
|
|
1828
|
+
*/
|
|
1829
|
+
declare function accrueWarmSeconds(db: Database, input: {
|
|
1830
|
+
accountId: string;
|
|
1831
|
+
workspaceId: string;
|
|
1832
|
+
sandboxGroupId: string;
|
|
1833
|
+
/** The epoch the tick observed; the fence — a stale writer no-ops. */
|
|
1834
|
+
expectedEpoch: number;
|
|
1835
|
+
/** usd_micros per warm-second for this box's backend (0 = meter only, no cost). */
|
|
1836
|
+
warmRateMicrosPerSecond: number;
|
|
1837
|
+
/** Optional attribution: the founding/observing session (visibility only — the
|
|
1838
|
+
* group meter key makes the workspace charge correct regardless). */
|
|
1839
|
+
subjectId?: string | null;
|
|
1840
|
+
/** Debit credits for warm-cost (default true). The force-drain at 0 balance
|
|
1841
|
+
* depends on this decrementing the balance. */
|
|
1842
|
+
debitCredits?: boolean;
|
|
1843
|
+
}): Promise<AccrueWarmSecondsResult>;
|
|
1844
|
+
interface ForceDrainResult {
|
|
1845
|
+
/** Whether the workspace was over a limit (0 balance or over the warm cap). */
|
|
1846
|
+
overLimit: boolean;
|
|
1847
|
+
/** The reason, for observability. */
|
|
1848
|
+
reason: "balance" | "warm_cap" | null;
|
|
1849
|
+
/** The (workspaceId, sandboxGroupId) viewer-only boxes CASed warm->draining. */
|
|
1850
|
+
drained: {
|
|
1851
|
+
workspaceId: string;
|
|
1852
|
+
sandboxGroupId: string;
|
|
1853
|
+
}[];
|
|
1854
|
+
}
|
|
1855
|
+
declare function forceDrainOverLimitViewerOnlyBoxes(db: Database, input: {
|
|
1856
|
+
workspaceId: string;
|
|
1857
|
+
/** account balance gate: when <= 0 (and a billing/managed mode is on) drain. */
|
|
1858
|
+
balanceMicros: number;
|
|
1859
|
+
enforceBalance: boolean;
|
|
1860
|
+
/** warm-second cap (cumulative this UTC month). 0 = unbounded (no cap gate). */
|
|
1861
|
+
maxWarmSecondsPerWorkspace: number;
|
|
1862
|
+
/** start of the cap window (caller passes startOfUtcMonth() so the fn stays
|
|
1863
|
+
* time-source-agnostic for tests). */
|
|
1864
|
+
capWindowStart?: Date;
|
|
1865
|
+
/** drain-grace horizon stamped on the newly-draining rows (matches the reaper). */
|
|
1866
|
+
idleGraceMs: number;
|
|
1867
|
+
}): Promise<ForceDrainResult>;
|
|
1868
|
+
declare function saveRunState(db: Database, input: {
|
|
1869
|
+
accountId: string;
|
|
1870
|
+
workspaceId: string;
|
|
1871
|
+
sessionId: string;
|
|
1872
|
+
turnId?: string | null;
|
|
1873
|
+
serializedRunState: string;
|
|
1874
|
+
pendingApprovals: unknown[];
|
|
1875
|
+
frozenCodexCredentialId?: string | null;
|
|
1876
|
+
}): Promise<void>;
|
|
1877
|
+
type CreateSessionGoalInput = {
|
|
1878
|
+
accountId: string;
|
|
1879
|
+
workspaceId: string;
|
|
1880
|
+
sessionId: string;
|
|
1881
|
+
text: string;
|
|
1882
|
+
successCriteria?: string | null;
|
|
1883
|
+
maxAutoContinuations?: number | null;
|
|
1884
|
+
createdBy: SessionGoalCreatedBy;
|
|
1885
|
+
};
|
|
1886
|
+
declare function createSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<SessionGoal>;
|
|
1887
|
+
declare function getSessionGoal(db: Database, workspaceId: string, sessionId: string): Promise<SessionGoal | null>;
|
|
1888
|
+
/**
|
|
1889
|
+
* goal_set semantics: insert, or replace the existing goal in place. A replace
|
|
1890
|
+
* re-activates the goal (even when paused or completed), bumps the version,
|
|
1891
|
+
* and resets the continuation counters — re-stating the objective re-arms the
|
|
1892
|
+
* auto-continuation budget.
|
|
1893
|
+
*/
|
|
1894
|
+
declare function upsertSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<{
|
|
1895
|
+
goal: SessionGoal;
|
|
1896
|
+
replaced: boolean;
|
|
1897
|
+
}>;
|
|
1898
|
+
/**
|
|
1899
|
+
* goal_update semantics: revise text/criteria without changing status. The
|
|
1900
|
+
* version bump counts as progress for the no-progress detector.
|
|
1901
|
+
*/
|
|
1902
|
+
declare function updateSessionGoal(db: Database, workspaceId: string, sessionId: string, input: {
|
|
1903
|
+
text?: string;
|
|
1904
|
+
successCriteria?: string | null;
|
|
1905
|
+
}): Promise<SessionGoal>;
|
|
1906
|
+
/**
|
|
1907
|
+
* Sets a session's display title. The clobber guard lives entirely in this
|
|
1908
|
+
* single atomic UPDATE: a user-set title is permanent, so agent/auto writes
|
|
1909
|
+
* carry an `AND title_source IS DISTINCT FROM 'user'` guard (NULL-safe in
|
|
1910
|
+
* Postgres) while user writes are unconditional. Never read-modify-write.
|
|
1911
|
+
* Returns `{ updated, title }`: `updated` is false when an agent write was
|
|
1912
|
+
* skipped because a user title already pinned the session, true otherwise;
|
|
1913
|
+
* `title` is the resulting title (null when skipped).
|
|
1914
|
+
*/
|
|
1915
|
+
declare function updateSessionTitle(db: Database, input: {
|
|
1916
|
+
workspaceId: string;
|
|
1917
|
+
sessionId: string;
|
|
1918
|
+
title: string;
|
|
1919
|
+
source: "user" | "agent";
|
|
1920
|
+
}): Promise<{
|
|
1921
|
+
updated: boolean;
|
|
1922
|
+
title: string | null;
|
|
1923
|
+
}>;
|
|
1924
|
+
/**
|
|
1925
|
+
* Status transition helper. Idempotent: requesting the current status returns
|
|
1926
|
+
* `changed: false` so callers can skip emitting a duplicate event. `completed`
|
|
1927
|
+
* is terminal for transitions; only `upsertSessionGoal` can replace a
|
|
1928
|
+
* completed goal. Resuming to `active` clears the pause fields and resets the
|
|
1929
|
+
* continuation counters.
|
|
1930
|
+
*/
|
|
1931
|
+
declare function setSessionGoalStatus(db: Database, workspaceId: string, sessionId: string, input: {
|
|
1932
|
+
status: SessionGoalStatus;
|
|
1933
|
+
evidence?: string;
|
|
1934
|
+
rationale?: string;
|
|
1935
|
+
pausedReason?: string;
|
|
1936
|
+
}): Promise<{
|
|
1937
|
+
goal: SessionGoal;
|
|
1938
|
+
changed: boolean;
|
|
1939
|
+
}>;
|
|
1940
|
+
declare function setSessionGoalLastContinuationTurn(db: Database, workspaceId: string, sessionId: string, turnId: string): Promise<void>;
|
|
1941
|
+
type GoalContinuationDecision = {
|
|
1942
|
+
decision: "none";
|
|
1943
|
+
} | {
|
|
1944
|
+
decision: "queue";
|
|
1945
|
+
} | {
|
|
1946
|
+
decision: "paused";
|
|
1947
|
+
reason: "no_progress" | "max_auto_continuations" | "limits";
|
|
1948
|
+
goal: SessionGoal;
|
|
1949
|
+
} | {
|
|
1950
|
+
decision: "continue";
|
|
1951
|
+
goal: SessionGoal;
|
|
1952
|
+
autoContinuation: number;
|
|
1953
|
+
cap: number | null;
|
|
1954
|
+
};
|
|
1955
|
+
/**
|
|
1956
|
+
* Core continuation decision, taken in one transaction with the goal row
|
|
1957
|
+
* locked. Queued work always wins; any non-terminal turn (queued, running, or
|
|
1958
|
+
* requires_action awaiting a human approval) blocks auto-continuation. The
|
|
1959
|
+
* no-progress and max-continuation guards mutate counters here only, so a
|
|
1960
|
+
* replaying workflow re-reads recorded activity results and never recomputes
|
|
1961
|
+
* them.
|
|
1962
|
+
*/
|
|
1963
|
+
declare function evaluateGoalContinuation(db: Database, input: {
|
|
1964
|
+
workspaceId: string;
|
|
1965
|
+
sessionId: string;
|
|
1966
|
+
defaultMaxAutoContinuations?: number | null;
|
|
1967
|
+
noProgressLimit: number;
|
|
1968
|
+
budgetBlocked?: string | null;
|
|
1969
|
+
}): Promise<GoalContinuationDecision>;
|
|
1970
|
+
declare function createTurn(db: Database, input: {
|
|
1971
|
+
workspaceId: string;
|
|
1972
|
+
sessionId: string;
|
|
1973
|
+
triggerEventId: string;
|
|
1974
|
+
temporalWorkflowId: string;
|
|
1975
|
+
}): Promise<string>;
|
|
1976
|
+
declare function enqueueSessionTurn(db: Database, input: EnqueueSessionTurnInput): Promise<SessionTurn>;
|
|
1977
|
+
declare function claimNextQueuedTurn(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<SessionTurn | null>;
|
|
1978
|
+
declare function setSessionStatus(db: Database, workspaceId: string, sessionId: string, status: SessionStatus, activeTurnId?: string | null): Promise<void>;
|
|
1979
|
+
type WakeParentForChildCompletionInput = {
|
|
1980
|
+
workspaceId: string;
|
|
1981
|
+
parentSessionId: string;
|
|
1982
|
+
clientEventId: string;
|
|
1983
|
+
text: string;
|
|
1984
|
+
childCompletion: Record<string, unknown>;
|
|
1985
|
+
reasoningEffortFallback: ReasoningEffort;
|
|
1986
|
+
};
|
|
1987
|
+
type WakeParentForChildCompletionResult = {
|
|
1988
|
+
delivered: false;
|
|
1989
|
+
reason: "already_delivered" | "parent_cancelled";
|
|
1990
|
+
} | {
|
|
1991
|
+
delivered: true;
|
|
1992
|
+
turn: SessionTurn;
|
|
1993
|
+
triggerEvent: SessionEvent;
|
|
1994
|
+
events: SessionEvent[];
|
|
1995
|
+
temporalWorkflowId: string;
|
|
1996
|
+
};
|
|
1997
|
+
/**
|
|
1998
|
+
* Deliver a one-shot completion wake from a spawned worker into its parent
|
|
1999
|
+
* (manager) session: append a system-authored `user.message`, transition the
|
|
2000
|
+
* parent idle/failed -> queued (a queued/running parent already has a turn in
|
|
2001
|
+
* flight and keeps it), and enqueue the resulting turn. The whole thing runs
|
|
2002
|
+
* under the parent's row lock in one transaction, and is idempotent on
|
|
2003
|
+
* `clientEventId`: a duplicate call for the same terminal episode (activity
|
|
2004
|
+
* retry, the workflow's idle re-check) is a no-op that enqueues no second
|
|
2005
|
+
* turn. The caller publishes the returned events and signals the parent's
|
|
2006
|
+
* Temporal workflow (signalWithStart) only when `delivered` is true.
|
|
2007
|
+
*
|
|
2008
|
+
* Mirrors `acceptSessionUserMessage`/`postUserMessageTurn` in the API domain:
|
|
2009
|
+
* cancelled is the one parent state that refuses the wake (an explicit stop);
|
|
2010
|
+
* failed stays revivable, matching the revivable-failed-sessions contract.
|
|
2011
|
+
*/
|
|
2012
|
+
declare function wakeParentSessionForChildCompletion(db: Database, input: WakeParentForChildCompletionInput): Promise<WakeParentForChildCompletionResult>;
|
|
2013
|
+
declare function setTemporalWorkflowId(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<void>;
|
|
2014
|
+
declare function finishTurn(db: Database, workspaceId: string, turnId: string, status: SessionStatus | SessionTurnStatus): Promise<void>;
|
|
2015
|
+
/**
|
|
2016
|
+
* Put a preempted (worker shutdown mid-flight) turn back on the session
|
|
2017
|
+
* queue so the workflow's next claim re-dispatches it on a healthy worker.
|
|
2018
|
+
* The trigger event is swapped when the resumed attempt should enter
|
|
2019
|
+
* through a synthesized resume notice instead of replaying the original
|
|
2020
|
+
* trigger (the original input is already part of persisted conversation
|
|
2021
|
+
* truth by then). Keeping the original position lets the resumed turn run
|
|
2022
|
+
* before any turns queued behind it. Accepts `running` turns and
|
|
2023
|
+
* `requires_action` turns: an approval rerun re-dispatches the same turn
|
|
2024
|
+
* without a fresh claim, so the row still carries the approval-wait status
|
|
2025
|
+
* while the rerun activity executes.
|
|
2026
|
+
*/
|
|
2027
|
+
declare function requeuePreemptedTurn(db: Database, workspaceId: string, turnId: string, triggerEventId: string): Promise<void>;
|
|
2028
|
+
/**
|
|
2029
|
+
* Bump the per-turn worker-death redispatch counter and return the new value.
|
|
2030
|
+
* Stored in the turn row's metadata (not workflow-local state) so the
|
|
2031
|
+
* crash-loop guard is replay-safe: the count survives workflow replay, worker
|
|
2032
|
+
* restarts, and even a session-workflow re-run, and the increment is a single
|
|
2033
|
+
* atomic statement.
|
|
2034
|
+
*/
|
|
2035
|
+
declare function incrementTurnWorkerDeathRedispatches(db: Database, workspaceId: string, turnId: string): Promise<number>;
|
|
2036
|
+
declare function getSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn | null>;
|
|
2037
|
+
declare function listSessionTurns(db: Database, workspaceId: string, sessionId: string, limit?: number): Promise<SessionTurn[]>;
|
|
2038
|
+
declare function updateQueuedSessionTurn(db: Database, workspaceId: string, turnId: string, input: UpdateQueuedSessionTurnInput): Promise<SessionTurn>;
|
|
2039
|
+
declare function cancelQueuedSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn>;
|
|
2040
|
+
declare function reorderQueuedSessionTurns(db: Database, workspaceId: string, sessionId: string, turnIds: string[]): Promise<SessionTurn[]>;
|
|
2041
|
+
declare function appendSessionEvents(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[]): Promise<SessionEvent[]>;
|
|
2042
|
+
declare function appendSessionEventsAndUpdateSession(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[], update: {
|
|
2043
|
+
resources?: ResourceRef[];
|
|
2044
|
+
tools?: ToolRef[];
|
|
2045
|
+
model?: string;
|
|
2046
|
+
metadata?: Record<string, unknown>;
|
|
2047
|
+
status?: SessionStatus;
|
|
2048
|
+
activeTurnId?: string | null;
|
|
2049
|
+
}): Promise<SessionEvent[]>;
|
|
2050
|
+
declare function appendSessionEventsWithLockedSessionUpdate(db: Database, workspaceId: string, sessionId: string, build: (session: Session) => {
|
|
2051
|
+
events: AppendEventInput[];
|
|
2052
|
+
update?: {
|
|
2053
|
+
resources?: ResourceRef[];
|
|
2054
|
+
tools?: ToolRef[];
|
|
2055
|
+
model?: string;
|
|
2056
|
+
metadata?: Record<string, unknown>;
|
|
2057
|
+
status?: SessionStatus;
|
|
2058
|
+
activeTurnId?: string | null;
|
|
2059
|
+
};
|
|
2060
|
+
}): Promise<SessionEvent[]>;
|
|
2061
|
+
declare function sessionSubject(workspaceId: string, sessionId: string): string;
|
|
2062
|
+
|
|
2063
|
+
export { type SessionCodexState as $, type AccrueWarmSecondsResult as A, type BootstrapWorkspaceInput as B, CLEARED_RUN_STATE as C, type Database as D, type EnableCapabilityInstallationInput as E, type EnrollmentOs as F, type EnrollmentRecord as G, type EnrollmentStatus as H, type ForceDrainResult as I, type GitHubInstallation as J, type GoalContinuationDecision as K, type LeaseHolderKind as L, type LeaseSnapshot as M, MACHINE_METRICS_SERIES_INTERVAL_MS as N, type MachineMetricsRow as O, type MachineMetricsSample as P, type ProvisionResult, type ProvisionRolesOptions, type MeterableWarmLease as Q, type ReapDrainable as R, type RegisterWorkspacePackInput as S, type RlsContext as T, type RlsStrategy as U, SandboxImageConflictError as V, type SandboxKind as W, type SandboxLeaseLiveness as X, SandboxLeaseSupersededError as Y, type SandboxPtySessionRow as Z, type SandboxRecord as _, type AcquireLeaseInput as a, decryptedCapabilityHeaders as a$, type SessionRecordingCodec as a0, type SessionRecordingMode as a1, type SessionRecordingRow as a2, type SessionRecordingState as a3, type StreamAcknowledgment as a4, type UpdateQueuedSessionTurnInput as a5, type UpdateScheduledTaskInput as a6, type UserLookup as a7, type WakeParentForChildCompletionInput as a8, type WakeParentForChildCompletionResult as a9, countActiveSessionHistoryItems as aA, countActiveSessionsForWorkspace as aB, countActiveSessionsUsingEnvironment as aC, countConsecutiveReactiveRotations as aD, countScheduledTasksForWorkspace as aE, countScheduledTasksUsingEnvironment as aF, countSessionHistoryItems as aG, countTurnSessionHistoryItems as aH, countWorkspaceEnvironments as aI, countWorkspacesForAccount as aJ, createApiKey as aK, createDb as aL, createDeviceEnrollmentRequest as aM, createEnrollment as aN, createFileUpload as aO, createSandbox as aP, createScheduledTask as aQ, createScheduledTaskRun as aR, createSession as aS, createSessionGoal as aT, createSessionWithIdempotencyKey as aU, createSocialConnection as aV, createSocialPost as aW, createTurn as aX, createWorkspace as aY, createWorkspaceEnvironment as aZ, decryptEnvironmentValue as a_, type WorkspaceEnvironmentForRun as aa, accrueWarmSeconds as ab, acquireLease as ac, allAccountPermissions as ad, allWorkspacePermissions as ae, appendSessionEvents as af, appendSessionEventsAndUpdateSession as ag, appendSessionEventsWithLockedSessionUpdate as ah, appendSessionHistoryItems as ai, applyContextCompaction as aj, applyCreditDebitUpToBalance as ak, applyCreditLedgerEntry as al, approveDeviceEnrollmentRequest as am, bootstrapWorkspace as an, buildCodexTokenResolver as ao, cancelQueuedSessionTurn as ap, claimNextQueuedTurn as aq, clearSessionContext as ar, clearedContextMarkerItem as as, closePtySession as at, commitWarmingToWarm as au, completeFileUpload as av, confirmDrainCold as aw, consumeDeviceEnrollmentRequest as ax, consumeSessionCompactionRequest as ay, countActiveApiKeysForWorkspace as az, type AcquireLeaseResult as b, hasCreditLedgerEntry as b$, deleteRecording as b0, deleteScheduledTask as b1, deleteWorkspace as b2, deleteWorkspaceEnvironment as b3, deleteWorkspaceEnvironmentVariable as b4, deleteWorkspacePack as b5, denyDeviceEnrollmentRequest as b6, disableCapabilityInstallation as b7, disconnectAllCodexAccounts as b8, disconnectCodexAccount as b9, getManagedAccount as bA, getManagedUserByEmail as bB, getOpenPtySession as bC, getPackInstallation as bD, getPendingDeviceEnrollmentRequestByUserCode as bE, getPendingDeviceEnrollmentRequestByUserCodeGlobal as bF, getRecording as bG, getSandbox as bH, getSandboxSessionEnvelope as bI, getScheduledTask as bJ, getSession as bK, getSessionByCreateIdempotencyKey as bL, getSessionCodexState as bM, getSessionEvent as bN, getSessionGoal as bO, getSessionHistoryItems as bP, getSessionTurn as bQ, getSocialConnection as bR, getStoredCapabilityHeaderCiphertext as bS, getStreamAcknowledgment as bT, getWorkspace as bU, getWorkspaceEnvironment as bV, getWorkspaceEnvironmentByName as bW, getWorkspaceEnvironmentValuesForRun as bX, getWorkspaceGrant as bY, getWorkspacePack as bZ, grantWorkspaceAccess as b_, enableCapabilityInstallation as ba, enablePackInstallation as bb, encryptEnvironmentValue as bc, enqueueSessionTurn as bd, ensureCodexRotationSettings as be, ensureManagedAccessForUser as bf, evaluateGoalContinuation as bg, failWarmingToCold as bh, fetchCodexUsageForAccount as bi, finalizeEnrollmentByToken as bj, findActiveApiKeyByHash as bk, finishTurn as bl, forceDrainOverLimitViewerOnlyBoxes as bm, getActiveSessionHistoryItems as bn, getAnySessionInGroup as bo, getBillingBalance as bp, getBillingCustomer as bq, getCapabilityCatalogItem as br, getCapabilityInstallation as bs, getCodexCredentialStatus as bt, getCodexRotationSettings as bu, getDeviceEnrollmentRequestByDeviceCode as bv, getEnrollment as bw, getFile as bx, getFileUpload as by, getLatestRunState as bz, type ActiveSandboxPointer as c, releaseLeaseHolder as c$, heartbeatLeaseHolder as c0, incrementTurnWorkerDeathRedispatches as c1, ingestMachineMetricsSample as c2, insertMachineMetricsSeries as c3, insertPtySession as c4, insertRecording as c5, isCodexBilledTurn as c6, isStripeWebhookProcessed as c7, listApiKeys as c8, listCapabilityCatalogItems as c9, loadWorkspaceEnvironmentForRun as cA, markFileUploadFailed as cB, markStripeWebhookProcessed as cC, mcpServerIdForCapability as cD, nextSessionHistoryPosition as cE, orphanedResultRowIndicesForRepair as cF, persistDrainSnapshot as cG, reArmDrainingLease as cH, readActiveSandbox as cI, readLease as cJ, readMachineMetricsLatest as cK, readMachineMetricsLatestForWorkspace as cL, readMachineMetricsSeries as cM, reapStaleLeaseHolders as cN, reapStaleLeaseHoldersGlobal as cO, recordAuditEvent as cP, recordCodexAccountConnectors as cQ, recordCodexAccountUsage as cR, recordCodexTokenRefresh as cS, recordLeaseDataPlaneUrl as cT, recordLeaseTerminalDataPlaneUrl as cU, recordSessionActiveCodexCredential as cV, recordStreamAcknowledgment as cW, recordStripeWebhookEvent as cX, recordUsageEvent as cY, registerDbBinding as cZ, registerWorkspacePack as c_, listCapabilityInstallations as ca, listCodexAccountStatuses as cb, listDistinctEnvironmentIdsInGroup as cc, listEnabledMcpCapabilityServers as cd, listEnrollments as ce, listGitHubInstallationIdsForWorkspace as cf, listGitHubInstallationsForWorkspace as cg, listMeterableWarmLeases as ch, listOpenPtySessions as ci, listPackInstallations as cj, listRecordings as ck, listSandboxes as cl, listScheduledTaskRuns as cm, listScheduledTasks as cn, listSessionEvents as co, listSessionIdsInGroup as cp, listSessionTurns as cq, listSessions as cr, listSocialConnections as cs, listSocialPosts as ct, listUsageEvents as cu, listWorkspaceEnvironments as cv, listWorkspaceMembers as cw, listWorkspacePacks as cx, listWorkspacesForSubject as cy, loadCodexCredentialForRun as cz, type AppendEventInput as d, removeWorkspaceMember as d0, renameCodexAccount as d1, reorderQueuedSessionTurns as d2, requestSessionCompaction as d3, requeuePreemptedTurn as d4, requireFile as d5, requireScheduledTask as d6, requireSession as d7, requireSocialConnection as d8, requireWorkspace as d9, updatePackInstallationStatus as dA, updatePtySessionActivity as dB, updateQueuedSessionTurn as dC, updateRecording as dD, updateScheduledTask as dE, updateScheduledTaskRun as dF, updateSessionGoal as dG, updateSessionTitle as dH, updateWorkspace as dI, updateWorkspaceEnvironment as dJ, upsertBillingCustomer as dK, upsertCapabilityCatalogItem as dL, upsertCodexSubscriptionCredential as dM, upsertGitHubInstallation as dN, upsertMachineMetricsLatest as dO, upsertSandboxSessionEnvelope as dP, upsertSessionGoal as dQ, wakeParentSessionForChildCompletion as dR, withAccountRls as dS, withRlsContext as dT, withWorkspaceRls as dU, withWorkspaceUsageLock as dV, workspaceCodexSubscriptionActive as dW, revokeApiKey as da, revokeEnrollment as db, revokeViewer as dc, rlsContextForWorkspace as dd, rlsStrategyFor as de, sanitizeEventPayload as df, sanitizeEventString as dg, saveRunState as dh, sessionSubject as di, setActiveCodexCredential as dj, setActiveSandbox as dk, setCodexCredentialExhausted as dl, setCodexCredentialStatus as dm, setEnrollmentHasDisplay as dn, setRlsContext as dp, setSessionCodexPin as dq, setSessionGoalLastContinuationTurn as dr, setSessionGoalStatus as ds, setSessionLastInputTokens as dt, setSessionStatus as du, setTemporalWorkflowId as dv, setWorkspaceEnvironmentVariable as dw, sumUsageQuantity as dx, touchEnrollmentLastSeen as dy, updateCodexRotationSettings as dz, CODEX_ROTATION_STRATEGIES as e, 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 CreateSocialConnectionInput as s, type CreateSocialPostInput as t, type DbClient as u, type DeviceEnrollmentRequestRecord as v, type DeviceEnrollmentStatus as w, type EnabledMcpCapabilityServer as x, type EnqueueSessionTurnInput as y, type EnrollmentExposure as z };
|