@opengeni/contracts 0.50.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ import { MemorySlackPublicationDistribution } from "./memory-slack-delivery";
10
10
  import { WorkspaceInstructionPolicyRoleKeyInput } from "./workspace-instruction-policies";
11
11
  import { ClientResumableVoiceInputConfig } from "./transcription-recordings";
12
12
  import { MediaGenerationResult } from "./video-generation";
13
+ import { KnowledgeProviderCitation } from "./knowledge";
13
14
 
14
15
  export * from "./slack-bot-scopes";
15
16
  export * from "./slack-task-policy";
@@ -4025,6 +4026,7 @@ export const DocumentSearchResult = z.object({
4025
4026
  authorityKind: DocumentAuthorityKind,
4026
4027
  authorityWorkspaceId: z.string().uuid().nullable(),
4027
4028
  authoritySubjectId: z.string().nullable(),
4029
+ citation: KnowledgeProviderCitation.nullable().optional(),
4028
4030
  });
4029
4031
  export type DocumentSearchResult = z.infer<typeof DocumentSearchResult>;
4030
4032
 
@@ -4054,6 +4056,7 @@ export const IndexedDocumentProvenance = z.object({
4054
4056
  authoritySubjectId: z.string().nullable(),
4055
4057
  createdBy: z.string().nullable(),
4056
4058
  createdAt: z.string(),
4059
+ citation: KnowledgeProviderCitation.nullable().optional(),
4057
4060
  });
4058
4061
  export type IndexedDocumentProvenance = z.infer<typeof IndexedDocumentProvenance>;
4059
4062
 
@@ -5089,8 +5092,26 @@ export const SessionRealtimeInboundEntry = z
5089
5092
  delegationItemId: z.string().max(1024).nullable().optional(),
5090
5093
  text: z.string().max(131_072).nullable().optional(),
5091
5094
  payload: z.record(z.string(), z.unknown()).optional(),
5095
+ // Application context attached to the exact delegation/transcript message.
5096
+ // It is ordinary model-visible user-message content when materialized, not
5097
+ // a secret or instruction-authority boundary.
5098
+ modelContext: z.string().trim().min(1).max(32768).optional(),
5092
5099
  })
5093
- .strict();
5100
+ .strict()
5101
+ .superRefine((entry, context) => {
5102
+ if (
5103
+ entry.modelContext !== undefined &&
5104
+ entry.kind !== "delegation_call" &&
5105
+ entry.kind !== "user_transcript" &&
5106
+ entry.kind !== "assistant_transcript"
5107
+ ) {
5108
+ context.addIssue({
5109
+ code: "custom",
5110
+ path: ["modelContext"],
5111
+ message: "modelContext requires a delegation or finalized transcript entry",
5112
+ });
5113
+ }
5114
+ });
5094
5115
  export type SessionRealtimeInboundEntry = z.infer<typeof SessionRealtimeInboundEntry>;
5095
5116
 
