@opengeni/contracts 0.19.0 → 0.20.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/contracts",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "Shared zod schemas and wire-contract types for the OpenGeni API.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/index.ts CHANGED
@@ -478,8 +478,10 @@ export type ErrorCode = z.infer<typeof ErrorCode>;
478
478
 
479
479
  export const ErrorEnvelope = z.object({
480
480
  error: z.object({
481
+ status: z.number().int().min(400).max(599),
481
482
  code: ErrorCode,
482
483
  message: z.string(),
484
+ retryable: z.boolean(),
483
485
  requestId: z.string().optional(),
484
486
  details: z.record(z.string(), z.unknown()).optional(),
485
487
  }),
@@ -2176,11 +2178,22 @@ export type ConnectionCredentialsPort = {
2176
2178
 
2177
2179
  export type GitHubInstallationSummary = {
2178
2180
  installationId: number;
2181
+ accountId: number;
2179
2182
  accountLogin: string | null;
2180
2183
  accountType: string | null;
2181
2184
  suspended: boolean;
2182
2185
  };
2183
2186
 
2187
+ export type GitHubInstallationAuthorityKind = "personal_owner" | "organization_owner";
2188
+
2189
+ export interface GitHubInstallationBindingProof {
2190
+ actorId: number;
2191
+ actorLogin: string;
2192
+ authorityKind: GitHubInstallationAuthorityKind;
2193
+ installation: GitHubInstallationSummary;
2194
+ repositories: GitHubRepository[];
2195
+ }
2196
+
2184
2197
  export type GitHubRepositoryPermissions = {
2185
2198
  admin: boolean;
2186
2199
  maintain: boolean;
@@ -2198,6 +2211,18 @@ export type GitHubUserInstallationAccess = GitHubInstallationSummary & {
2198
2211
  };
2199
2212
 
2200
2213
  export type GitHubAppApiPort = {
2214
+ /**
2215
+ * Exchange one fresh GitHub user-authorization code and prove current
2216
+ * installation authority. Implementations must accept only exact personal
2217
+ * ownership or active organization ownership; installation visibility,
2218
+ * repository permission bits, and App Manager metadata are not authority.
2219
+ * Organization ownership must be revalidated after repository discovery,
2220
+ * immediately before returning the proof used by the durable bind.
2221
+ */
2222
+ authorizeInstallationBinding?: (input: {
2223
+ code: string;
2224
+ installationId: number;
2225
+ }) => Promise<GitHubInstallationBindingProof>;
2201
2226
  authorizeUser?: (input: { code: string }) => Promise<GitHubUserInstallationAccess[]>;
2202
2227
  verifyInstallationAccessForUser?: (input: {
2203
2228
  code: string;
@@ -2491,6 +2516,37 @@ export type KnowledgeSourceKind = z.infer<typeof KnowledgeSourceKind>;
2491
2516
  export const DocumentSearchMode = z.enum(["hybrid", "vector", "keyword"]);
2492
2517
  export type DocumentSearchMode = z.infer<typeof DocumentSearchMode>;
2493
2518
 
2519
+ // 'workspace' documents are readable by anyone with workspace access;
2520
+ // 'private' documents are readable only by the grant subject that created them.
2521
+ export const DocumentVisibility = z.enum(["workspace", "private"]);
2522
+ export type DocumentVisibility = z.infer<typeof DocumentVisibility>;
2523
+
2524
+ // Knowledge-drop auto-curation lifecycle. 'none' = ordinary caller-described add
2525
+ // (never auto-curated). 'pending' = dropped, curation runs during indexing.
2526
+ // 'suggested' = curated but the base move was NOT applied (low confidence or
2527
+ // conflict) — the suggestion lives in Document.curation. 'auto_filed' = curated
2528
+ // and moved into the suggested base. 'failed' = curation errored (fail-soft;
2529
+ // the document still indexes and stays searchable).
2530
+ export const DocumentCurationStatus = z.enum([
2531
+ "none",
2532
+ "pending",
2533
+ "suggested",
2534
+ "auto_filed",
2535
+ "failed",
2536
+ ]);
2537
+ export type DocumentCurationStatus = z.infer<typeof DocumentCurationStatus>;
2538
+
2539
+ // Curator audit blob persisted on the document.
2540
+ export const DocumentCuration = z.object({
2541
+ suggestedBaseId: z.string().uuid().nullable(),
2542
+ suggestedBaseName: z.string().nullable(),
2543
+ confidence: z.number().min(0).max(1),
2544
+ reason: z.string().nullable(),
2545
+ originalTitle: z.string().nullable(),
2546
+ model: z.string().nullable(),
2547
+ });
2548
+ export type DocumentCuration = z.infer<typeof DocumentCuration>;
2549
+
2494
2550
  export const DocumentBase = z.object({
2495
2551
  id: z.string().uuid(),
2496
2552
  workspaceId: z.string().uuid(),
@@ -2520,6 +2576,13 @@ export const Document = z.object({
2520
2576
  sourceUpdatedAt: z.string().nullable(),
2521
2577
  sourceVersion: z.string().nullable(),
2522
2578
  aclTags: z.array(z.string()),
2579
+ visibility: DocumentVisibility,
2580
+ createdBy: z.string().nullable(),
2581
+ agentAccess: z.boolean(),
2582
+ summary: z.string().nullable(),
2583
+ topics: z.array(z.string()),
2584
+ curationStatus: DocumentCurationStatus,
2585
+ curation: DocumentCuration.nullable(),
2523
2586
  createdAt: z.string(),
2524
2587
  updatedAt: z.string(),
2525
2588
  });
@@ -2569,9 +2632,37 @@ export const AddDocumentRequest = z.object({
2569
2632
  sourceUpdatedAt: z.string().datetime({ offset: true }).optional(),
2570
2633
  sourceVersion: z.string().min(1).optional(),
2571
2634
  aclTags: z.array(z.string().min(1)).optional(),
2635
+ visibility: DocumentVisibility.optional(),
2636
+ agentAccess: z.boolean().optional(),
2572
2637
  });
2573
2638
  export type AddDocumentRequest = z.infer<typeof AddDocumentRequest>;
2574
2639
 
2640
+ // A knowledge drop: raw text or an already-uploaded file, with no required
2641
+ // metadata. The server files it into the workspace Default base. When a
2642
+ // curation provider is enabled, it may name, summarize, categorize, and
2643
+ // (confidence permitting) move the document; provider=none leaves caller
2644
+ // metadata and Default placement unchanged.
2645
+ export const CreateKnowledgeDropRequest = z
2646
+ .object({
2647
+ text: z.string().min(1).max(2_000_000).optional(),
2648
+ fileId: z.string().uuid().optional(),
2649
+ filename: z.string().min(1).optional(),
2650
+ title: z.string().min(1).optional(),
2651
+ visibility: DocumentVisibility.optional(),
2652
+ agentAccess: z.boolean().optional(),
2653
+ })
2654
+ .refine((value) => (value.text === undefined) !== (value.fileId === undefined), {
2655
+ message: "provide exactly one of text or fileId",
2656
+ });
2657
+ export type CreateKnowledgeDropRequest = z.infer<typeof CreateKnowledgeDropRequest>;
2658
+
2659
+ // Move a document (and its indexed chunks) to another base. With no explicit
2660
+ // targetBaseId, applies the document's stored curation suggestion.
2661
+ export const MoveDocumentRequest = z.object({
2662
+ targetBaseId: z.string().uuid().optional(),
2663
+ });
2664
+ export type MoveDocumentRequest = z.infer<typeof MoveDocumentRequest>;
2665
+
2575
2666
  export const DocumentSearchRequest = z.object({
2576
2667
  query: z.string().min(1),
2577
2668
  baseIds: z.array(z.string().uuid()).optional(),
@@ -3134,6 +3225,29 @@ export const UpdateSessionRequest = z.object({
3134
3225
  });
3135
3226
  export type UpdateSessionRequest = z.infer<typeof UpdateSessionRequest>;
3136
3227
 
3228
+ /**
3229
+ * Replace an existing session's durable tool policy, or explicitly opt back in
3230
+ * to the current workspace defaults. The mode-less explicit shape is retained
3231
+ * for compatibility with clients released before workspace-default adoption
3232
+ * was supported.
3233
+ */
3234
+ export const UpdateSessionToolPolicyRequest = z.union([
3235
+ z
3236
+ .object({
3237
+ mode: z.literal("workspace_default"),
3238
+ expectedVersion: z.number().int().positive(),
3239
+ })
3240
+ .strict(),
3241
+ z
3242
+ .object({
3243
+ mode: z.literal("explicit").optional(),
3244
+ tools: z.array(ToolRef).max(64),
3245
+ expectedVersion: z.number().int().positive(),
3246
+ })
3247
+ .strict(),
3248
+ ]);
3249
+ export type UpdateSessionToolPolicyRequest = z.infer<typeof UpdateSessionToolPolicyRequest>;
3250
+
3137
3251
  /**
3138
3252
  * A member's personal pin preference for a session. `expectedVersion` is
3139
3253
  * optional: ordinary pin/unpin actions are idempotent last-write-wins, while a
@@ -3275,6 +3389,7 @@ export const SessionAuthorizationOperation = z.enum([
3275
3389
  "session.human_input.write",
3276
3390
  "session.title.write",
3277
3391
  "session.mcp.approval_policy.write",
3392
+ "session.tool_policy.write",
3278
3393
  "session.goal.read",
3279
3394
  "session.goal.write",
3280
3395
  "session.child.create",
@@ -3569,6 +3684,8 @@ export const NewSessionDraft = z.object({
3569
3684
  text: z.string(),
3570
3685
  resources: z.array(ResourceRef),
3571
3686
  tools: z.array(ToolRef),
3687
+ /** False means the workspace-default MCP policy is still inherited. */
3688
+ toolsProvided: z.boolean().default(false),
3572
3689
  model: z.string().min(1),
3573
3690
  reasoningEffort: ReasoningEffort,
3574
3691
  options: NewSessionDraftOptions,
@@ -3580,6 +3697,7 @@ export const SaveNewSessionDraftRequest = NewSessionDraft.pick({
3580
3697
  text: true,
3581
3698
  resources: true,
3582
3699
  tools: true,
3700
+ toolsProvided: true,
3583
3701
  model: true,
3584
3702
  reasoningEffort: true,
3585
3703
  options: true,
@@ -4155,6 +4273,10 @@ export const ScheduledTaskAgentConfig = z.object({
4155
4273
  resources: z.array(ResourceRef).default([]),
4156
4274
  tools: z.array(ToolRef).default([]),
4157
4275
  metadata: z.record(z.string(), z.unknown()).default({}),
4276
+ // Explicit workspace-shared OpenGeni Slack bot binding for scheduled runs.
4277
+ // The worker copies this non-secret pointer into session metadata; the
4278
+ // first-party Slack tools never fall back to a personal hosted-MCP grant.
4279
+ slackBotConnectionId: z.string().uuid().optional(),
4158
4280
  model: z.string().min(1).optional(),
4159
4281
  reasoningEffort: ReasoningEffort.optional(),
4160
4282
  sandboxBackend: SandboxBackend.optional(),
@@ -4539,6 +4661,34 @@ export type ConnectionKind = z.infer<typeof ConnectionKind>;
4539
4661
  export const ConnectionStatus = z.enum(["active", "needs_reauth", "revoked", "error"]);
4540
4662
  export type ConnectionStatus = z.infer<typeof ConnectionStatus>;
4541
4663
 
4664
+ export const OPENGENI_SLACK_BOT_CREDENTIAL_ROLE = "opengeni_slack_bot" as const;
4665
+ export const OPENGENI_SLACK_BOT_CREDENTIAL_LABEL = "OpenGeni Slack bot" as const;
4666
+ export const OPENGENI_SLACK_BOT_SESSION_METADATA_KEY = "opengeniSlackBotConnectionId" as const;
4667
+ export const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [
4668
+ "chat:write",
4669
+ "im:write",
4670
+ "channels:read",
4671
+ "channels:history",
4672
+ "groups:read",
4673
+ "groups:history",
4674
+ "users:read",
4675
+ ] as const;
4676
+ export const OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES = ["channels:join", "chat:write.public"] as const;
4677
+
4678
+ export const OpenGeniSlackBotConnectionMetadata = z
4679
+ .object({
4680
+ credentialRole: z.literal(OPENGENI_SLACK_BOT_CREDENTIAL_ROLE),
4681
+ credentialLabel: z.literal(OPENGENI_SLACK_BOT_CREDENTIAL_LABEL),
4682
+ slackTeamId: z.string().min(1).max(64),
4683
+ slackTeamName: z.string().min(1).max(256),
4684
+ botUserId: z.string().min(1).max(64),
4685
+ botId: z.string().min(1).max(64),
4686
+ botDisplayName: z.literal("OpenGeni"),
4687
+ verifiedAt: z.string().datetime({ offset: true }),
4688
+ })
4689
+ .passthrough();
4690
+ export type OpenGeniSlackBotConnectionMetadata = z.infer<typeof OpenGeniSlackBotConnectionMetadata>;
4691
+
4542
4692
  export const ConnectionMetadata = z.object({
4543
4693
  id: z.string().uuid(),
4544
4694
  accountId: z.string().uuid(),
@@ -4553,6 +4703,8 @@ export const ConnectionMetadata = z.object({
4553
4703
  lastUsedAt: z.string().nullable(),
4554
4704
  lastError: z.string().nullable(),
4555
4705
  version: z.number().int().positive(),
4706
+ verifiedInstallAt: z.string().datetime({ offset: true }).nullable().optional(),
4707
+ verifiedInstallVersion: z.number().int().positive().nullable().optional(),
4556
4708
  metadata: z.record(z.string(), z.unknown()),
4557
4709
  createdBySubjectId: z.string().nullable(),
4558
4710
  updatedBySubjectId: z.string().nullable(),
@@ -4575,6 +4727,16 @@ export const CreateConnectionRequest = z.object({
4575
4727
  });
4576
4728
  export type CreateConnectionRequest = z.infer<typeof CreateConnectionRequest>;
4577
4729
 
4730
+ /**
4731
+ * Write-only Slack bot installation input. `token` is accepted only by the
4732
+ * dedicated validated endpoint and is never represented in a response schema.
4733
+ */
4734
+ export const ConnectOpenGeniSlackBotRequest = z.object({
4735
+ token: z.string().trim().startsWith("xoxb-").max(8192),
4736
+ connectionId: z.string().uuid().optional(),
4737
+ });
4738
+ export type ConnectOpenGeniSlackBotRequest = z.infer<typeof ConnectOpenGeniSlackBotRequest>;
4739
+
4578
4740
  export const UpdateConnectionRequest = z.object({
4579
4741
  providerDomain: z.string().min(1).optional(),
4580
4742
  subjectId: z.string().min(1).nullable().optional(),
@@ -4853,6 +5015,10 @@ export const Session = z.object({
4853
5015
  // Origin of the persisted tool allow-list. Optional for rolling client
4854
5016
  // compatibility; current servers emit it and legacy rows map to `legacy`.
4855
5017
  toolPolicy: SessionToolPolicy.optional(),
5018
+ // Optimistic-concurrency fence for durable policy mutations. Optional for
5019
+ // older clients/fixtures; current servers always emit the authoritative
5020
+ // value.
5021
+ toolPolicyVersion: z.number().int().positive().optional(),
4856
5022
  // Secret-safe current resolution, computed at an API/read or execution
4857
5023
  // boundary from IDs only. Optional because internal DB readers need not load
4858
5024
  // the workspace runtime registry.
@@ -5103,6 +5269,7 @@ export const SessionEventType = z.enum([
5103
5269
  "terminal.pty.exited", // PTY session ended (exitCode/reason)
5104
5270
  "session.title_set",
5105
5271
  "session.mcp.approval_policy.updated",
5272
+ "session.tool_policy.updated",
5106
5273
  // Multi-account Codex (P1): the account a session's turn runs on changed
5107
5274
  // (manual switch in P1; failover/rotation in P3 reuse the same event). Drives
5108
5275
  // the in-session "Running on:" indicator's live flip.
@@ -5268,6 +5435,7 @@ export const SESSION_EVENT_SEMANTIC_CLASS_TYPES = {
5268
5435
  "session.queue.changed",
5269
5436
  "session.queue.prompt.cancelled",
5270
5437
  "session.mcp.approval_policy.updated",
5438
+ "session.tool_policy.updated",
5271
5439
  ],
5272
5440
  terminal: [
5273
5441
  "turn.completed",
@@ -7468,10 +7636,18 @@ export type GitHubRepository = z.infer<typeof GitHubRepository>;
7468
7636
  export const GitHubRepositoryScope = z.enum(["all", "selected"]);
7469
7637
  export type GitHubRepositoryScope = z.infer<typeof GitHubRepositoryScope>;
7470
7638
 
7639
+ export const GitHubBindingStatus = z.enum(["disabled", "unbound", "bound"]);
7640
+ export type GitHubBindingStatus = z.infer<typeof GitHubBindingStatus>;
7641
+
7642
+ export const GitHubInstallationLifecycle = z.enum(["active", "suspended", "deleted", "unverified"]);
7643
+ export type GitHubInstallationLifecycle = z.infer<typeof GitHubInstallationLifecycle>;
7644
+
7471
7645
  export const GitHubInstallationBinding = z.object({
7472
7646
  installationId: z.number().int().positive(),
7647
+ githubAccountId: z.number().int().positive().nullable(),
7473
7648
  accountLogin: z.string().nullable(),
7474
7649
  accountType: z.string().nullable(),
7650
+ lifecycle: GitHubInstallationLifecycle,
7475
7651
  repositoryScope: GitHubRepositoryScope,
7476
7652
  repositoryCount: z.number().int().nonnegative(),
7477
7653
  createdAt: z.string(),
@@ -7481,6 +7657,7 @@ export type GitHubInstallationBinding = z.infer<typeof GitHubInstallationBinding
7481
7657
 
7482
7658
  export const GitHubAppInfo = z.object({
7483
7659
  configured: z.boolean(),
7660
+ status: GitHubBindingStatus,
7484
7661
  appId: z.string().nullable(),
7485
7662
  clientId: z.string().nullable(),
7486
7663
  appSlug: z.string().nullable(),
@@ -8473,6 +8650,8 @@ export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalog
8473
8650
  */
8474
8651
  export const OPENGENI_API_CONTRACT_REVISION = "2026-07-turn-instructions-v1" as const;
8475
8652
  export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
8653
+ /** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
8654
+ export const OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id" as const;
8476
8655
 
8477
8656
  export const ClientConfig = /* @__PURE__ */ defineModelContractSchema(() =>
8478
8657
  z.object({
@@ -8594,3 +8773,5 @@ export function evaluateWorkspaceModelPolicy(
8594
8773
  }
8595
8774
 
8596
8775
  export * from "./codex-fleet-policy";
8776
+ export * from "./secret-redaction";
8777
+ export * from "./workspace-instruction-policies";