@opengeni/contracts 0.23.0 → 0.27.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/src/index.ts CHANGED
@@ -6,6 +6,33 @@ import {
6
6
  type SessionEventBoundarySurface,
7
7
  } from "./event-preview";
8
8
 
9
+ export * from "./slack-bot-scopes";
10
+
11
+ export {
12
+ CreateWorkspaceArtifactRequest,
13
+ PublishWorkspaceArtifactVersionRequest,
14
+ RollbackWorkspaceArtifactRequest,
15
+ WorkspaceArtifact,
16
+ WorkspaceArtifactContentResponse,
17
+ WorkspaceArtifactDetailResponse,
18
+ WorkspaceArtifactEvent,
19
+ WorkspaceArtifactEventType,
20
+ WorkspaceArtifactHtml,
21
+ WorkspaceArtifactListQuery,
22
+ WorkspaceArtifactListResponse,
23
+ WorkspaceArtifactMutationResponse,
24
+ WorkspaceArtifactSlug,
25
+ WorkspaceArtifactStatus,
26
+ WorkspaceArtifactVersion,
27
+ WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS,
28
+ WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS,
29
+ WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES,
30
+ WORKSPACE_ARTIFACT_LIST_DEFAULT,
31
+ WORKSPACE_ARTIFACT_LIST_MAX,
32
+ WORKSPACE_ARTIFACT_TITLE_MAX_CHARS,
33
+ normalizeWorkspaceArtifactSlug,
34
+ } from "./artifacts";
35
+
9
36
  export {
10
37
  SESSION_EVENT_PAYLOAD_MAX_BYTES,
11
38
  approximateSessionEventTokens,
@@ -46,6 +73,25 @@ export {
46
73
  type RetainedOutputResolvedRange,
47
74
  } from "./retained-output";
48
75
 
76
+ export {
77
+ NATIVE_SNAPSHOT_PREFIXES,
78
+ WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
79
+ backendForNativeSnapshotProvider,
80
+ decodeNativeSnapshotRef,
81
+ parseWorkspaceArchiveDescriptor,
82
+ type NativeSnapshotDescriptor,
83
+ type NativeSnapshotProvider,
84
+ type NativeSnapshotRef,
85
+ type TarWorkspaceArchiveDescriptor,
86
+ type WorkspaceArchiveDescriptor,
87
+ type WorkspaceTreeFingerprint,
88
+ } from "./sandbox-snapshots";
89
+
90
+ export {
91
+ canonicalModalCheckpointProviderBinding,
92
+ type ModalCheckpointProviderBinding,
93
+ } from "./checkpoint-provider-bindings";
94
+
49
95
  export const SessionStatus = z.enum([
50
96
  "queued",
51
97
  "running",
@@ -458,6 +504,10 @@ export const CAPABILITY_DESCRIPTORS: Record<SandboxBackend, CapabilityDescriptor
458
504
  };
459
505
 
460
506
  export const ReasoningEffort = z.enum(["none", "minimal", "low", "medium", "high", "xhigh"]);
507
+
508
+ /** Provider service-tier / latency mode selected for a turn or session default. */
509
+ export const LatencyMode = z.enum(["standard", "priority", "fast"]);
510
+ export type LatencyMode = z.infer<typeof LatencyMode>;
461
511
  export type ReasoningEffort = z.infer<typeof ReasoningEffort>;
462
512
 
463
513
  export const ErrorCode = z.enum([
@@ -467,9 +517,11 @@ export const ErrorCode = z.enum([
467
517
  "validation_failed",
468
518
  "conflict",
469
519
  "idempotency_conflict",
520
+ "payment_required",
470
521
  "limit_exceeded",
471
522
  "nested_agent_depth_exceeded",
472
523
  "nested_agent_depth_override_forbidden",
524
+ "codex_compaction_v2_provider_locked",
473
525
  "provider_verification_failed",
474
526
  "upstream_unavailable",
475
527
  "internal_error",
@@ -599,6 +651,10 @@ export const Permission = z.enum([
599
651
  // super-wildcard over both.
600
652
  "rigs:use",
601
653
  "rigs:manage",
654
+ // Workspace-published HTML artifacts. Read permits listing/source retrieval;
655
+ // publish permits create, version publication, and rollback.
656
+ "artifacts:read",
657
+ "artifacts:publish",
602
658
  ]);
603
659
  export type Permission = z.infer<typeof Permission>;
604
660
 
@@ -624,6 +680,8 @@ export const DEFAULT_FIRST_PARTY_MCP_PERMISSIONS = [
624
680
  "variable-sets:manage",
625
681
  "rigs:use",
626
682
  "github:use",
683
+ "artifacts:read",
684
+ "artifacts:publish",
627
685
  ] as const satisfies readonly Permission[];
628
686
 
629
687
  /**
@@ -643,6 +701,8 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
643
701
  "memory_search",
644
702
  "memory_save",
645
703
  "memory_correct",
704
+ "preference_registry_summary",
705
+ "preference_registry_get",
646
706
  "sandboxes_list",
647
707
  "sandbox_attach",
648
708
  "sandbox_swap",
@@ -683,8 +743,18 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
683
743
  "scheduled_task_runs_list",
684
744
  "slack_bot_list_channels",
685
745
  "slack_bot_channel_history",
746
+ "slack_bot_thread_replies",
686
747
  "slack_bot_list_users",
748
+ "slack_bot_list_files",
749
+ "slack_bot_file_info",
750
+ "slack_bot_file_content",
687
751
  "slack_bot_post_message",
752
+ "slack_bot_delete_message",
753
+ "artifacts_list",
754
+ "artifacts_get_source",
755
+ "artifacts_create",
756
+ "artifacts_publish",
757
+ "artifacts_rollback",
688
758
  ] as const;
689
759
  export const FirstPartyMcpToolName = z.enum(FIRST_PARTY_MCP_TOOL_NAMES);
690
760
  export type FirstPartyMcpToolName = z.infer<typeof FirstPartyMcpToolName>;
@@ -800,10 +870,17 @@ export const TranscriptionErrorCode = z.enum([
800
870
  "policy_blocked",
801
871
  "timeout",
802
872
  "cancelled",
873
+ "unavailable",
874
+ "too_large",
875
+ "invalid_audio",
803
876
  "unknown",
804
877
  ]);
805
878
  export type TranscriptionErrorCode = z.infer<typeof TranscriptionErrorCode>;
806
879
 
880
+ /** Stable user-safe error codes for the native voice-input transcription path. */
881
+ export const VoiceInputErrorCode = TranscriptionErrorCode;
882
+ export type VoiceInputErrorCode = TranscriptionErrorCode;
883
+
807
884
  export const TranscriptionTimeSpan = z
808
885
  .object({
809
886
  startMilliseconds: z.number().finite().nonnegative(),
@@ -925,6 +1002,9 @@ export const TranscriptionEvent = z.discriminatedUnion("type", [
925
1002
  export type TranscriptionEvent = z.infer<typeof TranscriptionEvent>;
926
1003
 
927
1004
  /**
1005
+ * @deprecated Host-adapter transcription policy. Kept for one release so existing
1006
+ * workspace settings remain readable. New writes use `WorkspaceVoiceInputSettings`.
1007
+ *
928
1008
  * Workspace-only policy for the distinct speech-to-text capability. It never
929
1009
  * authorizes a turn model/provider and contains connection references rather
930
1010
  * than secrets. `acceptanceId` changes whenever an admin accepts a new target
@@ -1041,16 +1121,77 @@ export const WorkspaceTranscriptionPolicy = z
1041
1121
  });
1042
1122
  export type WorkspaceTranscriptionPolicy = z.infer<typeof WorkspaceTranscriptionPolicy>;
1043
1123
 
1124
+ /**
1125
+ * Workspace toggle for native browser voice input. Provider/model/credentials
1126
+ * stay server-private; this only records whether the workspace allows the
1127
+ * deployment-configured transcription path.
1128
+ */
1129
+ export const WorkspaceVoiceInputSettings = z
1130
+ .object({
1131
+ enabled: z.boolean(),
1132
+ })
1133
+ .strict();
1134
+ export type WorkspaceVoiceInputSettings = z.infer<typeof WorkspaceVoiceInputSettings>;
1135
+
1136
+ /** Client-safe voice-input capability projection. Never includes provider secrets. */
1137
+ export const ClientVoiceInputConfig = z
1138
+ .object({
1139
+ available: z.boolean(),
1140
+ maxDurationSeconds: z.number().int().positive().max(600),
1141
+ maxSizeBytes: z.number().int().positive(),
1142
+ acceptedMimeTypes: z.array(z.string().trim().min(1).max(128)).min(1).max(32),
1143
+ })
1144
+ .strict();
1145
+ export type ClientVoiceInputConfig = z.infer<typeof ClientVoiceInputConfig>;
1146
+
1147
+ /** Response from POST /v1/workspaces/:workspaceId/transcriptions. */
1148
+ export const TranscribeAudioResponse = z
1149
+ .object({
1150
+ text: z.string().max(1_000_000),
1151
+ languages: z.array(z.string().trim().min(1).max(64)).max(16).default([]),
1152
+ })
1153
+ .strict();
1154
+ export type TranscribeAudioResponse = z.infer<typeof TranscribeAudioResponse>;
1155
+
1156
+ /** Default ceilings for native voice input (hard-stop recording + upload). */
1157
+ export const VOICE_INPUT_MAX_DURATION_SECONDS = 60 as const;
1158
+ export const VOICE_INPUT_MAX_SIZE_BYTES = 25 * 1024 * 1024;
1159
+ export const VOICE_INPUT_ACCEPTED_MIME_TYPES = [
1160
+ "audio/webm",
1161
+ "audio/webm;codecs=opus",
1162
+ "audio/mp4",
1163
+ "audio/ogg",
1164
+ "audio/ogg;codecs=opus",
1165
+ "audio/mpeg",
1166
+ "audio/wav",
1167
+ "audio/x-wav",
1168
+ "audio/mp3",
1169
+ "audio/m4a",
1170
+ ] as const;
1171
+
1172
+ /** Per-session / workspace Codex compaction strategy. */
1173
+ export const CodexCompactionMode = z.enum(["remote_v2", "portable"]);
1174
+ export type CodexCompactionMode = z.infer<typeof CodexCompactionMode>;
1175
+
1044
1176
  // Validates the KNOWN keys of workspaces.settings; passthrough keeps unknown
1045
- // (future) keys rather than stripping them. memoryEnabled and transcription are
1046
- // both default-off capabilities.
1177
+ // (future) keys rather than stripping them. memoryEnabled defaults off;
1178
+ // voiceInput defaults to enabled when the deployment has a provider.
1047
1179
  export const WorkspaceSettingsSchema = z
1048
1180
  .object({
1049
1181
  memoryEnabled: z.boolean().optional(),
1182
+ /** Preferred workspace voice-input toggle. */
1183
+ voiceInput: WorkspaceVoiceInputSettings.optional(),
1184
+ /**
1185
+ * @deprecated Legacy host-adapter policy. Read for compatibility; new writes
1186
+ * should use `voiceInput`.
1187
+ */
1050
1188
  transcription: WorkspaceTranscriptionPolicy.optional(),
1051
1189
  // null clears the workspace override and falls back to the persisted
1052
1190
  // deployment policy. The database boundary validates the same range.
1053
1191
  maxNestedAgentDepth: NestedAgentDepthValue.nullable().optional(),
1192
+ // Default compaction strategy for NEW Codex sessions created in this
1193
+ // workspace. Absent ⇒ remote_v2. Non-Codex sessions always freeze portable.
1194
+ codexCompactionDefault: CodexCompactionMode.optional(),
1054
1195
  })
1055
1196
  .passthrough();
1056
1197
  export type WorkspaceSettings = z.infer<typeof WorkspaceSettingsSchema>;
@@ -1061,14 +1202,40 @@ export function resolveWorkspaceMemoryEnabled(settings: unknown): boolean {
1061
1202
  return parsed.success ? parsed.data.memoryEnabled === true : false;
1062
1203
  }
1063
1204
 
1205
+ /** Default Codex compaction mode for new Codex sessions (remote_v2 when unset). */
1206
+ export function resolveWorkspaceCodexCompactionDefault(settings: unknown): CodexCompactionMode {
1207
+ const parsed = WorkspaceSettingsSchema.safeParse(settings ?? {});
1208
+ if (!parsed.success) return "remote_v2";
1209
+ return parsed.data.codexCompactionDefault ?? "remote_v2";
1210
+ }
1211
+
1212
+ /**
1213
+ * Resolve whether voice input is enabled for a workspace.
1214
+ *
1215
+ * - Prefer `settings.voiceInput.enabled` when present.
1216
+ * - Map legacy `settings.transcription.enabled` when voiceInput is absent.
1217
+ * - Return `null` when neither is set so callers can default to deployment
1218
+ * availability (enabled when a provider is configured).
1219
+ */
1220
+ export function resolveWorkspaceVoiceInputEnabled(settings: unknown): boolean | null {
1221
+ const parsed = WorkspaceSettingsSchema.safeParse(settings ?? {});
1222
+ if (!parsed.success) return null;
1223
+ if (parsed.data.voiceInput) return parsed.data.voiceInput.enabled;
1224
+ if (parsed.data.transcription) return parsed.data.transcription.enabled;
1225
+ return null;
1226
+ }
1227
+
1064
1228
  // PATCH body for workspace settings: a partial top-level patch that merges into
1065
- // the stored bag. Nested transcription policy updates are therefore full
1066
- // replacements; passthrough carries forward-compatible unknown keys.
1229
+ // the stored bag. Nested voiceInput/transcription updates are full replacements;
1230
+ // passthrough carries forward-compatible unknown keys.
1067
1231
  export const UpdateWorkspaceSettingsRequest = z
1068
1232
  .object({
1069
1233
  memoryEnabled: z.boolean().optional(),
1234
+ voiceInput: WorkspaceVoiceInputSettings.optional(),
1235
+ /** @deprecated Prefer `voiceInput`. Kept for one compatibility release. */
1070
1236
  transcription: WorkspaceTranscriptionPolicy.optional(),
1071
1237
  maxNestedAgentDepth: NestedAgentDepthValue.nullable().optional(),
1238
+ codexCompactionDefault: CodexCompactionMode.optional(),
1072
1239
  })
1073
1240
  .passthrough();
1074
1241
  export type UpdateWorkspaceSettingsRequest = z.infer<typeof UpdateWorkspaceSettingsRequest>;
@@ -1160,6 +1327,16 @@ export const ServiceTurnInitiatorContext = TurnInitiatorContext.superRefine((val
1160
1327
  });
1161
1328
  export type ServiceTurnInitiatorContext = z.infer<typeof ServiceTurnInitiatorContext>;
1162
1329
 
1330
+ export const DelegatedAccessPrincipalKind = z.enum(["human_session", "agent_attempt", "service"]);
1331
+ export type DelegatedAccessPrincipalKind = z.infer<typeof DelegatedAccessPrincipalKind>;
1332
+
1333
+ export const AccessPrincipalKind = z.enum([
1334
+ ...DelegatedAccessPrincipalKind.options,
1335
+ "api_key",
1336
+ "configured_key",
1337
+ ]);
1338
+ export type AccessPrincipalKind = z.infer<typeof AccessPrincipalKind>;
1339
+
1163
1340
  export const AccountGrant = z.object({
1164
1341
  accountId: z.string().uuid(),
1165
1342
  subjectId: z.string().min(1),
@@ -1176,6 +1353,9 @@ export const AccessGrant = z.object({
1176
1353
  subjectId: z.string().min(1),
1177
1354
  subjectLabel: z.string().optional(),
1178
1355
  permissions: z.array(Permission),
1356
+ // Trusted principal provenance. Delegated grants copy this from the signed
1357
+ // token claim; managed/local grants derive it from their authenticated path.
1358
+ principalKind: AccessPrincipalKind.optional(),
1179
1359
  metadata: z.record(z.string(), z.unknown()).optional(),
1180
1360
  // Optional trusted causal principal for a command submitted by an embedding
1181
1361
  // host. Authorization still uses subjectId + permissions above.
@@ -1202,6 +1382,10 @@ export const DelegatedAccessTokenPayload = z
1202
1382
  subjectId: z.string().min(1),
1203
1383
  subjectLabel: z.string().optional(),
1204
1384
  permissions: z.array(Permission).min(1),
1385
+ // Required and covered by the token HMAC. Authorization must positively
1386
+ // select a principal kind instead of inferring "human" from absent machine
1387
+ // markers.
1388
+ principalKind: DelegatedAccessPrincipalKind,
1205
1389
  // Trusted embedding hosts can sign a causal service principal separately
1206
1390
  // from the grant subject that authorizes the request. The claim is consumed
1207
1391
  // only when a command creates a new session/turn.
@@ -1226,6 +1410,53 @@ export const DelegatedAccessTokenPayload = z
1226
1410
  exp: z.number().int().positive(),
1227
1411
  })
1228
1412
  .superRefine((payload, ctx) => {
1413
+ const exactAttemptClaims = [
1414
+ payload.sessionId,
1415
+ payload.turnId,
1416
+ payload.attemptId,
1417
+ payload.executionGeneration,
1418
+ ];
1419
+ const exactAttemptClaimCount = exactAttemptClaims.filter((value) => value !== undefined).length;
1420
+ if (
1421
+ payload.principalKind === "human_session" &&
1422
+ (exactAttemptClaimCount !== 0 || payload.serviceInitiator !== undefined)
1423
+ ) {
1424
+ ctx.addIssue({
1425
+ code: z.ZodIssueCode.custom,
1426
+ path: ["principalKind"],
1427
+ message: "human_session principal cannot carry machine authority claims",
1428
+ });
1429
+ }
1430
+ if (
1431
+ payload.principalKind === "agent_attempt" &&
1432
+ (exactAttemptClaimCount !== exactAttemptClaims.length ||
1433
+ payload.serviceInitiator !== undefined)
1434
+ ) {
1435
+ ctx.addIssue({
1436
+ code: z.ZodIssueCode.custom,
1437
+ path: ["principalKind"],
1438
+ message: "agent_attempt principal requires one exact signed attempt authority",
1439
+ });
1440
+ }
1441
+ if (
1442
+ payload.principalKind === "service" &&
1443
+ (payload.turnId !== undefined ||
1444
+ payload.attemptId !== undefined ||
1445
+ payload.executionGeneration !== undefined)
1446
+ ) {
1447
+ ctx.addIssue({
1448
+ code: z.ZodIssueCode.custom,
1449
+ path: ["principalKind"],
1450
+ message: "service principal cannot carry exact agent-attempt authority",
1451
+ });
1452
+ }
1453
+ if (payload.serviceInitiator && payload.principalKind !== "service") {
1454
+ ctx.addIssue({
1455
+ code: z.ZodIssueCode.custom,
1456
+ path: ["principalKind"],
1457
+ message: "serviceInitiator requires a service principal",
1458
+ });
1459
+ }
1229
1460
  if (payload.serviceInitiatorContext && !payload.serviceInitiator) {
1230
1461
  ctx.addIssue({
1231
1462
  code: z.ZodIssueCode.custom,
@@ -1737,6 +1968,169 @@ export const UsageEvent = z.object({
1737
1968
  });
1738
1969
  export type UsageEvent = z.infer<typeof UsageEvent>;
1739
1970
 
1971
+ /** UTC Insights windows. "this month" aligns with billing's UTC month. */
1972
+ export const InsightsRange = z.enum(["today", "week", "month", "ytd"]);
1973
+ export type InsightsRange = z.infer<typeof InsightsRange>;
1974
+
1975
+ export const InsightsBillingPath = z.enum(["opengeni_credits", "external"]);
1976
+ export type InsightsBillingPath = z.infer<typeof InsightsBillingPath>;
1977
+
1978
+ export const InsightsModelUsageRow = z.object({
1979
+ id: z.string().min(1),
1980
+ model: z.string().min(1),
1981
+ provider: z.string().min(1),
1982
+ billing: InsightsBillingPath,
1983
+ calls: z.number().int().nonnegative(),
1984
+ inputTokens: z.number().nonnegative(),
1985
+ outputTokens: z.number().nonnegative(),
1986
+ cachedTokens: z.number().nonnegative(),
1987
+ cacheWriteTokens: z.number().nonnegative(),
1988
+ reasoningTokens: z.number().nonnegative(),
1989
+ /** Priced OpenGeni credit $ for this model×provider (from model_call_facts). */
1990
+ creditUsd: z.number().nonnegative(),
1991
+ });
1992
+ export type InsightsModelUsageRow = z.infer<typeof InsightsModelUsageRow>;
1993
+
1994
+ export const InsightsSeriesPoint = z.object({
1995
+ label: z.string().min(1),
1996
+ /** Day-bucketed sum of usage_events.model.cost (workspace-wide) or filtered facts when provider/model set. */
1997
+ modelCostUsd: z.number().nonnegative(),
1998
+ warmSeconds: z.number().nonnegative(),
1999
+ inputTokens: z.number().nonnegative(),
2000
+ cachedTokens: z.number().nonnegative(),
2001
+ cacheHitPct: z.number().int().min(0).max(100),
2002
+ calls: z.number().int().nonnegative(),
2003
+ });
2004
+ export type InsightsSeriesPoint = z.infer<typeof InsightsSeriesPoint>;
2005
+
2006
+ export const InsightsDepthBucket = z.object({
2007
+ depth: z.number().int().nonnegative(),
2008
+ sessions: z.number().int().nonnegative(),
2009
+ });
2010
+ export type InsightsDepthBucket = z.infer<typeof InsightsDepthBucket>;
2011
+
2012
+ export const InsightsModelFacet = z.object({
2013
+ provider: z.string().min(1),
2014
+ model: z.string().min(1),
2015
+ });
2016
+ export type InsightsModelFacet = z.infer<typeof InsightsModelFacet>;
2017
+
2018
+ export const InsightsSpendDriver = z.object({
2019
+ id: z.string().min(1),
2020
+ groupBy: z.enum(["root_session", "schedule"]),
2021
+ label: z.string().min(1),
2022
+ creditUsd: z.number().nonnegative(),
2023
+ tokens: z.number().nonnegative(),
2024
+ cacheHitPct: z.number().int().min(0).max(100),
2025
+ pctOfCreditUsd: z.number().int().min(0).max(100),
2026
+ deltaUsdVsPrior: z.number(),
2027
+ });
2028
+ export type InsightsSpendDriver = z.infer<typeof InsightsSpendDriver>;
2029
+
2030
+ export const InsightsWarmGroupRow = z.object({
2031
+ id: z.string().min(1),
2032
+ groupId: z.string().uuid(),
2033
+ label: z.string().min(1),
2034
+ /** Live lease backend when known; null when only historical warm ticks exist. */
2035
+ backend: z.string().nullable(),
2036
+ warmSeconds: z.number().nonnegative(),
2037
+ /** Currently attached sessions — not cost share. */
2038
+ sessionsAttached: z.number().int().nonnegative(),
2039
+ });
2040
+ export type InsightsWarmGroupRow = z.infer<typeof InsightsWarmGroupRow>;
2041
+
2042
+ export const InsightsLiveWarmLease = z.object({
2043
+ id: z.string().uuid(),
2044
+ groupId: z.string().uuid(),
2045
+ backend: z.string().min(1),
2046
+ turnHolders: z.number().int().nonnegative(),
2047
+ viewerHolders: z.number().int().nonnegative(),
2048
+ warmForLabel: z.string().min(1),
2049
+ warmSeconds: z.number().nonnegative(),
2050
+ });
2051
+ export type InsightsLiveWarmLease = z.infer<typeof InsightsLiveWarmLease>;
2052
+
2053
+ export const InsightsFloorSession = z.object({
2054
+ id: z.string().uuid(),
2055
+ title: z.string(),
2056
+ state: z.enum(["running", "paused", "failed", "idle", "compacting", "waiting"]),
2057
+ depth: z.number().int().nonnegative(),
2058
+ model: z.string().nullable(),
2059
+ provider: z.string().nullable(),
2060
+ ageLabel: z.string(),
2061
+ cacheHitPct: z.number().int().min(0).max(100).nullable(),
2062
+ route: z.string().nullable(),
2063
+ });
2064
+ export type InsightsFloorSession = z.infer<typeof InsightsFloorSession>;
2065
+
2066
+ export const InsightsScheduleRow = z.object({
2067
+ id: z.string().uuid(),
2068
+ name: z.string(),
2069
+ fires: z.number().int().nonnegative(),
2070
+ /** Null when no facts carry scheduled_task_id for this window. */
2071
+ creditUsd: z.number().nonnegative().nullable(),
2072
+ tokens: z.number().nonnegative().nullable(),
2073
+ cacheHitPct: z.number().int().min(0).max(100).nullable(),
2074
+ billing: InsightsBillingPath.nullable(),
2075
+ });
2076
+ export type InsightsScheduleRow = z.infer<typeof InsightsScheduleRow>;
2077
+
2078
+ export const WorkspaceInsightsSnapshot = z.object({
2079
+ range: InsightsRange,
2080
+ rangeLabel: z.string().min(1),
2081
+ priorLabel: z.string().min(1),
2082
+ seriesLabel: z.string().min(1),
2083
+ cacheSeriesLabel: z.string().min(1),
2084
+ /** All ranges/series are UTC. */
2085
+ timezone: z.literal("UTC"),
2086
+ models: z.array(InsightsModelUsageRow),
2087
+ /** Unfiltered provider×model pairs in the window — drives filter dropdowns. */
2088
+ facets: z.array(InsightsModelFacet),
2089
+ series: z.array(InsightsSeriesPoint),
2090
+ depth: z.array(InsightsDepthBucket),
2091
+ drivers: z.array(InsightsSpendDriver),
2092
+ schedules: z.array(InsightsScheduleRow),
2093
+ warmSeconds: z.number().nonnegative(),
2094
+ priorWarmSeconds: z.number().nonnegative(),
2095
+ warmGroups: z.array(InsightsWarmGroupRow),
2096
+ liveWarm: z.array(InsightsLiveWarmLease),
2097
+ floor: z.array(InsightsFloorSession),
2098
+ selfhostedEnabled: z.boolean(),
2099
+ machinesOnline: z.number().int().nonnegative(),
2100
+ /** Workspace-wide OpenGeni credit $ from usage_events.model.cost (unfiltered). */
2101
+ workspaceCreditUsd: z.number().nonnegative(),
2102
+ priorWorkspaceCreditUsd: z.number().nonnegative(),
2103
+ /** Model-filterable credit $ from facts (equals workspace when unfiltered, ignoring late-reject drift). */
2104
+ creditUsd: z.number().nonnegative(),
2105
+ priorCreditUsd: z.number().nonnegative(),
2106
+ priorInputTokens: z.number().nonnegative(),
2107
+ priorCacheHitPct: z.number().int().min(0).max(100),
2108
+ priorCalls: z.number().int().nonnegative(),
2109
+ /** Lifetime workspace topology (not scoped to the selected Insights range). */
2110
+ goalsActive: z.number().int().nonnegative(),
2111
+ goalsCompleted: z.number().int().nonnegative(),
2112
+ sessionsTouched: z.number().int().nonnegative(),
2113
+ rootSessions: z.number().int().nonnegative(),
2114
+ deepestDepth: z.number().int().nonnegative(),
2115
+ deepestSessionTitle: z.string(),
2116
+ avgDepth: z.number().nonnegative(),
2117
+ warmIdleNow: z.number().int().nonnegative(),
2118
+ /** Billable credits-path tokens this UTC month (usage_events.model.tokens). */
2119
+ billableTokensUsed: z.number().nonnegative(),
2120
+ billableTokenCap: z.number().int().positive().nullable(),
2121
+ /** Agent runs this UTC month (usage_events.agent_run.created). */
2122
+ agentRunsUsed: z.number().nonnegative(),
2123
+ agentRunCap: z.number().int().positive().nullable(),
2124
+ /** True when provider/model filters exclude workspace-wide warm/caps meaning. */
2125
+ modelFilterActive: z.boolean(),
2126
+ });
2127
+ export type WorkspaceInsightsSnapshot = z.infer<typeof WorkspaceInsightsSnapshot>;
2128
+
2129
+ export const WorkspaceInsightsResponse = z.object({
2130
+ snapshot: WorkspaceInsightsSnapshot,
2131
+ });
2132
+ export type WorkspaceInsightsResponse = z.infer<typeof WorkspaceInsightsResponse>;
2133
+
1740
2134
  export const LimitAction = z.enum([
1741
2135
  "agent_run:create",
1742
2136
  "tokens:consume",
@@ -2896,11 +3290,14 @@ export const ToolRef = z.object({
2896
3290
  kind: z.literal("mcp"),
2897
3291
  id: z.string().min(1),
2898
3292
  // Non-fatal-on-connect marker for MCP server refs that can degrade
2899
- // gracefully. Absent/false is STRICT: the id must be configured and an
2900
- // unavailable server fails the turn. `optional:true` is preserved for known
2901
- // servers and makes runtime connect/list failures skip that server; if the
2902
- // deployment does not configure the id, validation drops the ref. The server
2903
- // also sets this for auto-attached workspace-default capability MCPs.
3293
+ // gracefully. On new input, absent/false is STRICT: the id must be configured
3294
+ // and an unavailable registered server fails the turn. Persisted refs are
3295
+ // intersected with the current registry at each turn boundary, so a server
3296
+ // disconnected after admission is retained in policy/audit truth but skipped
3297
+ // until it is registered again. `optional:true` additionally makes runtime
3298
+ // connect/list failures skip a known server; if the deployment does not
3299
+ // configure the id, validation drops the ref. Auto-attached workspace-default
3300
+ // capability MCPs also use this marker.
2904
3301
  optional: z.boolean().optional(),
2905
3302
  });
2906
3303
  export type ToolRef = z.infer<typeof ToolRef>;
@@ -3161,6 +3558,14 @@ export function reasoningEffortForMetadata(
3161
3558
  : fallback;
3162
3559
  }
3163
3560
 
3561
+ export function latencyModeForMetadata(
3562
+ metadata: Record<string, unknown>,
3563
+ fallback: LatencyMode = "standard",
3564
+ ): LatencyMode {
3565
+ const value = metadata.latencyMode;
3566
+ return value === "standard" || value === "priority" || value === "fast" ? value : fallback;
3567
+ }
3568
+
3164
3569
  export function stableJson(value: unknown): string {
3165
3570
  return JSON.stringify(sortJson(value));
3166
3571
  }
@@ -3595,6 +4000,7 @@ export const SessionTurn = z.object({
3595
4000
  toolsProvided: z.boolean().optional(),
3596
4001
  model: z.string().min(1),
3597
4002
  reasoningEffort: ReasoningEffort,
4003
+ latencyMode: LatencyMode.default("standard"),
3598
4004
  sandboxBackend: SandboxBackend,
3599
4005
  // Per-turn OS override. NULL = inherit the session's sandboxOs.
3600
4006
  sandboxOs: SandboxOs.nullable(),
@@ -3683,6 +4089,7 @@ export const ComposerDraft = z.object({
3683
4089
  resources: z.array(ResourceRef),
3684
4090
  model: z.string().min(1),
3685
4091
  reasoningEffort: ReasoningEffort,
4092
+ latencyMode: LatencyMode.default("standard"),
3686
4093
  sourceTurnId: z.string().uuid().nullable(),
3687
4094
  sourceTurnVersion: z.number().int().positive().nullable(),
3688
4095
  updatedAt: z.string().nullable(),
@@ -3723,6 +4130,7 @@ export const SaveComposerDraftRequest = ComposerDraft.pick({
3723
4130
  resources: true,
3724
4131
  model: true,
3725
4132
  reasoningEffort: true,
4133
+ latencyMode: true,
3726
4134
  }).extend({ expectedRevision: z.number().int().nonnegative() });
3727
4135
  export type SaveComposerDraftRequest = z.infer<typeof SaveComposerDraftRequest>;
3728
4136
 
@@ -3753,6 +4161,7 @@ export const NewSessionDraft = z.object({
3753
4161
  toolsProvided: z.boolean().default(false),
3754
4162
  model: z.string().min(1),
3755
4163
  reasoningEffort: ReasoningEffort,
4164
+ latencyMode: LatencyMode.default("standard"),
3756
4165
  options: NewSessionDraftOptions,
3757
4166
  updatedAt: z.string().nullable(),
3758
4167
  });
@@ -3765,6 +4174,7 @@ export const SaveNewSessionDraftRequest = NewSessionDraft.pick({
3765
4174
  toolsProvided: true,
3766
4175
  model: true,
3767
4176
  reasoningEffort: true,
4177
+ latencyMode: true,
3768
4178
  options: true,
3769
4179
  }).extend({ expectedRevision: z.number().int().nonnegative() });
3770
4180
  export type SaveNewSessionDraftRequest = z.infer<typeof SaveNewSessionDraftRequest>;
@@ -4853,20 +5263,11 @@ export type ConnectionKind = z.infer<typeof ConnectionKind>;
4853
5263
  export const ConnectionStatus = z.enum(["active", "needs_reauth", "revoked", "error"]);
4854
5264
  export type ConnectionStatus = z.infer<typeof ConnectionStatus>;
4855
5265
 
5266
+ export const OPENGENI_PERSONAL_SLACK_MCP_URL = "https://mcp.slack.com/mcp" as const;
5267
+
4856
5268
  export const OPENGENI_SLACK_BOT_CREDENTIAL_ROLE = "opengeni_slack_bot" as const;
4857
5269
  export const OPENGENI_SLACK_BOT_CREDENTIAL_LABEL = "OpenGeni Slack bot" as const;
4858
5270
  export const OPENGENI_SLACK_BOT_SESSION_METADATA_KEY = "opengeniSlackBotConnectionId" as const;
4859
- export const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [
4860
- "chat:write",
4861
- "im:write",
4862
- "channels:read",
4863
- "channels:history",
4864
- "groups:read",
4865
- "groups:history",
4866
- "users:read",
4867
- ] as const;
4868
- export const OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES = ["channels:join", "chat:write.public"] as const;
4869
-
4870
5271
  export const OpenGeniSlackBotConnectionMetadata = z
4871
5272
  .object({
4872
5273
  credentialRole: z.literal(OPENGENI_SLACK_BOT_CREDENTIAL_ROLE),
@@ -5285,6 +5686,10 @@ export const Session = z.object({
5285
5686
  // "Running on:" indicator's source). Both are credential-row ids, null until set.
5286
5687
  codexPinnedCredentialId: z.string().uuid().nullable(),
5287
5688
  codexLastCredentialId: z.string().uuid().nullable(),
5689
+ // Frozen at session create. remote_v2 ⇒ Codex remote compaction + Codex-only
5690
+ // model admission for the life of the session; portable ⇒ plaintext compaction
5691
+ // and free mid-session provider switching (today's behavior).
5692
+ codexCompactionMode: CodexCompactionMode,
5288
5693
  /** Personal (authenticated subject) workspace pin state, never workspace-global. */
5289
5694
  pinned: z.boolean().default(false),
5290
5695
  /** Stable pin ordering key; null when this subject has not pinned the session. */
@@ -5375,6 +5780,7 @@ export const SessionEventType = z.enum([
5375
5780
  "session.requiresAction",
5376
5781
  "session.humanInput.requested",
5377
5782
  "session.context.compaction.requested",
5783
+ "session.context.compaction.started",
5378
5784
  "session.context.compacted",
5379
5785
  "session.context.compaction.skipped",
5380
5786
  "session.context.cleared",
@@ -5668,6 +6074,7 @@ export const SESSION_EVENT_SEMANTIC_CLASS_TYPES = {
5668
6074
  ],
5669
6075
  checkpoint: [
5670
6076
  "session.context.compaction.requested",
6077
+ "session.context.compaction.started",
5671
6078
  "session.context.compacted",
5672
6079
  "session.context.compaction.skipped",
5673
6080
  "session.context.cleared",
@@ -7494,6 +7901,7 @@ export const CreateSessionRequest = withVariableSetIdAlias({
7494
7901
  metadata: z.record(z.string(), z.unknown()).default({}),
7495
7902
  model: z.string().min(1).optional(),
7496
7903
  reasoningEffort: ReasoningEffort.optional(),
7904
+ latencyMode: LatencyMode.optional(),
7497
7905
  sandboxBackend: SandboxBackend.optional(),
7498
7906
  // The enrolled machine (a sandbox id) to run this session on; seeds the
7499
7907
  // active-sandbox pointer at creation so the FIRST turn routes to the chosen
@@ -7763,6 +8171,7 @@ export const ClientSessionEvent = z.discriminatedUnion("type", [
7763
8171
  resources: z.array(ResourceRef).default([]),
7764
8172
  model: z.string().min(1).optional(),
7765
8173
  reasoningEffort: ReasoningEffort.optional(),
8174
+ latencyMode: LatencyMode.optional(),
7766
8175
  controlEtag: z.string().min(1).optional(),
7767
8176
  expectedDraftRevision: z.number().int().nonnegative().optional(),
7768
8177
  // Header-value rotation only. URL/name/tool settings are immutable after
@@ -7799,6 +8208,7 @@ export const SteerSessionMessageRequest = z
7799
8208
  resources: z.array(ResourceRef).default([]),
7800
8209
  model: z.string().min(1).optional(),
7801
8210
  reasoningEffort: ReasoningEffort.optional(),
8211
+ latencyMode: LatencyMode.optional(),
7802
8212
  clientEventId: SessionOperationKey.optional(),
7803
8213
  controlEtag: z.string().min(1).optional(),
7804
8214
  expectedDraftRevision: z.number().int().nonnegative().optional(),
@@ -8575,6 +8985,11 @@ export const TurnExecutionReasoningSourceV1 = /* @__PURE__ */ defineModelContrac
8575
8985
  );
8576
8986
  export type TurnExecutionReasoningSourceV1 = z.infer<typeof TurnExecutionReasoningSourceV1>;
8577
8987
 
8988
+ export const TurnExecutionLatencyModeSourceV1 = /* @__PURE__ */ defineModelContractSchema(() =>
8989
+ z.enum(["explicit", "session", "deployment", "continuation"]),
8990
+ );
8991
+ export type TurnExecutionLatencyModeSourceV1 = z.infer<typeof TurnExecutionLatencyModeSourceV1>;
8992
+
8578
8993
  /**
8579
8994
  * Secret-safe execution identity frozen onto one accepted logical turn.
8580
8995
  *
@@ -8582,6 +8997,9 @@ export type TurnExecutionReasoningSourceV1 = z.infer<typeof TurnExecutionReasoni
8582
8997
  * definition rather than a serialized provider client. It must never contain
8583
8998
  * a key/token, concrete connected credential id, account label, authorization
8584
8999
  * header, or credential-bearing URL/query value.
9000
+ *
9001
+ * `latencyMode` / `latencyModeSource` default to standard/deployment so legacy
9002
+ * snapshots without those keys remain readable as Standard.
8585
9003
  */
8586
9004
  export const TurnExecutionPolicyV1 = /* @__PURE__ */ defineModelContractSchema(() =>
8587
9005
  z
@@ -8592,6 +9010,8 @@ export const TurnExecutionPolicyV1 = /* @__PURE__ */ defineModelContractSchema((
8592
9010
  modelSource: TurnExecutionModelSourceV1,
8593
9011
  reasoningEffort: ReasoningEffort,
8594
9012
  reasoningSource: TurnExecutionReasoningSourceV1,
9013
+ latencyMode: LatencyMode.default("standard"),
9014
+ latencyModeSource: TurnExecutionLatencyModeSourceV1.default("deployment"),
8595
9015
  providerId: z.string().min(1),
8596
9016
  upstreamModelId: z.string().min(1),
8597
9017
  wireApi: z.enum(["responses", "chat"]),
@@ -8682,6 +9102,8 @@ export function turnExecutionPolicyAuditMetadata(
8682
9102
  modelSource: parsed.modelSource,
8683
9103
  effectiveReasoningEffort: parsed.reasoningEffort,
8684
9104
  reasoningSource: parsed.reasoningSource,
9105
+ effectiveLatencyMode: parsed.latencyMode,
9106
+ latencyModeSource: parsed.latencyModeSource,
8685
9107
  providerId: parsed.providerId,
8686
9108
  credentialSourceKind: parsed.credentialSource.kind,
8687
9109
  credentialSourceMechanism:
@@ -8862,7 +9284,7 @@ export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalog
8862
9284
  * that rollout boundary. Mutating clients send this value in
8863
9285
  * `x-opengeni-api-contract`; the API rejects any other value before routing.
8864
9286
  */
8865
- export const OPENGENI_API_CONTRACT_REVISION = "2026-07-turn-instructions-v1" as const;
9287
+ export const OPENGENI_API_CONTRACT_REVISION = "2026-07-workspace-artifacts-v1" as const;
8866
9288
  export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
8867
9289
  /** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
8868
9290
  export const OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id" as const;
@@ -8894,6 +9316,14 @@ export const ClientConfig = /* @__PURE__ */ defineModelContractSchema(() =>
8894
9316
  enabled: z.boolean(),
8895
9317
  maxSizeBytes: z.number().int().positive(),
8896
9318
  }),
9319
+ // Native voice-input capability. Provider/model/credentials stay server-private;
9320
+ // clients only learn whether a deployment can transcribe and the hard ceilings.
9321
+ voiceInput: ClientVoiceInputConfig.default({
9322
+ available: false,
9323
+ maxDurationSeconds: VOICE_INPUT_MAX_DURATION_SECONDS,
9324
+ maxSizeBytes: VOICE_INPUT_MAX_SIZE_BYTES,
9325
+ acceptedMimeTypes: [...VOICE_INPUT_ACCEPTED_MIME_TYPES],
9326
+ }),
8897
9327
  productAccessMode: ProductAccessMode,
8898
9328
  auth: ClientAuthConfig.default({ mode: "none" }),
8899
9329
  // Server-wide hint: does this deployment support Channel-A structured services
@@ -8989,3 +9419,5 @@ export function evaluateWorkspaceModelPolicy(
8989
9419
  export * from "./codex-fleet-policy";
8990
9420
  export * from "./secret-redaction";
8991
9421
  export * from "./workspace-instruction-policies";
9422
+ export * from "./workspace-state";
9423
+ export * from "./preference-registry";