5096
5117
  export const SyncSessionRealtimeLedgerRequest = SessionRealtimeOwnerProof.extend({
@@ -5559,6 +5580,28 @@ export function renderTimelineAnnotationsForModel(
5559
5580
  ].join("\n");
5560
5581
  }
5561
5582
 
5583
+ export const MODEL_CONTEXT_LABEL = "[Application context attached to this user message]" as const;
5584
+
5585
+ /**
5586
+ * Build one canonical user-role message body. `modelContext` is ordinary
5587
+ * message content: it is model-visible in the same chronological position as
5588
+ * the visible text, but presentation layers may omit it. It is not a secret or
5589
+ * an instruction-authority boundary.
5590
+ */
5591
+ export function renderUserMessageContentForModel(
5592
+ text: string,
5593
+ annotations: readonly TimelineAnnotation[],
5594
+ modelContext?: string | null,
5595
+ ): string | Array<{ type: "input_text"; text: string }> {
5596
+ const visibleContent = renderTimelineAnnotationsForModel(text, annotations);
5597
+ const context = modelContext?.trim();
5598
+ if (!context) return visibleContent;
5599
+ return [
5600
+ { type: "input_text", text: `${MODEL_CONTEXT_LABEL}\n${context}` },
5601
+ { type: "input_text", text: visibleContent },
5602
+ ];
5603
+ }
5604
+
5562
5605
  export const SessionTurn = z
5563
5606
  .object({
5564
5607
  id: z.string().uuid(),
@@ -6168,12 +6211,16 @@ export const VariableSetVariableName = z
6168
6211
  .max(128);
6169
6212
  export type VariableSetVariableName = z.infer<typeof VariableSetVariableName>;
6170
6213
 
6171
- function withVariableSetIdAlias<T extends z.ZodRawShape>(shape: T) {
6214
+ function withVariableSetIdAlias<T extends z.ZodRawShape>(
6215
+ shape: T,
6216
+ options: { rejectKeys?: readonly string[] } = {},
6217
+ ) {
6172
6218
  return z.preprocess((input) => {
6173
6219
  if (!input || typeof input !== "object" || Array.isArray(input)) {
6174
6220
  return input;
6175
6221
  }
6176
6222
  const record = input as Record<string, unknown>;
6223
+ if (options.rejectKeys?.some((key) => Object.hasOwn(record, key))) return null;
6177
6224
  if (record.variableSetId !== undefined || record.environmentId === undefined) {
6178
6225
  return record;
6179
6226
  }
@@ -11221,134 +11268,138 @@ export const SessionControlResponse = z.object({
11221
11268
  });
11222
11269
  export type SessionControlResponse = z.infer<typeof SessionControlResponse>;
11223
11270
 
11224
- export const CreateSessionRequest = withVariableSetIdAlias({
11225
- /**
11226
- * Optional UUID preallocated by an embedding host. This lets the host durably
11227
- * link its own projection before OpenGeni admits the initial turn. Replays
11228
- * must pair it with the same idempotency key; OpenGeni never derives host
11229
- * identity or authorization from the UUID.
11230
- */
11231
- requestedSessionId: z.string().uuid().optional(),
11232
- initialMessage: z.string().min(1).optional(),
11233
- // Creates the durable session shell without fabricating a user message or
11234
- // starting an underlying agent turn. Realtime can then become the first
11235
- // interaction and use the ordinary Send/Steer path when it delegates.
11236
- startMode: z.literal("realtime").optional(),
11237
- // System-level host context for the initial turn only. Unlike `instructions`,
11238
- // this does not persist into later turns and is never emitted as a user event.
11239
- turnInstructions: z.string().trim().min(1).max(32768).optional(),
11240
- // Per-session agent persona/system instructions (org-visible metadata, NOT a
11241
- // secret). Rides the SAME system-level instructions channel the per-workspace
11242
- // agentInstructions rides, composed AFTER the workspace persona so it refines
11243
- // it for this one session how a host delivers per-agent-type prompts without
11244
- // leaking them into the user-visible timeline (it is NEVER emitted as an
11245
- // event, unlike goal/initialMessage). Trimmed, non-empty. The 32768-char cap
11246
- // matches the codebase's largest free-form string convention (workspace
11247
- // variable set variable values). Absent byte-identical to today.
11248
- instructions: z.string().trim().min(1).max(32768).optional(),
11249
- // Immutable prompt-policy role binding for matching one activated role
11250
- // policy. This never derives from or grants a human workspace membership
11251
- // role. Existing callers may continue to use normalized metadata.role as a
11252
- // compatibility fallback by omitting this field.
11253
- policyRole: WorkspaceInstructionPolicyRoleKeyInput.optional(),
11254
- // For an agent-created child, omission inherits the trusted immediate
11255
- // parent's repository/file context. An explicit array, including [], is
11256
- // authoritative. Top-level omission remains []. Presence is resolved from
11257
- // the raw request because this Zod default erases absent-vs-empty.
11258
- resources: z.array(ResourceRef).default([]),
11259
- // Inline skills are fixed onto the session. Child omission inherits the
11260
- // trusted parent's selection; an explicit array, including [], wins.
11261
- skills: SessionSkills.default([]),
11262
- // The same child omission rule applies to selected MCP tool refs. Top-level
11263
- // omission still applies workspace-default capability MCP tools; explicit []
11264
- // suppresses those defaults (the first-party OpenGeni server remains added).
11265
- tools: z.array(ToolRef).default([]),
11266
- metadata: z.record(z.string(), z.unknown()).default({}),
11267
- model: z.string().min(1).optional(),
11268
- reasoningEffort: ReasoningEffort.optional(),
11269
- latencyMode: LatencyMode.optional(),
11270
- sandboxBackend: SandboxBackend.optional(),
11271
- // The enrolled machine (a sandbox id) to run this session on; seeds the
11272
- // active-sandbox pointer at creation so the FIRST turn routes to the chosen
11273
- // machine (race-free: the pointer is committed before the worker turn
11274
- // workflow can read it). An invalid/unowned/offline target fails the create.
11275
- targetSandboxId: z.string().uuid().optional(),
11276
- // The working directory the targeted machine runs the session under — the
11277
- // path/cwd base for its agent exec, terminal, and file dock. Free-form pass-
11278
- // through: a launch-workspace_root-relative subdir or an absolute machine path
11279
- // (the agent's resolve_cwd handles both). Only valid WITH targetSandboxId
11280
- // (workingDir alone is a 422); omitted the machine's default workspace_root.
11281
- workingDir: z.string().min(1).optional(),
11282
- // Variable set attachment is fixed at session creation; follow-up
11283
- // user.message events cannot switch or add one.
11284
- variableSetId: z.string().uuid().optional(),
11285
- environmentId: z.string().uuid().optional(),
11286
- // The rig to bind this session to (M3). Its ACTIVE version is resolved and
11287
- // FROZEN onto the session at create. Omitted ⇒ inherit the workspace default;
11288
- // null explicitly create a rig-less session; UUID bind that exact rig.
11289
- // An id that does not name a rig in the workspace is a 422.
11290
- rigId: z.string().uuid().nullable().optional(),
11291
- // The workspace channel to file this session under (rail organization only).
11292
- // Omitted/null ⇒ unfiled (inbox). An id that does not name a channel in the
11293
- // workspace is a 422.
11294
- channelId: z.string().uuid().nullable().optional(),
11295
- goal: GoalSpec.optional(),
11296
- clientEventId: SessionOperationKey.optional(),
11297
- // Workspace-scoped CREATE idempotency key: collapses concurrent/retried
11298
- // create calls carrying the same key to a single session (partial unique
11299
- // index on (workspace_id, create_idempotency_key)). Distinct from
11300
- // clientEventId, whose uniqueness is per-session and so cannot dedup the
11301
- // creation of a brand-new session. Absent means no create-dedup (each call
11302
- // is an independent create).
11303
- idempotencyKey: z.string().min(1).max(200).optional(),
11304
- // The exact actor-private pre-session draft revision represented by this
11305
- // create. The durable initializer consumes only this revision. A newer draft
11306
- // written by a sibling tab survives, while every failed pre-initialization
11307
- // create leaves the submitted draft intact.
11308
- expectedNewSessionDraftRevision: z.number().int().nonnegative().optional(),
11309
- // A child may lower its inherited limit freely; an increase requires
11310
- // workspace:admin and is checked again at the DB transaction boundary.
11311
- maxNestedAgentDepth: NestedAgentDepthValue.optional(),
11312
- // Permissions the session's first-party MCP token should carry. A top-level
11313
- // omission uses the deployment's worker default; a child omission inherits
11314
- // the creating session's effective grant. An explicit set is capped at
11315
- // creation: every requested permission must be held by the creating grant.
11316
- // A goal-bearing session whose explicit/effective set omits goals:manage is
11317
- // rejected; creation never silently expands a child beyond that set.
11318
- firstPartyMcpPermissions: z.array(Permission).optional(),
11319
- // Exact model-visible selection from the broad first-party OpenGeni MCP
11320
- // catalog. Omission selects the safe non-connector default; [] intentionally
11321
- // exposes none.
11322
- // This does not grant authority: every registered tool is permission-gated.
11323
- firstPartyMcpTools: z.array(FirstPartyMcpToolName).optional(),
11324
- // Third-party MCP servers attached only to this session. For an agent-created
11325
- // child, omission snapshots its trusted immediate parent's server definitions,
11326
- // policies, connection refs, and encrypted credentials. Explicit arrays,
11327
- // including [], are authoritative; non-empty explicit arrays require attach
11328
- // permission. Credential headers are write-only: create responses and events
11329
- // expose only SessionMcpServerMetadata.
11330
- mcpServers: z.array(SessionMcpServerInput).max(SESSION_MCP_SERVERS_MAX).default([]),
11331
- // Shared-sandbox placement (addendum 05 §D.1). Three-way union; OMITTED ⇒
11332
- // today's behavior (a context-dependent default resolved server-side: from
11333
- // inside a session "shared" with the creator's box, top-level → "new").
11334
- // - "shared": join the CREATOR's box. Requires a parent session (inferred
11335
- // from the worker-signed sessionId claim, never caller-supplied);
11336
- // top-level "shared" is a 422.
11337
- // - "new": mint a fresh singleton box (group ≡ the new session's id).
11338
- // - {groupId}: join a SPECIFIC sibling group in THIS workspace (manager
11339
- // fan-out). Validated workspace-scoped (cross-workspace 404).
11340
- // A shared spawn inherits the box's (backend, os) it is literally the same
11341
- // box; the child cannot pick its own backend. Cross-workspace sharing is
11342
- // forbidden by construction (the parent/group reads are RLS-workspace-scoped).
11343
- // ENV-AWARE: the box's variable set is fixed at creation, so a share requires
11344
- // the SAME variableSetId as the creator's box. On a mismatch the inherited
11345
- // default silently falls back to an own box; an explicit "shared"/{groupId}
11346
- // request 422s at create (instead of the first turn dying on the SDK's
11347
- // manifest-env guard).
11348
- sandbox: z
11349
- .union([z.literal("shared"), z.literal("new"), z.object({ groupId: z.string().uuid() })])
11350
- .optional(),
11351
- }).superRefine((value, context) => {
11271
+ export const CreateSessionRequest = withVariableSetIdAlias(
11272
+ {
11273
+ /**
11274
+ * Optional UUID preallocated by an embedding host. This lets the host durably
11275
+ * link its own projection before OpenGeni admits the initial turn. Replays
11276
+ * must pair it with the same idempotency key; OpenGeni never derives host
11277
+ * identity or authorization from the UUID.
11278
+ */
11279
+ requestedSessionId: z.string().uuid().optional(),
11280
+ initialMessage: z.string().min(1).optional(),
11281
+ // Creates the durable session shell without fabricating a user message or
11282
+ // starting an underlying agent turn. Realtime can then become the first
11283
+ // interaction and use the ordinary Send/Steer path when it delegates.
11284
+ startMode: z.literal("realtime").optional(),
11285
+ // Model-visible application context attached to the initial user message.
11286
+ // Standard timeline rendering omits it, while full event/audit reads retain
11287
+ // it. This is ordinary user-role content, not secret or privileged input.
11288
+ modelContext: z.string().trim().min(1).max(32768).optional(),
11289
+ // Per-session agent persona/system instructions (org-visible metadata, NOT a
11290
+ // secret). Rides the SAME system-level instructions channel the per-workspace
11291
+ // agentInstructions rides, composed AFTER the workspace persona so it refines
11292
+ // it for this one session how a host delivers per-agent-type prompts without
11293
+ // leaking them into the user-visible timeline (it is NEVER emitted as an
11294
+ // event, unlike goal/initialMessage). Trimmed, non-empty. The 32768-char cap
11295
+ // matches the codebase's largest free-form string convention (workspace
11296
+ // variable set variable values). Absent byte-identical to today.
11297
+ instructions: z.string().trim().min(1).max(32768).optional(),
11298
+ // Immutable prompt-policy role binding for matching one activated role
11299
+ // policy. This never derives from or grants a human workspace membership
11300
+ // role. Existing callers may continue to use normalized metadata.role as a
11301
+ // compatibility fallback by omitting this field.
11302
+ policyRole: WorkspaceInstructionPolicyRoleKeyInput.optional(),
11303
+ // For an agent-created child, omission inherits the trusted immediate
11304
+ // parent's repository/file context. An explicit array, including [], is
11305
+ // authoritative. Top-level omission remains []. Presence is resolved from
11306
+ // the raw request because this Zod default erases absent-vs-empty.
11307
+ resources: z.array(ResourceRef).default([]),
11308
+ // Inline skills are fixed onto the session. Child omission inherits the
11309
+ // trusted parent's selection; an explicit array, including [], wins.
11310
+ skills: SessionSkills.default([]),
11311
+ // The same child omission rule applies to selected MCP tool refs. Top-level
11312
+ // omission still applies workspace-default capability MCP tools; explicit []
11313
+ // suppresses those defaults (the first-party OpenGeni server remains added).
11314
+ tools: z.array(ToolRef).default([]),
11315
+ metadata: z.record(z.string(), z.unknown()).default({}),
11316
+ model: z.string().min(1).optional(),
11317
+ reasoningEffort: ReasoningEffort.optional(),
11318
+ latencyMode: LatencyMode.optional(),
11319
+ sandboxBackend: SandboxBackend.optional(),
11320
+ // The enrolled machine (a sandbox id) to run this session on; seeds the
11321
+ // active-sandbox pointer at creation so the FIRST turn routes to the chosen
11322
+ // machine (race-free: the pointer is committed before the worker turn
11323
+ // workflow can read it). An invalid/unowned/offline target fails the create.
11324
+ targetSandboxId: z.string().uuid().optional(),
11325
+ // The working directory the targeted machine runs the session under — the
11326
+ // path/cwd base for its agent exec, terminal, and file dock. Free-form pass-
11327
+ // through: a launch-workspace_root-relative subdir or an absolute machine path
11328
+ // (the agent's resolve_cwd handles both). Only valid WITH targetSandboxId
11329
+ // (workingDir alone is a 422); omitted the machine's default workspace_root.
11330
+ workingDir: z.string().min(1).optional(),
11331
+ // Variable set attachment is fixed at session creation; follow-up
11332
+ // user.message events cannot switch or add one.
11333
+ variableSetId: z.string().uuid().optional(),
11334
+ environmentId: z.string().uuid().optional(),
11335
+ // The rig to bind this session to (M3). Its ACTIVE version is resolved and
11336
+ // FROZEN onto the session at create. Omitted inherit the workspace default;
11337
+ // null ⇒ explicitly create a rig-less session; UUID ⇒ bind that exact rig.
11338
+ // An id that does not name a rig in the workspace is a 422.
11339
+ rigId: z.string().uuid().nullable().optional(),
11340
+ // The workspace channel to file this session under (rail organization only).
11341
+ // Omitted/null ⇒ unfiled (inbox). An id that does not name a channel in the
11342
+ // workspace is a 422.
11343
+ channelId: z.string().uuid().nullable().optional(),
11344
+ goal: GoalSpec.optional(),
11345
+ clientEventId: SessionOperationKey.optional(),
11346
+ // Workspace-scoped CREATE idempotency key: collapses concurrent/retried
11347
+ // create calls carrying the same key to a single session (partial unique
11348
+ // index on (workspace_id, create_idempotency_key)). Distinct from
11349
+ // clientEventId, whose uniqueness is per-session and so cannot dedup the
11350
+ // creation of a brand-new session. Absent means no create-dedup (each call
11351
+ // is an independent create).
11352
+ idempotencyKey: z.string().min(1).max(200).optional(),
11353
+ // The exact actor-private pre-session draft revision represented by this
11354
+ // create. The durable initializer consumes only this revision. A newer draft
11355
+ // written by a sibling tab survives, while every failed pre-initialization
11356
+ // create leaves the submitted draft intact.
11357
+ expectedNewSessionDraftRevision: z.number().int().nonnegative().optional(),
11358
+ // A child may lower its inherited limit freely; an increase requires
11359
+ // workspace:admin and is checked again at the DB transaction boundary.
11360
+ maxNestedAgentDepth: NestedAgentDepthValue.optional(),
11361
+ // Permissions the session's first-party MCP token should carry. A top-level
11362
+ // omission uses the deployment's worker default; a child omission inherits
11363
+ // the creating session's effective grant. An explicit set is capped at
11364
+ // creation: every requested permission must be held by the creating grant.
11365
+ // A goal-bearing session whose explicit/effective set omits goals:manage is
11366
+ // rejected; creation never silently expands a child beyond that set.
11367
+ firstPartyMcpPermissions: z.array(Permission).optional(),
11368
+ // Exact model-visible selection from the broad first-party OpenGeni MCP
11369
+ // catalog. Omission selects the safe non-connector default; [] intentionally
11370
+ // exposes none.
11371
+ // This does not grant authority: every registered tool is permission-gated.
11372
+ firstPartyMcpTools: z.array(FirstPartyMcpToolName).optional(),
11373
+ // Third-party MCP servers attached only to this session. For an agent-created
11374
+ // child, omission snapshots its trusted immediate parent's server definitions,
11375
+ // policies, connection refs, and encrypted credentials. Explicit arrays,
11376
+ // including [], are authoritative; non-empty explicit arrays require attach
11377
+ // permission. Credential headers are write-only: create responses and events
11378
+ // expose only SessionMcpServerMetadata.
11379
+ mcpServers: z.array(SessionMcpServerInput).max(SESSION_MCP_SERVERS_MAX).default([]),
11380
+ // Shared-sandbox placement (addendum 05 §D.1). Three-way union; OMITTED
11381
+ // today's behavior (a context-dependent default resolved server-side: from
11382
+ // inside a session → "shared" with the creator's box, top-level → "new").
11383
+ // - "shared": join the CREATOR's box. Requires a parent session (inferred
11384
+ // from the worker-signed sessionId claim, never caller-supplied);
11385
+ // top-level "shared" is a 422.
11386
+ // - "new": mint a fresh singleton box (group the new session's id).
11387
+ // - {groupId}: join a SPECIFIC sibling group in THIS workspace (manager
11388
+ // fan-out). Validated workspace-scoped (cross-workspace 404).
11389
+ // A shared spawn inherits the box's (backend, os) — it is literally the same
11390
+ // box; the child cannot pick its own backend. Cross-workspace sharing is
11391
+ // forbidden by construction (the parent/group reads are RLS-workspace-scoped).
11392
+ // ENV-AWARE: the box's variable set is fixed at creation, so a share requires
11393
+ // the SAME variableSetId as the creator's box. On a mismatch the inherited
11394
+ // default silently falls back to an own box; an explicit "shared"/{groupId}
11395
+ // request 422s at create (instead of the first turn dying on the SDK's
11396
+ // manifest-env guard).
11397
+ sandbox: z
11398
+ .union([z.literal("shared"), z.literal("new"), z.object({ groupId: z.string().uuid() })])
11399
+ .optional(),
11400
+ },
11401
+ { rejectKeys: ["turnInstructions"] },
11402
+ ).superRefine((value, context) => {
11352
11403
  if (value.startMode !== "realtime" && value.initialMessage === undefined) {
11353
11404
  context.addIssue({
11354
11405
  code: z.ZodIssueCode.custom,
@@ -11363,6 +11414,13 @@ export const CreateSessionRequest = withVariableSetIdAlias({
11363
11414
  message: "initialMessage must be omitted when startMode is realtime",
11364
11415
  });
11365
11416
  }
11417
+ if (value.startMode === "realtime" && value.modelContext !== undefined) {
11418
+ context.addIssue({
11419
+ code: z.ZodIssueCode.custom,
11420
+ path: ["modelContext"],
11421
+ message: "modelContext requires an initialMessage; attach it to a realtime entry instead",
11422
+ });
11423
+ }
11366
11424
  });
11367
11425
  export type CreateSessionRequest = z.infer<typeof CreateSessionRequest>;
11368
11426
 
@@ -11549,9 +11607,9 @@ export const SessionUserMessagePayload = z
11549
11607
  .object({
11550
11608
  text: z.string().default(""),
11551
11609
  annotations: SubmittedTimelineAnnotations.default([]),
11552
- // System-level host context for this exact turn only. Persisted on the
11553
- // turn for retry/recovery, never copied into the visible user message.
11554
- turnInstructions: z.string().trim().min(1).max(32768).optional(),
11610
+ // Model-visible application context attached to this exact user message.
11611
+ // It is retained in full event/history data but omitted by standard UI.
11612
+ modelContext: z.string().trim().min(1).max(32768).optional(),
11555
11613
  resources: z.array(ResourceRef).default([]),
11556
11614
  model: z.string().min(1).optional(),
11557
11615
  reasoningEffort: ReasoningEffort.optional(),
@@ -11596,8 +11654,8 @@ export const SteerSessionMessageRequest = z
11596
11654
  .object({
11597
11655
  text: z.string().default(""),
11598
11656
  annotations: SubmittedTimelineAnnotations.default([]),
11599
- // Same per-turn system-level context as a queued user.message.
11600
- turnInstructions: z.string().trim().min(1).max(32768).optional(),
11657
+ // Same model-visible message context as a queued user.message.
11658
+ modelContext: z.string().trim().min(1).max(32768).optional(),
11601
11659
  resources: z.array(ResourceRef).default([]),
11602
11660
  model: z.string().min(1).optional(),
11603
11661
  reasoningEffort: ReasoningEffort.optional(),
@@ -12752,7 +12810,7 @@ export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalog
12752
12810
  * that rollout boundary. Mutating clients send this value in
12753
12811
  * `x-opengeni-api-contract`; the API rejects any other value before routing.
12754
12812
  */
12755
- export const OPENGENI_API_CONTRACT_REVISION = "2026-08-social-provider-tools-v1" as const;
12813
+ export const OPENGENI_API_CONTRACT_REVISION = "2026-08-model-context-v1" as const;
12756
12814
  export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
12757
12815
  /** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
12758
12816
  export const OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id" as const;
package/src/knowledge.ts CHANGED
@@ -102,6 +102,20 @@ export const KnowledgeSource = z.object({
102
102
  });
103
103
  export type KnowledgeSource = z.infer<typeof KnowledgeSource>;
104
104
 
105
+ export const KnowledgeProviderCitation = z.object({
106
+ provider: z.literal("google_drive"),
107
+ externalObjectId: boundedUtf8(KNOWLEDGE_SOURCE_STRING_MAX_BYTES),
108
+ providerRevision: boundedUtf8(KNOWLEDGE_SOURCE_STRING_MAX_BYTES).nullable(),
109
+ sourceVersion: boundedUtf8(KNOWLEDGE_SOURCE_STRING_MAX_BYTES),
110
+ driveId: boundedUtf8(KNOWLEDGE_SOURCE_STRING_MAX_BYTES).nullable(),
111
+ deepLink: boundedUtf8(KNOWLEDGE_SOURCE_URI_MAX_BYTES).pipe(z.string().min(1)).nullable(),
112
+ aclRevision: z.string().regex(/^[0-9a-f]{64}$/u),
113
+ authorizationObservedAt: z.string().datetime({ offset: true }),
114
+ authorizationExpiresAt: z.string().datetime({ offset: true }),
115
+ reauthorizedAt: z.string().datetime({ offset: true }),
116
+ });
117
+ export type KnowledgeProviderCitation = z.infer<typeof KnowledgeProviderCitation>;
118
+
105
119
  export const KnowledgeLinkTarget = z.discriminatedUnion("kind", [
106
120
  z.object({
107
121
  kind: z.literal("knowledge"),
@@ -144,6 +158,7 @@ export const KnowledgeRecord = z.object({
144
158
  provenance: z.object({
145
159
  source: KnowledgeSource,
146
160
  indexedAt: z.string(),
161
+ citation: KnowledgeProviderCitation.nullable().optional(),
147
162
  }),
148
163
  lifecycle: z.object({
149
164
  state: z.literal("active"),