@opengeni/contracts 0.9.0 → 0.10.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/index.js CHANGED
@@ -5,6 +5,9 @@ var SessionStatus = z.enum([
5
5
  "running",
6
6
  "idle",
7
7
  "requires_action",
8
+ "recovering",
9
+ "waiting_capacity",
10
+ "paused",
8
11
  "failed",
9
12
  "cancelled"
10
13
  ]);
@@ -414,8 +417,12 @@ var Permission = z.enum([
414
417
  "api_keys:manage",
415
418
  "connections:read",
416
419
  "connections:write",
420
+ /** @deprecated alias of variable-sets:manage */
417
421
  "environments:manage",
422
+ /** @deprecated alias of variable-sets:use */
418
423
  "environments:use",
424
+ "variable-sets:manage",
425
+ "variable-sets:use",
419
426
  // Attach or rotate per-session third-party MCP server credentials. Deliberately
420
427
  // not part of the worker's default first-party MCP permission set: a sandboxed
421
428
  // agent must not be able to hand itself new bearer credentials.
@@ -431,7 +438,14 @@ var Permission = z.enum([
431
438
  // enrollment grants WHOLE-MACHINE access to a user's own hardware — a high-trust,
432
439
  // admin-shaped action. workspace:admin is the super-wildcard over both.
433
440
  "enrollments:read",
434
- "enrollments:manage"
441
+ "enrollments:manage",
442
+ // Rigs (workspace-scoped, versioned sandbox machine definitions). rigs:use is
443
+ // read + propose-change (the agent-native, additive path a sandboxed session
444
+ // is trusted with); rigs:manage is create/edit/activate/promote/delete (the
445
+ // admin-shaped path that mints or rolls versions). workspace:admin is the
446
+ // super-wildcard over both.
447
+ "rigs:use",
448
+ "rigs:manage"
435
449
  ]);
436
450
  function prefixedMcpToolName(registryId2, toolName) {
437
451
  return `${registryId2}__${toolName}`;
@@ -459,12 +473,40 @@ var Workspace = z.object({
459
473
  // Per-workspace agent persona template (white-label override). null means
460
474
  // the deployment default (OPENGENI_AGENT_INSTRUCTIONS_TEMPLATE /
461
475
  // DEFAULT_AGENT_INSTRUCTIONS) is used. The runtime always injects the
462
- // non-bypassable CORE (goal-loop ownership + environment block), so an
476
+ // non-bypassable CORE (goal-loop ownership + variableSet block), so an
463
477
  // override restyles the persona without dropping that contract.
464
478
  agentInstructions: z.string().nullable(),
479
+ // Growth-ready per-workspace settings bag (migration 0045). Known keys are
480
+ // validated by WorkspaceSettingsSchema; unknown keys are preserved across
481
+ // PATCH merges so newer settings survive an older server.
482
+ settings: z.record(z.string(), z.unknown()),
483
+ inferenceState: z.enum(["active", "paused"]),
484
+ inferenceGeneration: z.number().int().nonnegative(),
485
+ inferenceReason: z.string().nullable(),
486
+ inferenceChangedBy: z.string().nullable(),
487
+ inferenceChangedAt: z.string().nullable(),
488
+ // Workspace default rig used by session/scheduled-task create fallback.
489
+ defaultRigId: z.string().uuid().nullable(),
465
490
  createdAt: z.string(),
466
491
  updatedAt: z.string()
467
492
  });
493
+ var WorkspaceSettingsSchema = z.object({
494
+ memoryEnabled: z.boolean().optional()
495
+ }).passthrough();
496
+ function resolveWorkspaceMemoryEnabled(settings) {
497
+ const parsed = WorkspaceSettingsSchema.safeParse(settings ?? {});
498
+ return parsed.success ? parsed.data.memoryEnabled === true : false;
499
+ }
500
+ var UpdateWorkspaceSettingsRequest = z.object({
501
+ memoryEnabled: z.boolean().optional()
502
+ }).passthrough();
503
+ var SetWorkspaceDefaultRigRequest = z.object({
504
+ rigId: z.string().uuid().nullable()
505
+ });
506
+ var UpdateWorkspaceModelPolicyRequest = z.object({
507
+ allowedProviders: z.array(z.string().min(1).max(128)).max(64).nullable().optional(),
508
+ allowedModels: z.array(z.string().min(1).max(256)).max(256).nullable().optional()
509
+ });
468
510
  var AccountGrant = z.object({
469
511
  accountId: z.string().uuid(),
470
512
  subjectId: z.string().min(1),
@@ -499,10 +541,18 @@ var DelegatedAccessTokenPayload = z.object({
499
541
  // Worker-asserted session scope for first-party MCP calls (HMAC-signed, not
500
542
  // agent-controlled); enables session-scoped tools such as goal management.
501
543
  sessionId: z.string().uuid().optional(),
544
+ // The turn making the call (the caller's identity), HMAC-signed by the worker
545
+ // at turn setup. Lets a tool classify WHO is calling from the token itself,
546
+ // instead of racily re-reading the session's live active_turn_id — e.g. the
547
+ // sacred-pause guard must know if the CALLER is a machine child-notification
548
+ // turn, and the active pointer can flip to another turn mid-check.
549
+ turnId: z.string().uuid().optional(),
502
550
  exp: z.number().int().positive()
503
551
  });
504
552
  async function signDelegatedAccessToken(secret, payload) {
505
- const encodedPayload = base64UrlEncode(JSON.stringify(DelegatedAccessTokenPayload.parse(payload)));
553
+ const encodedPayload = base64UrlEncode(
554
+ JSON.stringify(DelegatedAccessTokenPayload.parse(payload))
555
+ );
506
556
  const signature = await hmacSha256Base64Url(secret, encodedPayload);
507
557
  return `ogd_${encodedPayload}.${signature}`;
508
558
  }
@@ -521,7 +571,9 @@ async function verifyDelegatedAccessToken(secret, token, nowSeconds = Math.floor
521
571
  if (!constantTimeEqual(signature, expected)) {
522
572
  return null;
523
573
  }
524
- const payload = DelegatedAccessTokenPayload.safeParse(JSON.parse(base64UrlDecode(encodedPayload)));
574
+ const payload = DelegatedAccessTokenPayload.safeParse(
575
+ JSON.parse(base64UrlDecode(encodedPayload))
576
+ );
525
577
  if (!payload.success || payload.data.exp < nowSeconds) {
526
578
  return null;
527
579
  }
@@ -817,8 +869,24 @@ var LimitDecision = z.discriminatedUnion("allowed", [
817
869
  ]);
818
870
  var EntitlementDecision = z.discriminatedUnion("allowed", [
819
871
  z.object({ allowed: z.literal(true), quantity: z.number().optional() }),
820
- z.object({ allowed: z.literal(false), reason: z.string(), code: z.string().optional(), quantity: z.number().optional() })
872
+ z.object({
873
+ allowed: z.literal(false),
874
+ reason: z.string(),
875
+ code: z.string().optional(),
876
+ quantity: z.number().optional()
877
+ })
821
878
  ]);
879
+ var GitCredentialProvider = z.enum(["github", "gitlab", "azure_devops"]);
880
+ var GitProviderRepositoryId = z.union([z.number().int().positive(), z.string().min(1)]);
881
+ var GitCredentialRepositoryRef = z.object({
882
+ provider: GitCredentialProvider.optional(),
883
+ uri: z.string().min(1),
884
+ ref: z.string().min(1),
885
+ repositoryId: GitProviderRepositoryId.optional(),
886
+ installationId: GitProviderRepositoryId.optional(),
887
+ projectId: GitProviderRepositoryId.optional(),
888
+ connectionId: z.string().min(1).optional()
889
+ });
822
890
  var BillingBalance = z.object({
823
891
  accountId: z.string().uuid(),
824
892
  balanceMicros: z.number().int(),
@@ -844,6 +912,11 @@ var RepositoryResourceRef = z.object({
844
912
  ref: z.string().min(1),
845
913
  mountPath: z.string().min(1).optional(),
846
914
  subpath: z.string().min(1).optional(),
915
+ provider: GitCredentialProvider.optional(),
916
+ repositoryId: GitProviderRepositoryId.optional(),
917
+ installationId: GitProviderRepositoryId.optional(),
918
+ projectId: GitProviderRepositoryId.optional(),
919
+ connectionId: z.string().min(1).optional(),
847
920
  githubInstallationId: z.number().int().positive().optional(),
848
921
  githubRepositoryId: z.number().int().positive().optional()
849
922
  });
@@ -854,7 +927,13 @@ var FileResourceRef = z.object({
854
927
  });
855
928
  var ResourceRef = z.discriminatedUnion("kind", [RepositoryResourceRef, FileResourceRef]);
856
929
  var FileStatus = z.enum(["pending_upload", "ready", "failed", "expired", "deleted"]);
857
- var FileUploadStatus = z.enum(["pending", "completed", "expired", "failed"]);
930
+ var FileUploadStatus = z.enum([
931
+ "pending",
932
+ "cleanup_pending",
933
+ "completed",
934
+ "expired",
935
+ "failed"
936
+ ]);
858
937
  var FileAsset = z.object({
859
938
  id: z.string().uuid(),
860
939
  workspaceId: z.string().uuid(),
@@ -891,7 +970,16 @@ var FileDownloadUrlResponse = z.object({
891
970
  expiresAt: z.string()
892
971
  });
893
972
  var DocumentStatus = z.enum(["queued", "indexing", "ready", "failed"]);
894
- var KnowledgeSourceKind = z.enum(["manual_upload", "meeting_transcript", "repository", "email", "chat", "document", "web", "other"]);
973
+ var KnowledgeSourceKind = z.enum([
974
+ "manual_upload",
975
+ "meeting_transcript",
976
+ "repository",
977
+ "email",
978
+ "chat",
979
+ "document",
980
+ "web",
981
+ "other"
982
+ ]);
895
983
  var DocumentSearchMode = z.enum(["hybrid", "vector", "keyword"]);
896
984
  var DocumentBase = z.object({
897
985
  id: z.string().uuid(),
@@ -972,8 +1060,21 @@ var DocumentSearchRequest = z.object({
972
1060
  aclTags: z.array(z.string().min(1)).optional(),
973
1061
  limit: z.number().int().positive().max(50).default(5)
974
1062
  });
975
- var KnowledgeMemoryStatus = z.enum(["proposed", "approved", "rejected"]);
976
- var KnowledgeMemoryKind = z.enum(["semantic", "episodic", "procedural", "decision", "preference"]);
1063
+ var KnowledgeMemoryStatus = z.enum([
1064
+ "proposed",
1065
+ "approved",
1066
+ "rejected",
1067
+ "active",
1068
+ "superseded",
1069
+ "archived"
1070
+ ]);
1071
+ var KnowledgeMemoryKind = z.enum([
1072
+ "semantic",
1073
+ "episodic",
1074
+ "procedural",
1075
+ "decision",
1076
+ "preference"
1077
+ ]);
977
1078
  var KnowledgeSourceRef = z.object({
978
1079
  kind: z.enum(["document_chunk", "document", "session_event", "memory", "external"]),
979
1080
  id: z.string().min(1),
@@ -994,18 +1095,31 @@ var KnowledgeMemory = z.object({
994
1095
  createdBySessionId: z.string().uuid().nullable(),
995
1096
  reviewedBy: z.string().nullable(),
996
1097
  reviewedAt: z.string().nullable(),
1098
+ // Workspace Memory V1 fields. usageCount/lastUsedAt feed end-state ranking and
1099
+ // decay; supersedesId/supersededById link correction chains; validFrom/validUntil
1100
+ // are the point-in-time window. embedding/embeddingModel/textHash are internal
1101
+ // and never exposed on the wire.
1102
+ pinned: z.boolean(),
1103
+ usageCount: z.number().int(),
1104
+ lastUsedAt: z.string().nullable(),
1105
+ supersedesId: z.string().uuid().nullable(),
1106
+ supersededById: z.string().uuid().nullable(),
1107
+ validFrom: z.string(),
1108
+ validUntil: z.string().nullable(),
997
1109
  createdAt: z.string(),
998
1110
  updatedAt: z.string()
999
1111
  });
1000
1112
  var CreateKnowledgeMemoryRequest = z.object({
1001
- status: KnowledgeMemoryStatus.default("proposed"),
1113
+ status: KnowledgeMemoryStatus.default("active"),
1002
1114
  kind: KnowledgeMemoryKind.default("semantic"),
1003
1115
  scope: z.string().min(1).default("workspace"),
1004
1116
  text: z.string().min(1),
1005
1117
  sourceRefs: z.array(KnowledgeSourceRef).default([]),
1006
1118
  confidence: z.number().min(0).max(1).default(0.5),
1007
1119
  metadata: z.record(z.string(), z.unknown()).default({}),
1008
- createdBySessionId: z.string().uuid().optional()
1120
+ createdBySessionId: z.string().uuid().optional(),
1121
+ pinned: z.boolean().optional(),
1122
+ replacesId: z.string().min(1).optional()
1009
1123
  });
1010
1124
  var UpdateKnowledgeMemoryRequest = z.object({
1011
1125
  status: KnowledgeMemoryStatus.optional(),
@@ -1015,7 +1129,9 @@ var UpdateKnowledgeMemoryRequest = z.object({
1015
1129
  sourceRefs: z.array(KnowledgeSourceRef).optional(),
1016
1130
  confidence: z.number().min(0).max(1).optional(),
1017
1131
  metadata: z.record(z.string(), z.unknown()).optional(),
1018
- reviewedBy: z.string().min(1).optional()
1132
+ reviewedBy: z.string().min(1).optional(),
1133
+ // Human audit action: pin (never decays) / unpin.
1134
+ pinned: z.boolean().optional()
1019
1135
  });
1020
1136
  var KnowledgeMemorySearchRequest = z.object({
1021
1137
  query: z.string().min(1).optional(),
@@ -1024,6 +1140,23 @@ var KnowledgeMemorySearchRequest = z.object({
1024
1140
  scope: z.string().min(1).optional(),
1025
1141
  limit: z.number().int().positive().max(100).default(20)
1026
1142
  });
1143
+ var WorkspaceMemorySearchMode = z.enum(["hybrid", "vector", "keyword"]);
1144
+ var WorkspaceMemorySearchRequest = z.object({
1145
+ query: z.string().min(1),
1146
+ kind: KnowledgeMemoryKind.optional(),
1147
+ limit: z.number().int().positive().max(20).optional(),
1148
+ mode: WorkspaceMemorySearchMode.optional()
1149
+ });
1150
+ var WorkspaceMemorySearchResult = z.object({
1151
+ memory: KnowledgeMemory,
1152
+ score: z.number(),
1153
+ matchType: WorkspaceMemorySearchMode,
1154
+ vectorScore: z.number().nullable(),
1155
+ keywordScore: z.number().nullable()
1156
+ });
1157
+ var WorkspaceMemorySearchResponse = z.object({
1158
+ results: z.array(WorkspaceMemorySearchResult)
1159
+ });
1027
1160
  var ToolRef = z.object({
1028
1161
  kind: z.literal("mcp"),
1029
1162
  id: z.string().min(1),
@@ -1036,13 +1169,16 @@ var ToolRef = z.object({
1036
1169
  optional: z.boolean().optional()
1037
1170
  });
1038
1171
  var registryId = /^[A-Za-z0-9_-]+$/;
1039
- var httpsUrl = z.string().url().refine((value) => {
1040
- try {
1041
- return new URL(value).protocol === "https:";
1042
- } catch {
1043
- return false;
1044
- }
1045
- }, { message: "URL must use https" });
1172
+ var httpsUrl = z.string().url().refine(
1173
+ (value) => {
1174
+ try {
1175
+ return new URL(value).protocol === "https:";
1176
+ } catch {
1177
+ return false;
1178
+ }
1179
+ },
1180
+ { message: "URL must use https" }
1181
+ );
1046
1182
  var SessionMcpServerInput = z.object({
1047
1183
  id: z.string().min(1).regex(registryId),
1048
1184
  name: z.string().min(1).optional(),
@@ -1097,8 +1233,14 @@ function mergeToolRefs(existing, additions) {
1097
1233
  }
1098
1234
  function mergeResourceRefs(existing, additions, options = {}) {
1099
1235
  const out = [...existing];
1100
- const mountPaths = new Map(existing.flatMap((resource) => resource.mountPath ? [[resource.mountPath, stableJson(resource)]] : []));
1101
- const identities = new Map(existing.map((resource) => [resourceIdentityKey(resource), stableJson(resource)]));
1236
+ const mountPaths = new Map(
1237
+ existing.flatMap(
1238
+ (resource) => resource.mountPath ? [[resource.mountPath, stableJson(resource)]] : []
1239
+ )
1240
+ );
1241
+ const identities = new Map(
1242
+ existing.map((resource) => [resourceIdentityKey(resource), stableJson(resource)])
1243
+ );
1102
1244
  const exact = new Set(existing.map(stableJson));
1103
1245
  for (const resource of additions) {
1104
1246
  const serialized = stableJson(resource);
@@ -1108,12 +1250,16 @@ function mergeResourceRefs(existing, additions, options = {}) {
1108
1250
  if (options.rejectConflicts) {
1109
1251
  const existingAtMount = resource.mountPath ? mountPaths.get(resource.mountPath) : void 0;
1110
1252
  if (existingAtMount && existingAtMount !== serialized) {
1111
- throw new ResourceRefConflictError(`resource mount path is already attached: ${resource.mountPath}`);
1253
+ throw new ResourceRefConflictError(
1254
+ `resource mount path is already attached: ${resource.mountPath}`
1255
+ );
1112
1256
  }
1113
1257
  const identity = resourceIdentityKey(resource);
1114
1258
  const existingIdentity = identities.get(identity);
1115
1259
  if (existingIdentity && existingIdentity !== serialized) {
1116
- throw new ResourceRefConflictError(`resource is already attached with different settings: ${identity}`);
1260
+ throw new ResourceRefConflictError(
1261
+ `resource is already attached with different settings: ${identity}`
1262
+ );
1117
1263
  }
1118
1264
  }
1119
1265
  out.push(resource);
@@ -1143,17 +1289,38 @@ function sortJson(value) {
1143
1289
  return value.map(sortJson);
1144
1290
  }
1145
1291
  if (value && typeof value === "object") {
1146
- return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, nested]) => [key, sortJson(nested)]));
1292
+ return Object.fromEntries(
1293
+ Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, nested]) => [key, sortJson(nested)])
1294
+ );
1147
1295
  }
1148
1296
  return value;
1149
1297
  }
1150
- var SessionTurnStatus = z.enum(["queued", "running", "requires_action", "completed", "failed", "cancelled"]);
1151
- var SessionTurnSource = z.enum(["user", "scheduled_task", "api", "goal"]);
1298
+ var SessionTurnStatus = z.enum([
1299
+ "queued",
1300
+ "running",
1301
+ "requires_action",
1302
+ "recovering",
1303
+ "waiting_capacity",
1304
+ "completed",
1305
+ "failed",
1306
+ "cancelled",
1307
+ "superseded"
1308
+ ]);
1309
+ var SessionTurnSource = z.enum([
1310
+ "user",
1311
+ "scheduled_task",
1312
+ "api",
1313
+ "goal",
1314
+ "system",
1315
+ "compaction"
1316
+ ]);
1317
+ var SessionControlState = z.enum(["active", "paused"]);
1318
+ var WorkspaceInferenceState = z.enum(["active", "paused"]);
1152
1319
  var SessionGoalStatus = z.enum(["active", "paused", "completed"]);
1153
1320
  var SessionGoalCreatedBy = z.enum(["api", "agent", "scheduled_task"]);
1154
1321
  var SessionGoalPausedReason = z.enum([
1155
1322
  "agent",
1156
- "user_interrupt",
1323
+ "user_pause",
1157
1324
  "api",
1158
1325
  "no_progress",
1159
1326
  "max_auto_continuations",
@@ -1191,6 +1358,10 @@ var UpdateSessionGoalRequest = z.object({
1191
1358
  var UpdateSessionRequest = z.object({
1192
1359
  title: z.string().min(1).max(200)
1193
1360
  });
1361
+ var UpdateSessionPinRequest = z.object({
1362
+ pinned: z.boolean(),
1363
+ expectedVersion: z.number().int().nonnegative().optional()
1364
+ });
1194
1365
  var ClearSessionContextRequest = z.object({
1195
1366
  confirm: z.literal(true)
1196
1367
  });
@@ -1209,9 +1380,10 @@ function isClearedRunStateBlob(serialized) {
1209
1380
  }
1210
1381
  var CompactSessionContextRequest = z.object({}).strict();
1211
1382
  var CompactSessionContextResult = z.object({
1212
- // queued: a client-side (Azure) compaction will run before the next turn.
1213
- // noop: nothing to do (server-managed provider, mode off, or no history).
1214
- status: z.enum(["queued", "noop"]),
1383
+ // pending: an active/paused session will compact at its next safe boundary.
1384
+ // completed: an idle compaction-only activity completed synchronously.
1385
+ // noop: there is no active history to compact.
1386
+ status: z.enum(["pending", "completed", "noop"]),
1215
1387
  message: z.string()
1216
1388
  });
1217
1389
  var SessionTurn = z.object({
@@ -1222,7 +1394,7 @@ var SessionTurn = z.object({
1222
1394
  temporalWorkflowId: z.string(),
1223
1395
  status: SessionTurnStatus,
1224
1396
  source: SessionTurnSource,
1225
- position: z.number().int().positive(),
1397
+ position: z.number().int(),
1226
1398
  prompt: z.string().min(1),
1227
1399
  resources: z.array(ResourceRef),
1228
1400
  tools: z.array(ToolRef),
@@ -1232,55 +1404,232 @@ var SessionTurn = z.object({
1232
1404
  // Per-turn OS override. NULL = inherit the session's sandboxOs.
1233
1405
  sandboxOs: SandboxOs.nullable(),
1234
1406
  metadata: z.record(z.string(), z.unknown()),
1407
+ version: z.number().int().positive(),
1408
+ executionGeneration: z.number().int().nonnegative(),
1409
+ activeAttemptId: z.string().uuid().nullable(),
1410
+ lineage: z.record(z.string(), z.unknown()),
1411
+ cancelledBy: z.string().nullable(),
1412
+ cancelReason: z.string().nullable(),
1235
1413
  startedAt: z.string().nullable(),
1236
1414
  finishedAt: z.string().nullable(),
1237
1415
  createdAt: z.string(),
1238
1416
  updatedAt: z.string()
1239
1417
  });
1240
- var UpdateSessionTurnRequest = z.object({
1241
- prompt: z.string().min(1).optional(),
1242
- resources: z.array(ResourceRef).optional(),
1243
- tools: z.array(ToolRef).optional(),
1244
- model: z.string().min(1).optional(),
1245
- reasoningEffort: ReasoningEffort.optional(),
1246
- sandboxBackend: SandboxBackend.optional(),
1247
- metadata: z.record(z.string(), z.unknown()).optional()
1248
- });
1249
- var ReorderSessionTurnsRequest = z.object({
1250
- turnIds: z.array(z.string().uuid()).min(1)
1418
+ var SessionQueueSnapshot = z.object({
1419
+ version: z.number().int().nonnegative(),
1420
+ controlState: SessionControlState,
1421
+ controlGeneration: z.number().int().nonnegative(),
1422
+ workspaceInferenceState: WorkspaceInferenceState,
1423
+ workspaceInferenceGeneration: z.number().int().nonnegative(),
1424
+ workspaceRunExceptionGeneration: z.number().int().nonnegative().nullable(),
1425
+ items: z.array(SessionTurn)
1426
+ });
1427
+ var CancelSessionQueueItemRequest = z.object({
1428
+ expectedQueueVersion: z.number().int().nonnegative(),
1429
+ expectedItemVersion: z.number().int().positive(),
1430
+ reason: z.string().min(1).optional()
1431
+ });
1432
+ var SessionControlRequest = z.object({
1433
+ mode: z.enum(["pause", "resume"]),
1434
+ reason: z.string().min(1).optional(),
1435
+ clientEventId: z.string().min(1).optional(),
1436
+ expectedControlState: SessionControlState.optional(),
1437
+ expectedControlGeneration: z.number().int().nonnegative().optional(),
1438
+ expectedWorkspaceInferenceGeneration: z.number().int().nonnegative().optional()
1439
+ });
1440
+ var WorkspaceInferenceControlRequest = z.object({
1441
+ state: WorkspaceInferenceState,
1442
+ reason: z.string().min(1),
1443
+ clientEventId: z.string().min(1),
1444
+ expectedState: WorkspaceInferenceState,
1445
+ expectedGeneration: z.number().int().nonnegative(),
1446
+ exceptSessionIds: z.array(z.string().uuid()).default([])
1447
+ });
1448
+ var WorkspaceInferenceControlResponse = z.object({
1449
+ operationId: z.string().uuid(),
1450
+ state: WorkspaceInferenceState,
1451
+ generation: z.number().int().nonnegative(),
1452
+ affectedSessionIds: z.array(z.string().uuid()),
1453
+ controlSessionIds: z.array(z.string().uuid()),
1454
+ exceptionSessionIds: z.array(z.string().uuid())
1455
+ });
1456
+ var SystemUpdateClassification = z.enum(["success", "failure", "action_required", "info"]);
1457
+ var SessionSystemUpdateKind = z.enum([
1458
+ "child_session_update",
1459
+ "scheduled_wake",
1460
+ "lifecycle_event",
1461
+ "runtime_notice"
1462
+ ]);
1463
+ var SessionSystemUpdateState = z.enum([
1464
+ "pending",
1465
+ "deferred",
1466
+ "delivered",
1467
+ "cancelled",
1468
+ "failed"
1469
+ ]);
1470
+ var SessionSystemUpdate = z.object({
1471
+ id: z.string().uuid(),
1472
+ sessionId: z.string().uuid(),
1473
+ kind: SessionSystemUpdateKind,
1474
+ classification: SystemUpdateClassification,
1475
+ sourceId: z.string(),
1476
+ dedupeKey: z.string(),
1477
+ summary: z.string(),
1478
+ payload: z.record(z.string(), z.unknown()),
1479
+ lineage: z.record(z.string(), z.unknown()),
1480
+ state: SessionSystemUpdateState,
1481
+ deliveredTurnId: z.string().uuid().nullable(),
1482
+ deliveredAt: z.string().nullable(),
1483
+ createdAt: z.string()
1251
1484
  });
1252
- var WorkspaceEnvironmentVariableName = z.string().regex(/^[A-Z][A-Z0-9_]*$/).max(128);
1253
- var WorkspaceEnvironmentVariableMetadata = z.object({
1254
- name: WorkspaceEnvironmentVariableName,
1485
+ var VariableSetVariableName = z.string().regex(/^[A-Z][A-Z0-9_]*$/).max(128);
1486
+ function withVariableSetIdAlias(shape) {
1487
+ return z.preprocess((input) => {
1488
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
1489
+ return input;
1490
+ }
1491
+ const record = input;
1492
+ if (record.variableSetId !== void 0 || record.environmentId === void 0) {
1493
+ return record;
1494
+ }
1495
+ return { ...record, variableSetId: record.environmentId };
1496
+ }, z.object(shape));
1497
+ }
1498
+ var VariableSetVariableMetadata = z.object({
1499
+ name: VariableSetVariableName,
1255
1500
  version: z.number().int().positive(),
1256
1501
  createdAt: z.string(),
1257
1502
  updatedAt: z.string()
1258
1503
  });
1259
- var WorkspaceEnvironment = z.object({
1504
+ var WorkspaceEnvironmentVariableMetadata = VariableSetVariableMetadata;
1505
+ var VariableSet = z.object({
1260
1506
  id: z.string().uuid(),
1261
1507
  accountId: z.string().uuid(),
1262
1508
  workspaceId: z.string().uuid(),
1263
1509
  name: z.string(),
1264
1510
  description: z.string().nullable(),
1265
- variables: z.array(WorkspaceEnvironmentVariableMetadata),
1511
+ variables: z.array(VariableSetVariableMetadata),
1266
1512
  createdAt: z.string(),
1267
1513
  updatedAt: z.string()
1268
1514
  });
1269
- var CreateWorkspaceEnvironmentRequest = z.object({
1515
+ var WorkspaceEnvironment = VariableSet;
1516
+ var CreateVariableSetRequest = z.object({
1270
1517
  name: z.string().min(1).max(120),
1271
1518
  description: z.string().max(2e3).optional(),
1272
- variables: z.array(z.object({
1273
- name: WorkspaceEnvironmentVariableName,
1274
- value: z.string().min(1).max(32768)
1275
- })).default([])
1519
+ variables: z.array(
1520
+ z.object({
1521
+ name: VariableSetVariableName,
1522
+ value: z.string().min(1).max(32768)
1523
+ })
1524
+ ).default([])
1276
1525
  });
1277
- var UpdateWorkspaceEnvironmentRequest = z.object({
1526
+ var CreateWorkspaceEnvironmentRequest = CreateVariableSetRequest;
1527
+ var UpdateVariableSetRequest = z.object({
1278
1528
  name: z.string().min(1).max(120).optional(),
1279
1529
  description: z.string().max(2e3).nullable().optional()
1280
1530
  });
1281
- var SetWorkspaceEnvironmentVariableRequest = z.object({
1531
+ var UpdateWorkspaceEnvironmentRequest = UpdateVariableSetRequest;
1532
+ var SetVariableSetVariableRequest = z.object({
1282
1533
  value: z.string().min(1).max(32768)
1283
1534
  });
1535
+ var SetWorkspaceEnvironmentVariableRequest = SetVariableSetVariableRequest;
1536
+ var RigCheck = z.object({
1537
+ name: z.string().min(1).max(120),
1538
+ command: z.string().min(1).max(8192)
1539
+ });
1540
+ var RigVersion = z.object({
1541
+ id: z.string().uuid(),
1542
+ rigId: z.string().uuid(),
1543
+ version: z.number().int().positive(),
1544
+ image: z.string().nullable(),
1545
+ setupScript: z.string().nullable(),
1546
+ checks: z.array(RigCheck),
1547
+ credentialHooks: z.array(z.string()),
1548
+ defaultVariableSetIds: z.array(z.string().uuid()),
1549
+ changelog: z.string().nullable(),
1550
+ // Attribution: 'user:<subject>' | 'session:<id>' | 'system'.
1551
+ createdBy: z.string().nullable(),
1552
+ active: z.boolean(),
1553
+ createdAt: z.string()
1554
+ });
1555
+ var RigVerificationHealth = z.object({
1556
+ checkHealth: z.enum(["passing", "failing", "unknown"]),
1557
+ lastVerifiedAt: z.string().nullable()
1558
+ });
1559
+ var Rig = z.object({
1560
+ id: z.string().uuid(),
1561
+ accountId: z.string().uuid(),
1562
+ workspaceId: z.string().uuid(),
1563
+ name: z.string(),
1564
+ description: z.string().nullable(),
1565
+ createdBy: z.string().nullable(),
1566
+ // The rig's currently-active version (present after create; nullable so a
1567
+ // partial/list read can omit it without a schema change).
1568
+ activeVersion: RigVersion.nullable(),
1569
+ // Summary for the currently active version. null only when there is no active
1570
+ // version; otherwise "unknown" means the active version has no verification.
1571
+ activeVersionHealth: RigVerificationHealth.nullable(),
1572
+ versionCount: z.number().int().nonnegative(),
1573
+ createdAt: z.string(),
1574
+ updatedAt: z.string()
1575
+ });
1576
+ var RigChangeKind = z.enum(["setup_append", "definition_edit"]);
1577
+ var RigChangeStatus = z.enum(["proposed", "verifying", "merged", "rejected", "failed"]);
1578
+ var RigCheckResult = z.object({
1579
+ name: z.string(),
1580
+ command: z.string(),
1581
+ exitCode: z.number().int().nullable(),
1582
+ output: z.string().optional()
1583
+ });
1584
+ var RigChangeVerification = z.object({
1585
+ startedAt: z.string().optional(),
1586
+ finishedAt: z.string().optional(),
1587
+ log: z.string().optional(),
1588
+ checkResults: z.array(RigCheckResult).optional()
1589
+ }).passthrough();
1590
+ var RigChange = z.object({
1591
+ id: z.string().uuid(),
1592
+ rigId: z.string().uuid(),
1593
+ baseVersionId: z.string().uuid().nullable(),
1594
+ kind: RigChangeKind,
1595
+ payload: z.record(z.string(), z.unknown()),
1596
+ status: RigChangeStatus,
1597
+ proposedBy: z.string().nullable(),
1598
+ verification: RigChangeVerification.nullable(),
1599
+ resultVersionId: z.string().uuid().nullable(),
1600
+ createdAt: z.string(),
1601
+ updatedAt: z.string()
1602
+ });
1603
+ var CreateRigRequest = z.object({
1604
+ name: z.string().min(1).max(120),
1605
+ description: z.string().max(2e3).optional(),
1606
+ // Initial (version 1) content, inline.
1607
+ image: z.string().max(1024).optional(),
1608
+ setupScript: z.string().max(131072).optional(),
1609
+ checks: z.array(RigCheck).max(100).default([]),
1610
+ credentialHooks: z.array(z.string().min(1).max(200)).max(50).default([]),
1611
+ defaultVariableSetIds: z.array(z.string().uuid()).max(25).default([])
1612
+ });
1613
+ var UpdateRigRequest = z.object({
1614
+ name: z.string().min(1).max(120).optional(),
1615
+ description: z.string().max(2e3).nullable().optional()
1616
+ });
1617
+ var RigSetupAppendPayload = z.object({
1618
+ command: z.string().min(1).max(8192),
1619
+ note: z.string().max(2e3).optional()
1620
+ });
1621
+ var RigDefinitionEditPayload = z.object({
1622
+ image: z.string().max(1024).nullish(),
1623
+ setupScript: z.string().max(131072).nullish(),
1624
+ checks: z.array(RigCheck).max(100).optional(),
1625
+ credentialHooks: z.array(z.string().min(1).max(200)).max(50).optional(),
1626
+ defaultVariableSetIds: z.array(z.string().uuid()).max(25).optional(),
1627
+ changelog: z.string().max(4096).nullish()
1628
+ });
1629
+ var ProposeRigChangeRequest = z.discriminatedUnion("kind", [
1630
+ z.object({ kind: z.literal("setup_append"), payload: RigSetupAppendPayload }),
1631
+ z.object({ kind: z.literal("definition_edit"), payload: RigDefinitionEditPayload })
1632
+ ]);
1284
1633
  var ScheduledTaskStatus = z.enum(["active", "paused"]);
1285
1634
  var ScheduledTaskRunStatus = z.enum(["queued", "dispatched", "failed"]);
1286
1635
  var ScheduledTaskRunMode = z.enum(["new_session_per_run", "reusable_session"]);
@@ -1328,7 +1677,13 @@ var ScheduledTask = z.object({
1328
1677
  overlapPolicy: ScheduledTaskOverlapPolicy,
1329
1678
  agentConfig: ScheduledTaskAgentConfig,
1330
1679
  reusableSessionId: z.string().uuid().nullable(),
1331
- environmentId: z.string().uuid().nullable(),
1680
+ variableSetId: z.string().uuid().nullable().default(null),
1681
+ /** @deprecated use variableSetId */
1682
+ environmentId: z.string().uuid().nullable().default(null),
1683
+ // The rig each run binds to (M3). Stored on the task; the ACTIVE version is
1684
+ // resolved PER FIRE (at dispatch), so a task always runs the rig's current
1685
+ // version rather than one frozen at task-create time. Null ⇒ rig-less runs.
1686
+ rigId: z.string().uuid().nullable().default(null),
1332
1687
  metadata: z.record(z.string(), z.unknown()),
1333
1688
  createdAt: z.string(),
1334
1689
  updatedAt: z.string()
@@ -1348,24 +1703,31 @@ var ScheduledTaskRun = z.object({
1348
1703
  createdAt: z.string(),
1349
1704
  updatedAt: z.string()
1350
1705
  });
1351
- var CreateScheduledTaskRequest = z.object({
1706
+ var CreateScheduledTaskRequest = withVariableSetIdAlias({
1352
1707
  name: z.string().min(1),
1353
1708
  schedule: ScheduledTaskScheduleSpec,
1354
1709
  runMode: ScheduledTaskRunMode.default("new_session_per_run"),
1355
1710
  overlapPolicy: ScheduledTaskOverlapPolicy.default("allow_concurrent"),
1356
1711
  agentConfig: ScheduledTaskAgentConfig,
1357
1712
  status: ScheduledTaskStatus.default("active"),
1713
+ variableSetId: z.string().uuid().nullable().optional(),
1358
1714
  environmentId: z.string().uuid().nullable().optional(),
1715
+ // The rig each run binds to (M3); its active version is resolved per fire.
1716
+ rigId: z.string().uuid().nullable().optional(),
1359
1717
  metadata: z.record(z.string(), z.unknown()).default({})
1360
1718
  });
1361
- var UpdateScheduledTaskRequest = z.object({
1719
+ var UpdateScheduledTaskRequest = withVariableSetIdAlias({
1362
1720
  name: z.string().min(1).optional(),
1363
1721
  schedule: ScheduledTaskScheduleSpec.optional(),
1364
1722
  runMode: ScheduledTaskRunMode.optional(),
1365
1723
  overlapPolicy: ScheduledTaskOverlapPolicy.optional(),
1366
1724
  agentConfig: ScheduledTaskAgentConfig.optional(),
1367
1725
  status: ScheduledTaskStatus.optional(),
1726
+ variableSetId: z.string().uuid().nullable().optional(),
1368
1727
  environmentId: z.string().uuid().nullable().optional(),
1728
+ // The rig each run binds to (M3); null clears it. Its active version is
1729
+ // resolved per fire, so an update takes effect on the next dispatch.
1730
+ rigId: z.string().uuid().nullable().optional(),
1369
1731
  metadata: z.record(z.string(), z.unknown()).optional()
1370
1732
  });
1371
1733
  var TriggerScheduledTaskRequest = z.object({
@@ -1421,12 +1783,20 @@ var CapabilityPackSkill = z.object({
1421
1783
  const seen = /* @__PURE__ */ new Set();
1422
1784
  skill.files.forEach((file, index) => {
1423
1785
  if (seen.has(file.path)) {
1424
- ctx.addIssue({ code: "custom", message: `duplicate skill file path: ${file.path}`, path: ["files", index, "path"] });
1786
+ ctx.addIssue({
1787
+ code: "custom",
1788
+ message: `duplicate skill file path: ${file.path}`,
1789
+ path: ["files", index, "path"]
1790
+ });
1425
1791
  }
1426
1792
  seen.add(file.path);
1427
1793
  });
1428
1794
  if (!skill.files.some((file) => file.path === "SKILL.md")) {
1429
- ctx.addIssue({ code: "custom", message: "skill must include a top-level SKILL.md file", path: ["files"] });
1795
+ ctx.addIssue({
1796
+ code: "custom",
1797
+ message: "skill must include a top-level SKILL.md file",
1798
+ path: ["files"]
1799
+ });
1430
1800
  }
1431
1801
  });
1432
1802
  function isSafePackSkillRelativePath(path) {
@@ -1435,39 +1805,71 @@ function isSafePackSkillRelativePath(path) {
1435
1805
  }
1436
1806
  return path.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
1437
1807
  }
1438
- var CapabilityPack = z.object({
1439
- id: z.string().min(1),
1440
- name: z.string().min(1),
1808
+ var CapabilityPackVariableSet = z.object({
1441
1809
  description: z.string().min(1),
1442
- role: z.string().min(1),
1443
- category: z.string().min(1),
1444
- version: z.string().min(1),
1445
- // Container image ref (digest-pinned recommended) the pack's sessions run
1446
- // in. At most one enabled pack per workspace may declare one; with none,
1447
- // sessions use the deployment-wide image settings.
1448
- sandboxImage: z.string().trim().min(1).max(512).optional(),
1449
- // Skills delivered into the sandbox skill index when the pack is enabled.
1450
- skills: z.array(CapabilityPackSkill).max(32).superRefine((skills, ctx) => {
1451
- const seen = /* @__PURE__ */ new Set();
1452
- skills.forEach((skill, index) => {
1453
- const key = skill.name.toLowerCase();
1454
- if (seen.has(key)) {
1455
- ctx.addIssue({ code: "custom", message: `duplicate pack skill name: ${skill.name}`, path: [index, "name"] });
1456
- }
1457
- seen.add(key);
1458
- });
1459
- }).default([]),
1460
- tools: z.array(ToolRef).default([]),
1461
- connectors: z.array(CapabilityPackConnector).default([]),
1462
- knowledge: z.array(CapabilityPackKnowledge).default([]),
1463
- scheduledTaskTemplates: z.array(CapabilityPackScheduledTaskTemplate).default([]),
1464
- environment: z.object({
1465
- description: z.string().min(1),
1466
- requiredVariables: z.array(WorkspaceEnvironmentVariableName).default([]),
1467
- required: z.boolean().default(false)
1468
- }).optional(),
1469
- metadata: z.record(z.string(), z.unknown()).default({})
1810
+ requiredVariables: z.array(VariableSetVariableName).default([]),
1811
+ required: z.boolean().default(false)
1470
1812
  });
1813
+ var CapabilityPack = z.preprocess(
1814
+ (input) => {
1815
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
1816
+ return input;
1817
+ }
1818
+ const record = input;
1819
+ if (record.variableSet !== void 0) {
1820
+ return record;
1821
+ }
1822
+ if (record.environment !== void 0) {
1823
+ const { environment: _environment, ...rest } = record;
1824
+ return { ...rest, variableSet: record.environment };
1825
+ }
1826
+ if (record.requiredVariables !== void 0) {
1827
+ const { requiredVariables: _requiredVariables, ...rest } = record;
1828
+ return {
1829
+ ...rest,
1830
+ variableSet: {
1831
+ description: "Required variables",
1832
+ requiredVariables: record.requiredVariables,
1833
+ required: Array.isArray(record.requiredVariables) && record.requiredVariables.length > 0
1834
+ }
1835
+ };
1836
+ }
1837
+ return record;
1838
+ },
1839
+ z.object({
1840
+ id: z.string().min(1),
1841
+ name: z.string().min(1),
1842
+ description: z.string().min(1),
1843
+ role: z.string().min(1),
1844
+ category: z.string().min(1),
1845
+ version: z.string().min(1),
1846
+ // Container image ref (digest-pinned recommended) the pack's sessions run
1847
+ // in. At most one enabled pack per workspace may declare one; with none,
1848
+ // sessions use the deployment-wide image settings.
1849
+ sandboxImage: z.string().trim().min(1).max(512).optional(),
1850
+ // Skills delivered into the sandbox skill index when the pack is enabled.
1851
+ skills: z.array(CapabilityPackSkill).max(32).superRefine((skills, ctx) => {
1852
+ const seen = /* @__PURE__ */ new Set();
1853
+ skills.forEach((skill, index) => {
1854
+ const key = skill.name.toLowerCase();
1855
+ if (seen.has(key)) {
1856
+ ctx.addIssue({
1857
+ code: "custom",
1858
+ message: `duplicate pack skill name: ${skill.name}`,
1859
+ path: [index, "name"]
1860
+ });
1861
+ }
1862
+ seen.add(key);
1863
+ });
1864
+ }).default([]),
1865
+ tools: z.array(ToolRef).default([]),
1866
+ connectors: z.array(CapabilityPackConnector).default([]),
1867
+ knowledge: z.array(CapabilityPackKnowledge).default([]),
1868
+ scheduledTaskTemplates: z.array(CapabilityPackScheduledTaskTemplate).default([]),
1869
+ variableSet: CapabilityPackVariableSet.optional(),
1870
+ metadata: z.record(z.string(), z.unknown()).default({})
1871
+ })
1872
+ );
1471
1873
  var RegisterCapabilityPackRequest = CapabilityPack;
1472
1874
  var WorkspaceRegisteredPack = z.object({
1473
1875
  accountId: z.string().uuid(),
@@ -1487,7 +1889,8 @@ var PackInstallation = z.object({
1487
1889
  enabledAt: z.string(),
1488
1890
  updatedAt: z.string()
1489
1891
  });
1490
- var EnablePackRequest = z.object({
1892
+ var EnablePackRequest = withVariableSetIdAlias({
1893
+ variableSetId: z.string().uuid().optional(),
1491
1894
  environmentId: z.string().uuid().optional(),
1492
1895
  metadata: z.record(z.string(), z.unknown()).default({})
1493
1896
  });
@@ -1615,7 +2018,12 @@ var OAuthStartRequest = z.object({
1615
2018
  resource: z.string().url().optional(),
1616
2019
  requestedScopes: z.array(z.string().min(1)).default([]),
1617
2020
  returnPath: z.string().min(1).optional(),
1618
- connectionId: z.string().uuid().optional()
2021
+ connectionId: z.string().uuid().optional(),
2022
+ oauthClient: z.object({
2023
+ clientId: z.string().min(1),
2024
+ clientSecret: z.string().min(1).optional(),
2025
+ tokenEndpointAuthMethod: z.enum(["none", "client_secret_post", "client_secret_basic"]).optional()
2026
+ }).optional()
1619
2027
  }).refine((value) => Boolean(value.mcpUrl ?? value.resource), {
1620
2028
  message: "mcpUrl is required",
1621
2029
  path: ["mcpUrl"]
@@ -1646,7 +2054,13 @@ var MarketingDailyAnalysisTaskRequest = z.object({
1646
2054
  overlapPolicy: ScheduledTaskOverlapPolicy.default("skip")
1647
2055
  });
1648
2056
  var CapabilityKind = z.enum(["pack", "mcp", "api", "skill", "plugin"]);
1649
- var CapabilitySource = z.enum(["built_in", "configured", "public_registry", "registry", "manual"]);
2057
+ var CapabilitySource = z.enum([
2058
+ "built_in",
2059
+ "configured",
2060
+ "public_registry",
2061
+ "registry",
2062
+ "manual"
2063
+ ]);
1650
2064
  var CapabilityInstallationStatus = z.enum(["active", "disabled"]);
1651
2065
  var CapabilityCatalogAuthKind = z.enum(["oauth2", "api_key", "none", "unknown"]);
1652
2066
  var CapabilityCatalogTier = z.enum(["verified", "community"]);
@@ -1686,6 +2100,15 @@ var CapabilityCatalogItem = z.object({
1686
2100
  runtime: CapabilityRuntime.default({ available: false, notes: null }),
1687
2101
  enabled: z.boolean().default(false),
1688
2102
  enabledReason: z.string().nullable().default(null),
2103
+ // The connection backing this enabled installation, when the enable-time
2104
+ // connectionRef resolved to one (null for header/credential-free items —
2105
+ // that means "no connection involved", not "broken"). Lets the UI match
2106
+ // connection health by id instead of guessing from providerDomain alone.
2107
+ connectionRef: z.object({
2108
+ connectionId: z.string().min(1),
2109
+ providerDomain: z.string().min(1),
2110
+ kind: z.string().min(1)
2111
+ }).nullable().default(null),
1689
2112
  metadata: z.record(z.string(), z.unknown()).default({}),
1690
2113
  createdAt: z.string().optional(),
1691
2114
  updatedAt: z.string().optional()
@@ -1716,23 +2139,24 @@ var CreateCapabilityCatalogItemRequest = z.object({
1716
2139
  authModel: z.string().min(1).optional(),
1717
2140
  metadata: z.record(z.string(), z.unknown()).default({})
1718
2141
  });
1719
- var EnableCapabilityRequest = z.object({
2142
+ var EnableCapabilityRequest = withVariableSetIdAlias({
1720
2143
  config: z.record(z.string(), z.unknown()).default({}),
1721
2144
  metadata: z.record(z.string(), z.unknown()).default({}),
1722
2145
  connectionRef: McpServerConnectionRef.optional(),
1723
2146
  /**
1724
2147
  * Credential headers for remote MCP capabilities (for example an
1725
2148
  * Authorization bearer token). Values are encrypted at rest with the
1726
- * workspace-environments key, injected only into the runtime MCP client,
2149
+ * workspace-variable-sets key, injected only into the runtime MCP client,
1727
2150
  * and never returned by the API — responses expose header names only.
1728
2151
  */
1729
2152
  headers: z.record(z.string(), z.string()).default({}),
1730
2153
  /**
1731
- * Initial environment attachment for kind=pack capabilities. Mirrors the
2154
+ * Initial variableSet attachment for kind=pack capabilities. Mirrors the
1732
2155
  * dedicated POST /packs/:id/enable body: required to enable an
1733
- * environment.required pack through the unified capability-enable path,
2156
+ * variableSet.required pack through the unified capability-enable path,
1734
2157
  * optional otherwise. Ignored by non-pack capabilities.
1735
2158
  */
2159
+ variableSetId: z.string().uuid().optional(),
1736
2160
  environmentId: z.string().uuid().optional()
1737
2161
  });
1738
2162
  var CapabilityCatalogResponse = z.object({
@@ -1774,7 +2198,16 @@ var Session = z.object({
1774
2198
  // stale in-flight op and retry against the new active sandbox.
1775
2199
  activeSandboxId: z.string().uuid().nullable(),
1776
2200
  activeEpoch: z.number().int().nonnegative(),
1777
- environmentId: z.string().uuid().nullable(),
2201
+ variableSetId: z.string().uuid().nullable().default(null),
2202
+ /** @deprecated use variableSetId */
2203
+ environmentId: z.string().uuid().nullable().default(null),
2204
+ // The rig this session rides (M3 runtime binding). Both are resolved and
2205
+ // FROZEN at session create: rigId names the rig, rigVersionId pins the exact
2206
+ // active version the session's box/env/setup/doctrine are built from for the
2207
+ // session's whole life (a later promote does NOT move an existing session).
2208
+ // Both null ⇒ a rig-less session (byte-for-byte today's behavior).
2209
+ rigId: z.string().uuid().nullable().default(null),
2210
+ rigVersionId: z.string().uuid().nullable().default(null),
1778
2211
  // Non-default first-party MCP token permissions (manager-style sessions);
1779
2212
  // null means the fixed worker default set.
1780
2213
  firstPartyMcpPermissions: z.array(Permission).nullable(),
@@ -1793,9 +2226,18 @@ var Session = z.object({
1793
2226
  temporalWorkflowId: z.string().nullable(),
1794
2227
  activeTurnId: z.string().uuid().nullable(),
1795
2228
  // Actual input tokens of the last model call of the most recent turn; the
1796
- // pre-turn client-side context-compaction trigger reads it as its budget
2229
+ // pre-turn portable context-compaction trigger reads it as its budget
1797
2230
  // signal. Null until a turn with usage has completed.
1798
2231
  lastInputTokens: z.number().int().nonnegative().nullable(),
2232
+ queueVersion: z.number().int().nonnegative(),
2233
+ queueHeadPosition: z.number().int(),
2234
+ queueTailPosition: z.number().int(),
2235
+ controlState: SessionControlState,
2236
+ controlGeneration: z.number().int().nonnegative(),
2237
+ controlReason: z.string().nullable(),
2238
+ controlChangedBy: z.string().nullable(),
2239
+ controlChangedAt: z.string().nullable(),
2240
+ workspaceRunExceptionGeneration: z.number().int().nonnegative().nullable(),
1799
2241
  lastSequence: z.number().int().nonnegative(),
1800
2242
  // Multi-account Codex (P1). codexPinnedCredentialId: the account this session is
1801
2243
  // manually PINNED to (null ⇒ follow the workspace active pointer).
@@ -1803,32 +2245,76 @@ var Session = z.object({
1803
2245
  // "Running on:" indicator's source). Both are credential-row ids, null until set.
1804
2246
  codexPinnedCredentialId: z.string().uuid().nullable(),
1805
2247
  codexLastCredentialId: z.string().uuid().nullable(),
2248
+ /** Personal (authenticated subject) workspace pin state, never workspace-global. */
2249
+ pinned: z.boolean().default(false),
2250
+ /** Stable pin ordering key; null when this subject has not pinned the session. */
2251
+ pinnedAt: z.string().nullable().default(null),
2252
+ /** Optimistic pin-state revision; zero represents an absent pin relation. */
2253
+ pinVersion: z.number().int().nonnegative().default(0),
2254
+ /**
2255
+ * Server-authoritative hierarchy summary populated on session-list reads.
2256
+ * Detail reads may omit it. The rail uses this instead of guessing a tree
2257
+ * from whichever global recency page happened to be loaded.
2258
+ */
2259
+ treeStats: z.object({
2260
+ directChildren: z.number().int().nonnegative(),
2261
+ totalDescendants: z.number().int().nonnegative(),
2262
+ runningDescendants: z.number().int().nonnegative(),
2263
+ queuedDescendants: z.number().int().nonnegative(),
2264
+ attentionDescendants: z.number().int().nonnegative(),
2265
+ pausedDescendants: z.number().int().nonnegative(),
2266
+ failedDescendants: z.number().int().nonnegative()
2267
+ }).optional(),
1806
2268
  createdAt: z.string(),
1807
2269
  updatedAt: z.string()
1808
2270
  });
2271
+ var SessionListResponse = z.object({
2272
+ pinned: z.array(Session),
2273
+ sessions: z.array(Session),
2274
+ nextCursor: z.string().nullable()
2275
+ });
2276
+ var LineageNode = z.lazy(
2277
+ () => z.object({
2278
+ session: Session,
2279
+ children: z.array(LineageNode)
2280
+ })
2281
+ );
2282
+ var SessionLineageResponse = z.object({
2283
+ ancestors: z.array(Session),
2284
+ children: z.array(LineageNode),
2285
+ truncated: z.boolean().default(false)
2286
+ });
1809
2287
  var SessionEventType = z.enum([
1810
2288
  "session.created",
1811
2289
  "session.status.changed",
1812
2290
  "session.requiresAction",
2291
+ "session.context.compaction.requested",
1813
2292
  "session.context.compacted",
2293
+ "session.context.compaction.skipped",
1814
2294
  "session.context.cleared",
1815
2295
  "user.message",
1816
- "user.interrupt",
2296
+ "user.pause",
1817
2297
  "user.approvalDecision",
1818
2298
  "turn.queued",
1819
- "turn.updated",
1820
2299
  "turn.started",
1821
2300
  "turn.completed",
1822
2301
  "turn.failed",
1823
2302
  "turn.cancelled",
1824
- "turn.preempted",
2303
+ "turn.superseded",
2304
+ "turn.recovery.requested",
2305
+ "turn.capacity_waiting",
1825
2306
  "agent.message.delta",
1826
2307
  "agent.message.completed",
1827
2308
  "agent.reasoning.delta",
1828
2309
  "agent.toolCall.created",
1829
2310
  "agent.toolCall.output",
2311
+ "agent.model.usage",
1830
2312
  "tool.auth_needed",
1831
2313
  "agent.updated",
2314
+ "rig.setup.started",
2315
+ "rig.setup.completed",
2316
+ "rig.setup.skipped",
2317
+ "rig.setup.failed",
1832
2318
  "sandbox.operation.started",
1833
2319
  "sandbox.operation.completed",
1834
2320
  "sandbox.operation.failed",
@@ -1839,7 +2325,22 @@ var SessionEventType = z.enum([
1839
2325
  "goal.completed",
1840
2326
  "goal.paused",
1841
2327
  "goal.resumed",
2328
+ "goal.cleared",
1842
2329
  "goal.continuation",
2330
+ "system.update.pending",
2331
+ "system.update.delivered",
2332
+ "session.control.paused",
2333
+ "session.control.resumed",
2334
+ "session.control.steer_requested",
2335
+ "workspace.inference.paused",
2336
+ "workspace.inference.resumed",
2337
+ "session.queue.prompt.cancelled",
2338
+ "session.queue.history",
2339
+ // A terminal/stale activity callback is retained as an audit wrapper rather
2340
+ // than being dropped or emitted as though it belonged to the current turn.
2341
+ "turn.event.rejected_late",
2342
+ "memory.saved",
2343
+ "memory.corrected",
1843
2344
  // Channel-B desktop pixel-plane signals (07-channel-b §1.2). The pixel socket
1844
2345
  // carries opaque RFB and cannot carry a control message the client can act on,
1845
2346
  // so these ride the durable, sequenced, gap-filled Channel-A SSE spine.
@@ -1883,7 +2384,84 @@ var SessionEventType = z.enum([
1883
2384
  // Multi-account Codex (P1): the account a session's turn runs on changed
1884
2385
  // (manual switch in P1; failover/rotation in P3 reuse the same event). Drives
1885
2386
  // the in-session "Running on:" indicator's live flip.
1886
- "codex.account.switched"
2387
+ "codex.account.switched",
2388
+ // OPE-21 per-turn selection audit. Payload is metadata only: credential row
2389
+ // id, bounded strategy/reason, and pool counts — never token material.
2390
+ "codex.credential.selected",
2391
+ // OPE-21 durable zero-capacity wait lifecycle. Runtime/system events only;
2392
+ // no synthetic user message is created when capacity returns.
2393
+ "codex.capacity.waiting",
2394
+ "codex.capacity.resumed",
2395
+ "codex.capacity.superseded",
2396
+ // Sandbox durability observability (sandbox-file-persistence). The 2026-07
2397
+ // incidents (mid-session box death with /workspace loss; a fatal manifest-env
2398
+ // delta on a live box) were near-unattributable because box lifecycle left no
2399
+ // durable trace — only worker logs, which rotate within hours. These events
2400
+ // make every box transition and env recomputation drift readable from the DB
2401
+ // alone. Payloads carry ids/flags/key NAMES only — never env values (secrets).
2402
+ "sandbox.box.created",
2403
+ // box cold-created/cold-restored ({hydrated: "archive"|"none"})
2404
+ "sandbox.box.lost",
2405
+ // resume-by-id found the box gone (provider NotFound)
2406
+ "sandbox.box.terminated",
2407
+ // reaper drain terminated the box ({actor, persisted})
2408
+ "sandbox.box.snapshot",
2409
+ // mid-session /workspace snapshot persisted ({trigger})
2410
+ "sandbox.env.drift",
2411
+ // recomputed manifest env != live box env (key names only)
2412
+ // Active-sandbox pointer reconcile (issue #341 invariant B). Turn start found the
2413
+ // persisted (active_sandbox_id, active_epoch) pointing at a target the turn cannot
2414
+ // establish — a deleted/absent sandbox, a Modal sibling with no establisher, or a
2415
+ // selfhosted sandbox with no enrollment — and reset it to the session HOME under
2416
+ // the epoch fence instead of routing every op into the dead target. A VISIBLE,
2417
+ // never-silent downgrade: payload carries the typed reason + from/to epoch, never a
2418
+ // target id or command content. Announce-only; hits the timeline projection default
2419
+ // (no rendered item) like the other sandbox.* diagnostics.
2420
+ "session.route.reconciled",
2421
+ // Workbench v2 turn-end workspace capture (dossier §10.1). ANNOUNCE-ONLY: a new
2422
+ // capture revision was persisted at turn end; the client refetches the latest
2423
+ // capture. It carries metadata only (revision/turnId/capturedAt/leaseEpoch/stats),
2424
+ // never file content. Hits the timeline projection default case (ignored) — it
2425
+ // must NEVER gain a rendered timeline item without regenerating the golden
2426
+ // snapshots (dossier §7.3 golden-grammar gate).
2427
+ "workspace.revision.captured",
2428
+ // Repository discovery could not prove a complete capture. The worker
2429
+ // persisted a failed/degraded revision marker and clients must fall back to
2430
+ // the live box rather than trust a zero-repository snapshot.
2431
+ "workspace.revision.degraded",
2432
+ // Connected Machine (selfhosted) op-outcome observability (failure-visibility
2433
+ // doctrine, out-of-band plane). SESSION-scoped facts only: these fire for the
2434
+ // session whose turn ran the op (the two-planes rule — machine-plane facts like
2435
+ // pressure live in the M10 metrics DB, never as session events). Payloads carry
2436
+ // the op kind + a typed fault class + attempt count — NEVER command content.
2437
+ //
2438
+ // `machine.op.failed` fires ONLY for INFRASTRUCTURE fault classes (offline,
2439
+ // draining-exhausted, payload-too-large, reconnecting-timeout, OS/stream/protocol)
2440
+ // — a semantic miss the model asked about (a missing path, a consent gate, a
2441
+ // nonzero exit) is an OUTCOME, not an infra fault, and never fires this.
2442
+ // `machine.op.recovered` is the healed-fault leading indicator (a blip/backpressure
2443
+ // the transport absorbed): announce-only, quiet. Both hit the timeline projection's
2444
+ // quiet status-tick tier (the severity split's "degraded"); adding a rendered item
2445
+ // requires regenerating the golden snapshots (the golden-grammar gate).
2446
+ "machine.op.failed",
2447
+ "machine.op.recovered",
2448
+ // Connected Machine (selfhosted) LINK-plane observability (failure-visibility
2449
+ // doctrine). SESSION-scoped, ANNOUNCE-ONLY facts fanned out to the sessions that
2450
+ // had an active op running on the machine when its control link changed — never
2451
+ // to idle/historical sessions. Payloads carry ids / a typed reason / key-names
2452
+ // only, NEVER command content.
2453
+ //
2454
+ // `machine.link.lost` — the machine announced a clean GoingOffline (its control
2455
+ // link is going away) while a session had a running turn on it. `machine.link.
2456
+ // restored` — a reconnect Hello re-established the link that was previously lost.
2457
+ // `machine.runner.restarted` — the additional signal that the going-offline was
2458
+ // a self-update restart specifically (link.lost also fires for it; this
2459
+ // distinguishes a restart from a plain stop / host shutdown). All three hit the
2460
+ // timeline projection's quiet default tier (no rendered item); adding a rendered
2461
+ // item requires regenerating the golden snapshots (the golden-grammar gate).
2462
+ "machine.link.lost",
2463
+ "machine.link.restored",
2464
+ "machine.runner.restarted"
1887
2465
  ]);
1888
2466
  var ToolAuthNeededPayload = z.object({
1889
2467
  serverId: z.string().min(1),
@@ -1977,15 +2555,17 @@ var SandboxCommandOutputDeltaPayload = z.object({
1977
2555
  });
1978
2556
  var FsChangeKind = z.enum(["created", "modified", "deleted", "renamed"]);
1979
2557
  var FsChangedPayload = z.object({
1980
- changes: z.array(z.object({
1981
- path: z.string(),
1982
- // workspace-relative POSIX path
1983
- kind: FsChangeKind,
1984
- isDir: z.boolean().default(false),
1985
- sizeBytes: z.number().int().nonnegative().nullable().default(null),
1986
- oldPath: z.string().optional()
1987
- // for "renamed"
1988
- })).min(1),
2558
+ changes: z.array(
2559
+ z.object({
2560
+ path: z.string(),
2561
+ // workspace-relative POSIX path
2562
+ kind: FsChangeKind,
2563
+ isDir: z.boolean().default(false),
2564
+ sizeBytes: z.number().int().nonnegative().nullable().default(null),
2565
+ oldPath: z.string().optional()
2566
+ // for "renamed"
2567
+ })
2568
+ ).min(1),
1989
2569
  source: z.enum(["write", "watch", "agent"]).default("write"),
1990
2570
  // Monotonic FS revision (per-lease, paired with leaseEpoch for staleness).
1991
2571
  revision: z.number().int().nonnegative(),
@@ -2028,16 +2608,18 @@ var TerminalPtyExitedPayload = z.object({
2028
2608
  reason: z.enum(["exit", "killed", "owner_gone", "timeout"])
2029
2609
  });
2030
2610
  var FsNodeType = z.enum(["file", "dir", "symlink", "other"]);
2031
- var FsTreeNode = z.lazy(() => z.object({
2032
- name: z.string(),
2033
- path: z.string(),
2034
- type: FsNodeType,
2035
- sizeBytes: z.number().int().nonnegative().nullable(),
2036
- mtimeMs: z.number().int().nonnegative().nullable(),
2037
- mode: z.number().int().nullable(),
2038
- children: z.array(FsTreeNode).optional(),
2039
- truncated: z.boolean().default(false)
2040
- }));
2611
+ var FsTreeNode = z.lazy(
2612
+ () => z.object({
2613
+ name: z.string(),
2614
+ path: z.string(),
2615
+ type: FsNodeType,
2616
+ sizeBytes: z.number().int().nonnegative().nullable(),
2617
+ mtimeMs: z.number().int().nonnegative().nullable(),
2618
+ mode: z.number().int().nullable(),
2619
+ children: z.array(FsTreeNode).optional(),
2620
+ truncated: z.boolean().default(false)
2621
+ })
2622
+ );
2041
2623
  var FsListRequest = z.object({
2042
2624
  path: z.string().default(""),
2043
2625
  // "" = workspace root
@@ -2196,6 +2778,125 @@ var GitDiffResponse = z.object({
2196
2778
  files: z.array(GitFileDiff),
2197
2779
  revision: z.number().int().nonnegative()
2198
2780
  });
2781
+ var WorkspaceCaptureFile = z.object({
2782
+ path: z.string(),
2783
+ status: GitFileStatusCode,
2784
+ // sha256 of the captured after-image bytes; null when deleted / tooLarge.
2785
+ hash: z.string().nullable(),
2786
+ // git blob sha of the HEAD version — the wake-on-edit flush guard (dossier
2787
+ // §10.1). null when the path is new/untracked (no HEAD blob).
2788
+ baseHash: z.string().nullable(),
2789
+ // Content-addressed storage key of the after-image; null when deleted /
2790
+ // tooLarge / binary (no inline content captured).
2791
+ contentRef: z.string().nullable(),
2792
+ sizeBytes: z.number().int().nonnegative(),
2793
+ isBinary: z.boolean().default(false),
2794
+ // >5MB per-file content guard tripped: content NOT captured, render "open live".
2795
+ tooLarge: z.boolean().default(false),
2796
+ deleted: z.boolean().default(false)
2797
+ });
2798
+ var WorkspaceCaptureRepo = z.object({
2799
+ root: z.string(),
2800
+ head: z.string().nullable(),
2801
+ detached: z.boolean().default(false),
2802
+ upstream: z.string().nullable(),
2803
+ ahead: z.number().int().nonnegative().default(0),
2804
+ behind: z.number().int().nonnegative().default(0),
2805
+ status: z.array(GitFileStatus),
2806
+ diff: z.array(GitFileDiff)
2807
+ });
2808
+ var WorkspaceCaptureDegradedReason = z.enum([
2809
+ "repository_discovery_command_failed",
2810
+ "repository_discovery_timed_out",
2811
+ "repository_discovery_result_limit_exceeded"
2812
+ ]);
2813
+ var WorkspaceCaptureStats = z.object({
2814
+ repoCount: z.number().int().nonnegative(),
2815
+ fileCount: z.number().int().nonnegative(),
2816
+ additions: z.number().int().nonnegative(),
2817
+ deletions: z.number().int().nonnegative(),
2818
+ totalBytes: z.number().int().nonnegative(),
2819
+ tooLargeCount: z.number().int().nonnegative(),
2820
+ binaryCount: z.number().int().nonnegative(),
2821
+ treeEntryCount: z.number().int().nonnegative(),
2822
+ treeTruncated: z.boolean().default(false),
2823
+ durationMs: z.number().int().nonnegative(),
2824
+ // sha256 over the change surface (per-file path/hash/status + per-repo diff
2825
+ // summary, tree/mtime excluded). The empty-turn gate skips a capture whose
2826
+ // fingerprint equals the previous revision's — "no new revision when nothing
2827
+ // changed" holds even when the tree stays dirty across read-only turns.
2828
+ fingerprint: z.string().optional()
2829
+ });
2830
+ var WorkspaceCaptureManifest = z.object({
2831
+ version: z.literal(1),
2832
+ revision: z.number().int().nonnegative(),
2833
+ capturedAt: z.string(),
2834
+ turnId: z.string().nullable(),
2835
+ leaseEpoch: z.number().int().nonnegative(),
2836
+ treeIndex: FsTreeNode,
2837
+ treeTruncated: z.boolean().default(false),
2838
+ repos: z.array(WorkspaceCaptureRepo),
2839
+ files: z.array(WorkspaceCaptureFile),
2840
+ stats: WorkspaceCaptureStats
2841
+ });
2842
+ var WorkspaceRevisionCapturedPayload = z.object({
2843
+ revision: z.number().int().nonnegative(),
2844
+ turnId: z.string().nullable(),
2845
+ capturedAt: z.string(),
2846
+ leaseEpoch: z.number().int().nonnegative(),
2847
+ stats: WorkspaceCaptureStats
2848
+ });
2849
+ var WorkspaceRevisionDegradedPayload = z.object({
2850
+ revision: z.number().int().nonnegative(),
2851
+ turnId: z.string().nullable(),
2852
+ capturedAt: z.string(),
2853
+ leaseEpoch: z.number().int().nonnegative(),
2854
+ reason: WorkspaceCaptureDegradedReason
2855
+ });
2856
+ var WorkspaceCaptureSignedUrl = z.object({
2857
+ url: z.string().url(),
2858
+ expiresAt: z.string()
2859
+ });
2860
+ var GetWorkspaceCaptureResponse = z.discriminatedUnion("available", [
2861
+ z.object({
2862
+ available: z.literal(false),
2863
+ // Optional for additive compatibility with older servers. New servers set
2864
+ // these fields when the newest durable revision is an explicit degraded
2865
+ // marker rather than "no capture exists yet".
2866
+ degradedReason: WorkspaceCaptureDegradedReason.nullable().optional(),
2867
+ revision: z.number().int().nonnegative().nullable().optional(),
2868
+ capturedAt: z.string().nullable().optional(),
2869
+ turnId: z.string().nullable().optional(),
2870
+ leaseEpoch: z.number().int().nonnegative().nullable().optional()
2871
+ }),
2872
+ z.object({
2873
+ available: z.literal(true),
2874
+ revision: z.number().int().nonnegative(),
2875
+ capturedAt: z.string(),
2876
+ turnId: z.string().nullable(),
2877
+ leaseEpoch: z.number().int().nonnegative(),
2878
+ sizeBytes: z.number().int().nonnegative(),
2879
+ stats: WorkspaceCaptureStats,
2880
+ manifest: WorkspaceCaptureManifest.nullable().default(null),
2881
+ manifestUrl: WorkspaceCaptureSignedUrl.nullable().default(null)
2882
+ })
2883
+ ]);
2884
+ var GetWorkspaceCaptureFileResponse = z.object({
2885
+ path: z.string(),
2886
+ revision: z.number().int().nonnegative(),
2887
+ status: GitFileStatusCode,
2888
+ hash: z.string().nullable(),
2889
+ baseHash: z.string().nullable(),
2890
+ sizeBytes: z.number().int().nonnegative(),
2891
+ isBinary: z.boolean(),
2892
+ tooLarge: z.boolean(),
2893
+ encoding: FsEncoding.nullable().default(null),
2894
+ // set iff content is inline
2895
+ content: z.string().nullable().default(null),
2896
+ // inline ≤256KB (per encoding)
2897
+ contentUrl: WorkspaceCaptureSignedUrl.nullable().default(null)
2898
+ // signed >256KB
2899
+ });
2199
2900
  var GitLogRequest = z.object({
2200
2901
  path: z.string().default(""),
2201
2902
  ref: z.string().default("HEAD"),
@@ -2229,7 +2930,12 @@ var GitShowResponse = z.object({
2229
2930
  // null when fetching a raw blob
2230
2931
  files: z.array(GitFileDiff),
2231
2932
  // commit diff vs first parent
2232
- blob: z.object({ content: z.string(), encoding: FsEncoding, sizeBytes: z.number().int(), truncated: z.boolean() }).nullable(),
2933
+ blob: z.object({
2934
+ content: z.string(),
2935
+ encoding: FsEncoding,
2936
+ sizeBytes: z.number().int(),
2937
+ truncated: z.boolean()
2938
+ }).nullable(),
2233
2939
  revision: z.number().int().nonnegative()
2234
2940
  });
2235
2941
  var TerminalExecRequest = z.object({
@@ -2267,7 +2973,11 @@ var PtyOpenResponse = z.object({
2267
2973
  // false on backends without writeStdin
2268
2974
  });
2269
2975
  var PtyWriteRequest = z.object({ ptyId: z.string().uuid(), data: z.string() });
2270
- var PtyResizeRequest = z.object({ ptyId: z.string().uuid(), cols: z.number().int().positive(), rows: z.number().int().positive() });
2976
+ var PtyResizeRequest = z.object({
2977
+ ptyId: z.string().uuid(),
2978
+ cols: z.number().int().positive(),
2979
+ rows: z.number().int().positive()
2980
+ });
2271
2981
  var PtyCloseRequest = z.object({ ptyId: z.string().uuid() });
2272
2982
  var SessionStructuredCapabilities = z.object({
2273
2983
  FileSystem: z.object({ available: z.boolean(), readOnly: z.boolean(), root: z.string() }),
@@ -2290,9 +3000,31 @@ var SessionEvent = z.object({
2290
3000
  payload: z.unknown().default({}),
2291
3001
  occurredAt: z.string(),
2292
3002
  clientEventId: z.string().min(1).nullable().optional(),
2293
- turnId: z.string().uuid().nullable().optional()
2294
- });
2295
- var CreateSessionRequest = z.object({
3003
+ turnId: z.string().uuid().nullable().optional(),
3004
+ turnGeneration: z.number().int().nonnegative().nullable().optional(),
3005
+ turnAttemptId: z.string().uuid().nullable().optional(),
3006
+ turnAssociation: z.enum(["current", "late_rejected", "duplicate"]).nullable().optional(),
3007
+ duplicateOfEventId: z.string().uuid().nullable().optional(),
3008
+ duplicateReason: z.string().min(1).nullable().optional()
3009
+ });
3010
+ var SessionQueueMutationResponse = z.object({
3011
+ snapshot: SessionQueueSnapshot,
3012
+ events: z.array(SessionEvent),
3013
+ shouldWake: z.boolean()
3014
+ });
3015
+ var SessionControlResponse = z.object({
3016
+ operationId: z.string().uuid(),
3017
+ event: SessionEvent,
3018
+ controlState: SessionControlState,
3019
+ controlGeneration: z.number().int().nonnegative(),
3020
+ expectedActiveTurnId: z.string().uuid().nullable(),
3021
+ expectedExecutionGeneration: z.number().int().nonnegative().nullable(),
3022
+ expectedAttemptId: z.string().uuid().nullable(),
3023
+ deliveryEventId: z.string().uuid().nullable(),
3024
+ shouldSignalControl: z.boolean(),
3025
+ shouldWake: z.boolean()
3026
+ });
3027
+ var CreateSessionRequest = withVariableSetIdAlias({
2296
3028
  initialMessage: z.string().min(1),
2297
3029
  // Per-session agent persona/system instructions (org-visible metadata, NOT a
2298
3030
  // secret). Rides the SAME system-level instructions channel the per-workspace
@@ -2301,7 +3033,7 @@ var CreateSessionRequest = z.object({
2301
3033
  // leaking them into the user-visible timeline (it is NEVER emitted as an
2302
3034
  // event, unlike goal/initialMessage). Trimmed, non-empty. The 32768-char cap
2303
3035
  // matches the codebase's largest free-form string convention (workspace
2304
- // environment variable values). Absent ⇒ byte-identical to today.
3036
+ // variable set variable values). Absent ⇒ byte-identical to today.
2305
3037
  instructions: z.string().trim().min(1).max(32768).optional(),
2306
3038
  resources: z.array(ResourceRef).default([]),
2307
3039
  tools: z.array(ToolRef).default([]),
@@ -2320,9 +3052,15 @@ var CreateSessionRequest = z.object({
2320
3052
  // (the agent's resolve_cwd handles both). Only valid WITH targetSandboxId
2321
3053
  // (workingDir alone is a 422); omitted ⇒ the machine's default workspace_root.
2322
3054
  workingDir: z.string().min(1).optional(),
2323
- // Workspace environment attachment is fixed at session creation; follow-up
3055
+ // Variable set attachment is fixed at session creation; follow-up
2324
3056
  // user.message events cannot switch or add one.
3057
+ variableSetId: z.string().uuid().optional(),
2325
3058
  environmentId: z.string().uuid().optional(),
3059
+ // The rig to bind this session to (M3). Its ACTIVE version is resolved and
3060
+ // FROZEN onto the session at create. Omitted ⇒ the workspace's default rig
3061
+ // (workspaces.default_rig_id) when set, else a rig-less session (today's
3062
+ // behavior). An id that does not name a rig in the workspace is a 422.
3063
+ rigId: z.string().uuid().optional(),
2326
3064
  goal: GoalSpec.optional(),
2327
3065
  clientEventId: z.string().min(1).optional(),
2328
3066
  // Workspace-scoped CREATE idempotency key: collapses concurrent/retried
@@ -2334,7 +3072,7 @@ var CreateSessionRequest = z.object({
2334
3072
  idempotencyKey: z.string().min(1).max(200).optional(),
2335
3073
  // Permissions the session's first-party MCP token should carry instead of
2336
3074
  // the fixed worker default — how an operator hands a manager-style session
2337
- // the orchestration/environment/github tools. Capped at creation: every
3075
+ // the orchestration/variableSet/github tools. Capped at creation: every
2338
3076
  // requested permission must be held by the creating grant (no escalation).
2339
3077
  firstPartyMcpPermissions: z.array(Permission).optional(),
2340
3078
  // Third-party MCP servers attached only to this session. Credential headers are
@@ -2352,16 +3090,12 @@ var CreateSessionRequest = z.object({
2352
3090
  // A shared spawn inherits the box's (backend, os) — it is literally the same
2353
3091
  // box; the child cannot pick its own backend. Cross-workspace sharing is
2354
3092
  // forbidden by construction (the parent/group reads are RLS-workspace-scoped).
2355
- // ENV-AWARE: the box's environment is fixed at creation, so a share requires
2356
- // the SAME environmentId as the creator's box. On a mismatch the inherited
3093
+ // ENV-AWARE: the box's variable set is fixed at creation, so a share requires
3094
+ // the SAME variableSetId as the creator's box. On a mismatch the inherited
2357
3095
  // default silently falls back to an own box; an explicit "shared"/{groupId}
2358
3096
  // request 422s at create (instead of the first turn dying on the SDK's
2359
3097
  // manifest-env guard).
2360
- sandbox: z.union([
2361
- z.literal("shared"),
2362
- z.literal("new"),
2363
- z.object({ groupId: z.string().uuid() })
2364
- ]).optional()
3098
+ sandbox: z.union([z.literal("shared"), z.literal("new"), z.object({ groupId: z.string().uuid() })]).optional()
2365
3099
  });
2366
3100
  var ClientSessionEvent = z.discriminatedUnion("type", [
2367
3101
  z.object({
@@ -2378,11 +3112,6 @@ var ClientSessionEvent = z.discriminatedUnion("type", [
2378
3112
  mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional()
2379
3113
  })
2380
3114
  }),
2381
- z.object({
2382
- type: z.literal("user.interrupt"),
2383
- clientEventId: z.string().min(1).optional(),
2384
- payload: z.object({ reason: z.string().optional() }).default({})
2385
- }),
2386
3115
  z.object({
2387
3116
  type: z.literal("user.approvalDecision"),
2388
3117
  clientEventId: z.string().min(1).optional(),
@@ -2393,6 +3122,21 @@ var ClientSessionEvent = z.discriminatedUnion("type", [
2393
3122
  })
2394
3123
  })
2395
3124
  ]);
3125
+ var SteerSessionMessageRequest = z.object({
3126
+ text: z.string().min(1),
3127
+ resources: z.array(ResourceRef).default([]),
3128
+ tools: z.array(ToolRef).default([]),
3129
+ model: z.string().min(1).optional(),
3130
+ reasoningEffort: ReasoningEffort.optional(),
3131
+ clientEventId: z.string().min(1).optional(),
3132
+ expectedControlGeneration: z.number().int().nonnegative().optional(),
3133
+ expectedWorkspaceInferenceGeneration: z.number().int().nonnegative().optional(),
3134
+ mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional()
3135
+ });
3136
+ var SteerSessionMessageResponse = z.object({
3137
+ accepted: SessionEvent,
3138
+ turn: SessionTurn
3139
+ });
2396
3140
  var SessionBusMessage = z.object({
2397
3141
  workspaceId: z.string().uuid(),
2398
3142
  sessionId: z.string().uuid(),
@@ -2611,7 +3355,13 @@ var DeviceEnrollmentApproveResponse = z.object({
2611
3355
  var DeviceEnrollmentPollRequest = z.object({
2612
3356
  deviceCode: z.string().min(1).max(256)
2613
3357
  });
2614
- var DeviceEnrollmentState = z.enum(["pending", "authorized", "denied", "expired", "disabled"]);
3358
+ var DeviceEnrollmentState = z.enum([
3359
+ "pending",
3360
+ "authorized",
3361
+ "denied",
3362
+ "expired",
3363
+ "disabled"
3364
+ ]);
2615
3365
  var EnrollmentCredentialsResponse = z.object({
2616
3366
  agentId: z.string().uuid(),
2617
3367
  workspaceId: z.string().uuid(),
@@ -2774,7 +3524,18 @@ var SwapActiveSandboxResponse = z.object({
2774
3524
  swapped: z.boolean(),
2775
3525
  activeSandboxId: z.string().nullable(),
2776
3526
  activeEpoch: z.number().int(),
2777
- reason: z.string().optional()
3527
+ reason: z.string().optional(),
3528
+ // Typed rejection discriminant (issue #341). Present only when swapped is false,
3529
+ // so a client distinguishes a deleted/absent target from an unaddressable
3530
+ // enrollment from a backend the turn cannot establish from a lost epoch race —
3531
+ // without parsing the human reason string.
3532
+ code: z.enum([
3533
+ "stale_pointer",
3534
+ "offline_enrollment",
3535
+ "unsupported_backend_context",
3536
+ "transient_establishment",
3537
+ "concurrent_swap"
3538
+ ]).optional()
2778
3539
  });
2779
3540
  var MachineMetricsSeriesResponse = z.object({
2780
3541
  samples: z.array(MetricSample)
@@ -2801,10 +3562,12 @@ var ClientConfig = z.object({
2801
3562
  models: z.array(ClientModel).default([]),
2802
3563
  defaultReasoningEffort: ReasoningEffort,
2803
3564
  allowedReasoningEfforts: z.array(ReasoningEffort).min(1),
2804
- mcpServers: z.array(z.object({
2805
- id: z.string(),
2806
- name: z.string()
2807
- })).default([]),
3565
+ mcpServers: z.array(
3566
+ z.object({
3567
+ id: z.string(),
3568
+ name: z.string()
3569
+ })
3570
+ ).default([]),
2808
3571
  fileUploads: z.object({
2809
3572
  enabled: z.boolean(),
2810
3573
  maxSizeBytes: z.number().int().positive()
@@ -2850,6 +3613,18 @@ function constantTimeEqual(actual, expected) {
2850
3613
  }
2851
3614
  return diff === 0;
2852
3615
  }
3616
+ function evaluateWorkspaceModelPolicy(policy, candidate) {
3617
+ if (!policy) {
3618
+ return { allowed: true };
3619
+ }
3620
+ if (policy.allowedProviders !== null && !policy.allowedProviders.includes(candidate.providerId)) {
3621
+ return { allowed: false, reason: "provider" };
3622
+ }
3623
+ if (policy.allowedModels !== null && !policy.allowedModels.includes(candidate.modelId)) {
3624
+ return { allowed: false, reason: "model" };
3625
+ }
3626
+ return { allowed: true };
3627
+ }
2853
3628
  export {
2854
3629
  AccessContext,
2855
3630
  AccessGrant,
@@ -2866,6 +3641,7 @@ export {
2866
3641
  CAPABILITY_DESCRIPTORS,
2867
3642
  CLEARED_RUN_STATE_BLOB,
2868
3643
  CLEARED_RUN_STATE_MARKER,
3644
+ CancelSessionQueueItemRequest,
2869
3645
  CapabilityCatalogAuthKind,
2870
3646
  CapabilityCatalogItem,
2871
3647
  CapabilityCatalogResponse,
@@ -2906,10 +3682,12 @@ export {
2906
3682
  CreateFileUploadRequest,
2907
3683
  CreateFileUploadResponse,
2908
3684
  CreateKnowledgeMemoryRequest,
3685
+ CreateRigRequest,
2909
3686
  CreateScheduledTaskRequest,
2910
3687
  CreateSessionRequest,
2911
3688
  CreateSocialConnectionRequest,
2912
3689
  CreateSocialPostRequest,
3690
+ CreateVariableSetRequest,
2913
3691
  CreateWorkspaceEnvironmentRequest,
2914
3692
  CreateWorkspaceRequest,
2915
3693
  DESKTOP_STREAM_PORT,
@@ -2971,8 +3749,12 @@ export {
2971
3749
  FsTreeNode,
2972
3750
  FsWriteRequest,
2973
3751
  FsWriteResponse,
3752
+ GetWorkspaceCaptureFileResponse,
3753
+ GetWorkspaceCaptureResponse,
2974
3754
  GitChangedPayload,
2975
3755
  GitCommit,
3756
+ GitCredentialProvider,
3757
+ GitCredentialRepositoryRef,
2976
3758
  GitDiffHunk,
2977
3759
  GitDiffLine,
2978
3760
  GitDiffLineType,
@@ -2999,6 +3781,7 @@ export {
2999
3781
  KnowledgeSourceRef,
3000
3782
  LimitAction,
3001
3783
  LimitDecision,
3784
+ LineageNode,
3002
3785
  ListConnectionsResponse,
3003
3786
  ListEnrollmentsResponse,
3004
3787
  ListWorkspaceMembersResponse,
@@ -3019,6 +3802,7 @@ export {
3019
3802
  PackInstallationStatus,
3020
3803
  Permission,
3021
3804
  ProductAccessMode,
3805
+ ProposeRigChangeRequest,
3022
3806
  PtyCloseRequest,
3023
3807
  PtyOpenRequest,
3024
3808
  PtyOpenResponse,
@@ -3034,11 +3818,21 @@ export {
3034
3818
  RecordingStartedPayload,
3035
3819
  RegisterCapabilityPackRequest,
3036
3820
  RelayTokenPayload,
3037
- ReorderSessionTurnsRequest,
3038
3821
  RepositoryResourceRef,
3039
3822
  ResourceRef,
3040
3823
  ResourceRefConflictError,
3041
3824
  RevokeEnrollmentResponse,
3825
+ Rig,
3826
+ RigChange,
3827
+ RigChangeKind,
3828
+ RigChangeStatus,
3829
+ RigChangeVerification,
3830
+ RigCheck,
3831
+ RigCheckResult,
3832
+ RigDefinitionEditPayload,
3833
+ RigSetupAppendPayload,
3834
+ RigVerificationHealth,
3835
+ RigVersion,
3042
3836
  SandboxBackend,
3043
3837
  SandboxCapabilityName,
3044
3838
  SandboxCommandOutputDeltaPayload,
@@ -3055,26 +3849,40 @@ export {
3055
3849
  Session,
3056
3850
  SessionBusMessage,
3057
3851
  SessionCapabilities,
3852
+ SessionControlRequest,
3853
+ SessionControlResponse,
3854
+ SessionControlState,
3058
3855
  SessionEvent,
3059
3856
  SessionEventType,
3060
3857
  SessionGoal,
3061
3858
  SessionGoalCreatedBy,
3062
3859
  SessionGoalPausedReason,
3063
3860
  SessionGoalStatus,
3861
+ SessionLineageResponse,
3862
+ SessionListResponse,
3064
3863
  SessionMcpCredentialUpdateInput,
3065
3864
  SessionMcpServerInput,
3066
3865
  SessionMcpServerMetadata,
3866
+ SessionQueueMutationResponse,
3867
+ SessionQueueSnapshot,
3067
3868
  SessionStatus,
3068
3869
  SessionStructuredCapabilities,
3870
+ SessionSystemUpdate,
3871
+ SessionSystemUpdateKind,
3872
+ SessionSystemUpdateState,
3069
3873
  SessionTurn,
3070
3874
  SessionTurnSource,
3071
3875
  SessionTurnStatus,
3876
+ SetVariableSetVariableRequest,
3877
+ SetWorkspaceDefaultRigRequest,
3072
3878
  SetWorkspaceEnvironmentVariableRequest,
3073
3879
  SocialConnection,
3074
3880
  SocialConnectionStatus,
3075
3881
  SocialPost,
3076
3882
  SocialProvider,
3077
3883
  StaticUsageLimits,
3884
+ SteerSessionMessageRequest,
3885
+ SteerSessionMessageResponse,
3078
3886
  StreamClosedPayload,
3079
3887
  StreamOpenedPayload,
3080
3888
  StreamRevokedPayload,
@@ -3082,6 +3890,7 @@ export {
3082
3890
  StreamUrlRotatedPayload,
3083
3891
  SwapActiveSandboxRequest,
3084
3892
  SwapActiveSandboxResponse,
3893
+ SystemUpdateClassification,
3085
3894
  TERMINAL_STREAM_PORT,
3086
3895
  TerminalExecRequest,
3087
3896
  TerminalExecResponse,
@@ -3093,30 +3902,54 @@ export {
3093
3902
  TriggerScheduledTaskRequest,
3094
3903
  UpdateConnectionRequest,
3095
3904
  UpdateKnowledgeMemoryRequest,
3905
+ UpdateRigRequest,
3096
3906
  UpdateScheduledTaskRequest,
3097
3907
  UpdateSessionGoalRequest,
3908
+ UpdateSessionPinRequest,
3098
3909
  UpdateSessionRequest,
3099
- UpdateSessionTurnRequest,
3910
+ UpdateVariableSetRequest,
3100
3911
  UpdateWorkspaceEnvironmentRequest,
3101
3912
  UpdateWorkspaceMemberRequest,
3913
+ UpdateWorkspaceModelPolicyRequest,
3102
3914
  UpdateWorkspaceRequest,
3915
+ UpdateWorkspaceSettingsRequest,
3103
3916
  UsageEvent,
3104
3917
  UsageEventType,
3105
3918
  UsageLimitsMode,
3919
+ VariableSet,
3920
+ VariableSetVariableMetadata,
3921
+ VariableSetVariableName,
3106
3922
  ViewerHeartbeatRequest,
3107
3923
  ViewerHeartbeatResponse,
3108
3924
  ViewerHolder,
3109
3925
  Workspace,
3926
+ WorkspaceCaptureDegradedReason,
3927
+ WorkspaceCaptureFile,
3928
+ WorkspaceCaptureManifest,
3929
+ WorkspaceCaptureRepo,
3930
+ WorkspaceCaptureSignedUrl,
3931
+ WorkspaceCaptureStats,
3110
3932
  WorkspaceEnvironment,
3111
3933
  WorkspaceEnvironmentVariableMetadata,
3112
- WorkspaceEnvironmentVariableName,
3934
+ WorkspaceInferenceControlRequest,
3935
+ WorkspaceInferenceControlResponse,
3936
+ WorkspaceInferenceState,
3113
3937
  WorkspaceMember,
3938
+ WorkspaceMemorySearchMode,
3939
+ WorkspaceMemorySearchRequest,
3940
+ WorkspaceMemorySearchResponse,
3941
+ WorkspaceMemorySearchResult,
3114
3942
  WorkspaceRegisteredPack,
3943
+ WorkspaceRevisionCapturedPayload,
3944
+ WorkspaceRevisionDegradedPayload,
3945
+ WorkspaceSettingsSchema,
3946
+ evaluateWorkspaceModelPolicy,
3115
3947
  isClearedRunStateBlob,
3116
3948
  mergeResourceRefs,
3117
3949
  mergeToolRefs,
3118
3950
  prefixedMcpToolName,
3119
3951
  reasoningEffortForMetadata,
3952
+ resolveWorkspaceMemoryEnabled,
3120
3953
  resourceIdentityKey,
3121
3954
  signDelegatedAccessToken,
3122
3955
  signEnrollToken,