@opengeni/contracts 0.4.0 → 0.6.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.4.0",
3
+ "version": "0.6.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
@@ -486,6 +486,10 @@ export const Permission = z.enum([
486
486
  "api_keys:manage",
487
487
  "environments:manage",
488
488
  "environments:use",
489
+ // Attach or rotate per-session third-party MCP server credentials. Deliberately
490
+ // not part of the worker's default first-party MCP permission set: a sandboxed
491
+ // agent must not be able to hand itself new bearer credentials.
492
+ "mcp_servers:attach",
489
493
  "goals:manage",
490
494
  // Bring-your-own-compute (M5). enrollments:read lists a workspace's machines;
491
495
  // enrollments:manage approves a device-flow enrollment (the LOUD whole-machine
@@ -1351,19 +1355,53 @@ export type DocumentSearchRequest = z.infer<typeof DocumentSearchRequest>;
1351
1355
  export const ToolRef = z.object({
1352
1356
  kind: z.literal("mcp"),
1353
1357
  id: z.string().min(1),
1354
- // Non-fatal-on-connect marker for an AUTO-ATTACHED (workspace-default)
1355
- // capability MCP server: when true, a connect / tools-list failure (e.g. an
1356
- // expired capability credential returning 401) must SKIP that server with a
1357
- // logged warning and let the turn proceed, rather than failing the whole
1358
- // turn before the model runs. Absent/false STRICT: an unavailable server
1359
- // fails the turn (the contract for EXPLICITLY-requested tools). This flag is
1360
- // set server-side only, at the default-capability auto-attach seam; it is
1361
- // stripped from client-supplied tool refs so an explicit request always
1362
- // stays strict.
1358
+ // Non-fatal-on-connect marker for MCP server refs that can degrade
1359
+ // gracefully. Absent/false is STRICT: the id must be configured and an
1360
+ // unavailable server fails the turn. `optional:true` is preserved for known
1361
+ // servers and makes runtime connect/list failures skip that server; if the
1362
+ // deployment does not configure the id, validation drops the ref. The server
1363
+ // also sets this for auto-attached workspace-default capability MCPs.
1363
1364
  optional: z.boolean().optional(),
1364
1365
  });
1365
1366
  export type ToolRef = z.infer<typeof ToolRef>;
1366
1367
 
1368
+ const registryId = /^[A-Za-z0-9_-]+$/;
1369
+ const httpsUrl = z.string().url().refine((value) => {
1370
+ try {
1371
+ return new URL(value).protocol === "https:";
1372
+ } catch {
1373
+ return false;
1374
+ }
1375
+ }, { message: "URL must use https" });
1376
+
1377
+ export const SessionMcpServerInput = z.object({
1378
+ id: z.string().min(1).regex(registryId),
1379
+ name: z.string().min(1).optional(),
1380
+ url: httpsUrl,
1381
+ allowedTools: z.array(z.string().min(1)).optional(),
1382
+ timeoutMs: z.number().int().positive().optional(),
1383
+ cacheToolsList: z.boolean().optional(),
1384
+ // Write-only credential headers. Values are encrypted at rest and never
1385
+ // returned in session responses or events; response metadata exposes names.
1386
+ headers: z.record(z.string(), z.string()).optional(),
1387
+ });
1388
+ export type SessionMcpServerInput = z.infer<typeof SessionMcpServerInput>;
1389
+
1390
+ export const SessionMcpCredentialUpdateInput = z.object({
1391
+ id: z.string().min(1).regex(registryId),
1392
+ headers: z.record(z.string(), z.string()),
1393
+ });
1394
+ export type SessionMcpCredentialUpdateInput = z.infer<typeof SessionMcpCredentialUpdateInput>;
1395
+
1396
+ export const SessionMcpServerMetadata = z.object({
1397
+ id: z.string().min(1).regex(registryId),
1398
+ name: z.string().min(1).nullable(),
1399
+ url: httpsUrl,
1400
+ headerNames: z.array(z.string()).default([]),
1401
+ credentialVersion: z.number().int().positive(),
1402
+ }).strict();
1403
+ export type SessionMcpServerMetadata = z.infer<typeof SessionMcpServerMetadata>;
1404
+
1367
1405
  export class ResourceRefConflictError extends Error {
1368
1406
  constructor(message: string) {
1369
1407
  super(message);
@@ -1382,10 +1420,10 @@ export function mergeToolRefs(existing: ToolRef[], additions: ToolRef[]): ToolRe
1382
1420
  order.push(key);
1383
1421
  continue;
1384
1422
  }
1385
- // Strict wins: if the same server appears both auto-attached (optional) and
1386
- // explicitly requested (non-optional), the explicit occurrence upgrades the
1387
- // merged ref to strict a later explicit request of an already-defaulted
1388
- // capability MCP must still fail the turn when the server is unavailable.
1423
+ // Strict wins: if the same server appears both optional and strict, the
1424
+ // strict occurrence upgrades the merged ref so an unavailable server fails
1425
+ // the turn. This preserves the fail-loud default when defaults, packs, and
1426
+ // per-turn tool selections are combined.
1389
1427
  if (prior.optional === true && tool.optional !== true) {
1390
1428
  const { optional: _dropped, ...strict } = prior;
1391
1429
  byKey.set(key, strict);
@@ -2145,6 +2183,10 @@ export const Session = z.object({
2145
2183
  initialMessage: z.string(),
2146
2184
  title: z.string().nullable(),
2147
2185
  titleSource: z.enum(["user", "agent"]).nullable(),
2186
+ // Per-session agent persona/system instructions supplied at create. Org-visible
2187
+ // metadata (exposed like title/goal), never a secret and never a timeline event.
2188
+ // null when the session carried none.
2189
+ instructions: z.string().nullable(),
2148
2190
  resources: z.array(ResourceRef),
2149
2191
  tools: z.array(ToolRef),
2150
2192
  metadata: z.record(z.string(), z.unknown()),
@@ -2167,6 +2209,9 @@ export const Session = z.object({
2167
2209
  // Non-default first-party MCP token permissions (manager-style sessions);
2168
2210
  // null means the fixed worker default set.
2169
2211
  firstPartyMcpPermissions: z.array(Permission).nullable(),
2212
+ // Per-session third-party MCP servers, metadata only. Credential values are
2213
+ // write-only and never appear here.
2214
+ mcpServers: z.array(SessionMcpServerMetadata).default([]),
2170
2215
  // The manager session that spawned this one via session_create (set only
2171
2216
  // when the creating grant carried a worker-signed sessionId claim); null for
2172
2217
  // direct API creates and scheduled-task runs. When set, this session's
@@ -2738,6 +2783,15 @@ export type SessionEvent = z.infer<typeof SessionEvent>;
2738
2783
 
2739
2784
  export const CreateSessionRequest = z.object({
2740
2785
  initialMessage: z.string().min(1),
2786
+ // Per-session agent persona/system instructions (org-visible metadata, NOT a
2787
+ // secret). Rides the SAME system-level instructions channel the per-workspace
2788
+ // agentInstructions rides, composed AFTER the workspace persona so it refines
2789
+ // it for this one session — how a host delivers per-agent-type prompts without
2790
+ // leaking them into the user-visible timeline (it is NEVER emitted as an
2791
+ // event, unlike goal/initialMessage). Trimmed, non-empty. The 32768-char cap
2792
+ // matches the codebase's largest free-form string convention (workspace
2793
+ // environment variable values). Absent ⇒ byte-identical to today.
2794
+ instructions: z.string().trim().min(1).max(32768).optional(),
2741
2795
  resources: z.array(ResourceRef).default([]),
2742
2796
  tools: z.array(ToolRef).default([]),
2743
2797
  metadata: z.record(z.string(), z.unknown()).default({}),
@@ -2772,6 +2826,9 @@ export const CreateSessionRequest = z.object({
2772
2826
  // the orchestration/environment/github tools. Capped at creation: every
2773
2827
  // requested permission must be held by the creating grant (no escalation).
2774
2828
  firstPartyMcpPermissions: z.array(Permission).optional(),
2829
+ // Third-party MCP servers attached only to this session. Credential headers are
2830
+ // write-only: create responses and events expose only SessionMcpServerMetadata.
2831
+ mcpServers: z.array(SessionMcpServerInput).default([]),
2775
2832
  // Shared-sandbox placement (addendum 05 §D.1). Three-way union; OMITTED ⇒
2776
2833
  // today's behavior (a context-dependent default resolved server-side: from
2777
2834
  // inside a session → "shared" with the creator's box, top-level → "new").
@@ -2807,6 +2864,9 @@ export const ClientSessionEvent = z.discriminatedUnion("type", [
2807
2864
  tools: z.array(ToolRef).default([]),
2808
2865
  model: z.string().min(1).optional(),
2809
2866
  reasoningEffort: ReasoningEffort.optional(),
2867
+ // Header-value rotation only. URL/name/tool settings are immutable after
2868
+ // session create; persisted events expose metadata, never header values.
2869
+ mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional(),
2810
2870
  }),
2811
2871
  }),
2812
2872
  z.object({