@granular-software/sdk 0.4.30 → 0.4.32

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.
@@ -9,7 +9,7 @@ import { Doc } from '@automerge/automerge/slim';
9
9
  * Configuration for the Granular client
10
10
  */
11
11
  type AccessTokenProvider = () => Promise<string | null | undefined> | string | null | undefined;
12
- type EndpointMode = "auto" | "local" | "production";
12
+ type EndpointMode = 'auto' | 'local' | 'production';
13
13
  interface GranularOptions {
14
14
  /** Your Granular API key (for service/CLI auth; use with GRANULAR_API_KEY) */
15
15
  apiKey?: string;
@@ -86,35 +86,72 @@ interface Subject {
86
86
  updatedAt: number;
87
87
  }
88
88
  /**
89
- * Options for connecting to an ontology environment
89
+ * Options for opening an ontology environment for one delegated subject.
90
+ *
91
+ * This does not open a live runtime session. Use
92
+ * `environment.sessions.create()` or `granular.createSession({ environmentId })`
93
+ * when you need a conversation/session with jobs, prompts, heap, and effects.
90
94
  */
91
- interface ConnectOptions {
92
- /** The ontology name or ID to connect to */
95
+ interface OpenEnvironmentOptions {
96
+ /** The ontology name or ID to open. */
93
97
  ontology: string;
94
- /** Named environment slot such as `dev` or `prod` */
95
- environment: string;
96
- /** Advanced override for the version tag/channel to follow. In the common case, omit this. */
97
- tagName?: string;
98
+ /** Version channel to follow, typically `dev` or `prod`. */
99
+ tag?: string;
98
100
  /**
99
- * External user identifier from your app. This is the primary input for
100
- * connecting to a sandbox and the only required user field in the common case.
101
+ * External user identifier from your app.
102
+ *
103
+ * Exactly one of `userId`, `granularId`, or `user` should be provided.
101
104
  */
102
105
  userId?: string;
103
106
  /**
104
- * Internal Granular user identifier. Optional fallback when you only know
105
- * the Granular-side ID for an existing subject.
107
+ * Internal Granular user identifier.
108
+ *
109
+ * Exactly one of `userId`, `granularId`, or `user` should be provided.
106
110
  */
107
111
  granularId?: string;
108
- /** Optional display name used when upserting the user */
112
+ /** Optional display name used when upserting the user. */
109
113
  name?: string;
110
- /** Optional email used when upserting the user */
114
+ /** Optional email used when upserting the user. */
111
115
  email?: string;
112
- /** Permission profile IDs or names to ensure before connecting */
113
- permissions?: string[];
114
- /** Backwards-compatible user object returned from recordUser() */
116
+ /**
117
+ * Permission profile names or IDs to ensure before opening the environment.
118
+ * This should be provided even for existing users so the SDK can guarantee
119
+ * assignments for first-time environment creation.
120
+ */
121
+ permissions: string[];
122
+ /**
123
+ * When true, if the latest environment for this ontology/user/tag is marked
124
+ * outdated relative to the current tag target, create a fresh environment on
125
+ * the newest tag target instead of reusing the outdated one.
126
+ */
127
+ createFreshIfOutdated?: boolean;
128
+ /** Backwards-compatible user object returned from `recordUser()`. */
115
129
  user?: User;
116
- /** Optional stable client ID. Defaults to `client_${Date.now()}`. Use a fixed
117
- * value for long-lived effect hosts so tool catalogs don't accumulate. */
130
+ }
131
+ /**
132
+ * Deprecated compatibility alias for the legacy `connect()` entry point.
133
+ *
134
+ * `connect()` now resolves an environment handle and no longer opens a runtime
135
+ * session automatically. Prefer `openEnvironment()` for new code.
136
+ */
137
+ interface ConnectOptions extends OpenEnvironmentOptions {
138
+ /** @deprecated Legacy explicit environment slot name. Prefer `tag`. */
139
+ environment?: string;
140
+ /** @deprecated Legacy tag field. Prefer `tag`. */
141
+ tagName?: string;
142
+ /** @deprecated Ignored by `connect()` now that it no longer opens sessions. */
143
+ clientId?: string;
144
+ /** @deprecated Ignored by `connect()` now that it no longer opens sessions. */
145
+ initialHeap?: Array<{
146
+ className: string;
147
+ id: string;
148
+ }>;
149
+ }
150
+ /**
151
+ * Options for creating a live runtime session from an opened environment.
152
+ */
153
+ interface CreateSessionOptions {
154
+ /** Optional stable client ID. Defaults to `client_${Date.now()}`. */
118
155
  clientId?: string;
119
156
  /** Optional session heap seed. Each item is eagerly hydrated into the session heap on connect. */
120
157
  initialHeap?: Array<{
@@ -131,7 +168,7 @@ interface ConversationSessionInfo {
131
168
  environmentId: string;
132
169
  versionId?: string | null;
133
170
  docId: string;
134
- status: "active" | "closed" | "expired";
171
+ status: 'active' | 'closed' | 'expired';
135
172
  createdAt: string;
136
173
  lastSeenAt: string;
137
174
  summary?: string | null;
@@ -239,7 +276,7 @@ interface AssignmentListResponse {
239
276
  * pin themselves to one immutable ontology version.
240
277
  */
241
278
  interface BuildPolicy {
242
- mode: "tag" | "current" | "pinned";
279
+ mode: 'tag' | 'current' | 'pinned';
243
280
  buildId?: string;
244
281
  versionId?: string;
245
282
  tagId?: string;
@@ -250,7 +287,7 @@ interface VersionTag {
250
287
  tagId: string;
251
288
  sandboxId: string;
252
289
  name: string;
253
- kind: "channel" | "release" | "system";
290
+ kind: 'channel' | 'release' | 'system';
254
291
  targetBuildId?: string | null;
255
292
  targetVersionId?: string | null;
256
293
  description?: string | null;
@@ -275,7 +312,7 @@ interface EnvironmentData {
275
312
  tag?: VersionTag | null;
276
313
  tracking?: BuildPolicy;
277
314
  buildPolicy: BuildPolicy;
278
- updateState?: "up_to_date" | "update_available" | "upgrading" | "failed";
315
+ updateState?: 'up_to_date' | 'update_available' | 'upgrading' | 'failed';
279
316
  createdAt: number;
280
317
  updatedAt: number;
281
318
  }
@@ -324,7 +361,7 @@ interface Manifest {
324
361
  interface ManifestListResponse {
325
362
  items: Manifest[];
326
363
  }
327
- type BuildStatus = "queued" | "building" | "completed" | "failed" | "canceled";
364
+ type BuildStatus = 'queued' | 'building' | 'completed' | 'failed' | 'canceled';
328
365
  /**
329
366
  * An immutable ontology version derived from a specific manifest revision.
330
367
  *
@@ -359,8 +396,8 @@ interface BuildListResponse {
359
396
  }
360
397
  interface SemanticVersionDiffEntry {
361
398
  operationId: string;
362
- kind: "create" | "update" | "relationship" | "effect" | "eventStream" | "unknown";
363
- changeType: "added" | "removed" | "changed";
399
+ kind: 'create' | 'update' | 'relationship' | 'effect' | 'eventStream' | 'unknown';
400
+ changeType: 'added' | 'removed' | 'changed';
364
401
  label: string;
365
402
  additive: boolean;
366
403
  breaking: boolean;
@@ -422,7 +459,7 @@ interface ResolvedEffectBehaviors {
422
459
  reverse?: ResolvedEffectReverse;
423
460
  approvalRequired?: ResolvedEffectApprovalRequired;
424
461
  }
425
- type EffectInvocationMode = "execute" | "dryRun" | "reverse";
462
+ type EffectInvocationMode = 'execute' | 'dryRun' | 'reverse';
426
463
  interface EffectInvocationMetadata {
427
464
  mode?: EffectInvocationMode;
428
465
  reverseHandler?: string;
@@ -479,9 +516,9 @@ interface ToolSchema {
479
516
  * ```
480
517
  */
481
518
  outputSchema?: Record<string, unknown>;
482
- stability?: "stable" | "experimental" | "deprecated";
519
+ stability?: 'stable' | 'experimental' | 'deprecated';
483
520
  provenance?: {
484
- source: "mcp" | "custom";
521
+ source: 'mcp' | 'custom';
485
522
  };
486
523
  tags?: string[];
487
524
  /**
@@ -588,8 +625,8 @@ interface EffectsChangedEvent extends ToolsChangedEvent {
588
625
  }
589
626
  type EffectHandler = ToolHandler;
590
627
  type InstanceEffectHandler = InstanceToolHandler;
591
- type JobStatus = "queued" | "running" | "awaitingTool" | "awaitingHuman" | "succeeded" | "failed" | "timeout" | "canceled";
592
- type JobFeedbackSentiment = "good" | "bad";
628
+ type JobStatus = 'queued' | 'running' | 'awaitingTool' | 'awaitingHuman' | 'succeeded' | 'failed' | 'timeout' | 'canceled';
629
+ type JobFeedbackSentiment = 'good' | 'bad';
593
630
  interface JobFeedbackToolCall {
594
631
  callId?: string;
595
632
  toolName?: string;
@@ -601,7 +638,7 @@ interface JobFeedbackToolCall {
601
638
  durationMs?: number | null;
602
639
  }
603
640
  interface JobFeedbackMetadata {
604
- source: "sdk";
641
+ source: 'sdk';
605
642
  status: JobStatus;
606
643
  code: string;
607
644
  domainRevision?: string;
@@ -634,6 +671,18 @@ interface JobFeedbackRecord {
634
671
  createdAt: number;
635
672
  updatedAt: number;
636
673
  }
674
+ /**
675
+ * Persisted feedback row listed at the environment level.
676
+ */
677
+ interface EnvironmentFeedbackRecord {
678
+ feedbackId: string;
679
+ sessionId: string;
680
+ jobId: string;
681
+ sentiment: JobFeedbackSentiment;
682
+ comment?: string | null;
683
+ metadata?: Record<string, unknown> | null;
684
+ createdAt: string | null;
685
+ }
637
686
  /**
638
687
  * Result from submitting a job
639
688
  */
@@ -653,11 +702,11 @@ interface Job {
653
702
  /** Attach user feedback to this job and persist it with job/session metadata */
654
703
  leaveFeedback(input: JobFeedbackInput): Promise<JobFeedbackRecord>;
655
704
  /** Subscribe to job events */
656
- on(event: string, handler: (data: unknown) => void): void;
705
+ on(event: string, handler: (data: unknown) => void): () => void;
657
706
  }
658
707
  interface Prompt {
659
708
  id: string;
660
- type: "confirm" | "choice" | "input";
709
+ type: 'confirm' | 'choice' | 'input';
661
710
  title: string;
662
711
  message: string;
663
712
  options?: Array<string | {
@@ -676,7 +725,7 @@ interface ConversationMessageShowRefs {
676
725
  variableNames?: string[];
677
726
  }
678
727
  interface ConversationMessageInput {
679
- role: "user" | "assistant";
728
+ role: 'user' | 'assistant';
680
729
  content?: string;
681
730
  show?: ConversationMessageShowRefs;
682
731
  jobId?: string;
@@ -692,7 +741,7 @@ interface ConversationAppendResult {
692
741
  }
693
742
  interface SessionTranscriptEntry {
694
743
  id: string;
695
- role: "user" | "assistant";
744
+ role: 'user' | 'assistant';
696
745
  content: string;
697
746
  timestamp: number;
698
747
  jobId?: string;
@@ -703,9 +752,9 @@ interface SessionTranscriptEntry {
703
752
  error?: string;
704
753
  show?: ConversationMessageShowRefs;
705
754
  historyContent?: string;
706
- source: "conversation" | "job_code" | "job_result" | "job_prompt" | "job_agent_message";
755
+ source: 'conversation' | 'job_code' | 'job_result' | 'job_prompt' | 'job_agent_message';
707
756
  }
708
- type SessionHeapFieldType = "string" | "number" | "boolean" | "null" | "unknown";
757
+ type SessionHeapFieldType = 'string' | 'number' | 'boolean' | 'null' | 'unknown';
709
758
  interface SessionHeapFieldValue {
710
759
  name: string;
711
760
  type: SessionHeapFieldType;
@@ -733,7 +782,7 @@ interface SessionHeapList {
733
782
  }
734
783
  interface SessionHeapVariable {
735
784
  name: string;
736
- kind: "entry" | "list" | "scalar";
785
+ kind: 'entry' | 'list' | 'scalar';
737
786
  entryPath?: string;
738
787
  listName?: string;
739
788
  value?: string | number | boolean | null;
@@ -770,13 +819,13 @@ interface WSClientOptions {
770
819
  onReconnectError?: (info: WSReconnectErrorInfo) => void;
771
820
  }
772
821
  interface RPCRequest {
773
- type: "rpc";
822
+ type: 'rpc';
774
823
  method: string;
775
824
  params: unknown;
776
825
  id: string;
777
826
  }
778
827
  interface RPCResponse {
779
- type: "rpc_result" | "rpc_error";
828
+ type: 'rpc_result' | 'rpc_error';
780
829
  id: string;
781
830
  result?: unknown;
782
831
  error?: {
@@ -786,12 +835,12 @@ interface RPCResponse {
786
835
  };
787
836
  }
788
837
  interface SyncMessage {
789
- type: "sync";
838
+ type: 'sync';
790
839
  message?: string | number[] | Uint8Array;
791
840
  data?: number[];
792
841
  }
793
842
  interface RPCRequestFromServer {
794
- type: "rpc";
843
+ type: 'rpc';
795
844
  method: string;
796
845
  params: unknown;
797
846
  id: string;
@@ -835,7 +884,7 @@ interface RelationshipInfo {
835
884
  /** The foreign model type */
836
885
  foreign_model: ModelRef;
837
886
  /** Computed relationship kind: "one_to_one" | "one_to_many" | "many_to_one" | "many_to_many" */
838
- relationship_kind: "one_to_one" | "one_to_many" | "many_to_one" | "many_to_many";
887
+ relationship_kind: 'one_to_one' | 'one_to_many' | 'many_to_one' | 'many_to_many';
839
888
  }
840
889
  /**
841
890
  * Options for defining a relationship between two model types
@@ -934,8 +983,8 @@ interface RecordObjectsOptions {
934
983
  */
935
984
  onChunkComplete?: (info: RecordObjectsChunkInfo) => void | Promise<void>;
936
985
  }
937
- type RecordImportStatus = "queued" | "processing" | "completed" | "failed" | "canceled";
938
- type RecordImportItemStatus = "queued" | "processing" | "completed" | "failed" | "canceled";
986
+ type RecordImportStatus = 'queued' | 'processing' | 'completed' | 'failed' | 'canceled';
987
+ type RecordImportItemStatus = 'queued' | 'processing' | 'completed' | 'failed' | 'canceled';
939
988
  interface RecordImportStats {
940
989
  totalRecords: number;
941
990
  queuedRecords: number;
@@ -1000,14 +1049,10 @@ interface ManifestPropertySpec {
1000
1049
  required?: boolean;
1001
1050
  note?: string | string[];
1002
1051
  enum?: string[] | ManifestEnumRuleSpec;
1003
- searchable?: boolean | {
1004
- enabled?: boolean;
1005
- phonetic?: boolean;
1006
- };
1007
1052
  filterBy?: boolean | string[] | ManifestFilterBySpec;
1008
1053
  validate?: ManifestValidationRuleSpec[];
1009
1054
  }
1010
- type ManifestValidationOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "true" | "false" | "regex" | "contains" | "not_contains" | "starts_with" | "ends_with";
1055
+ type ManifestValidationOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'true' | 'false' | 'regex' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with';
1011
1056
  interface ManifestEnumRuleSpec {
1012
1057
  values: string[];
1013
1058
  message?: string;
@@ -1096,7 +1141,7 @@ interface ManifestEffectDeclaration {
1096
1141
  isStatic?: boolean;
1097
1142
  inputSchema: ManifestEffectSchema;
1098
1143
  outputSchema?: ManifestEffectSchema;
1099
- stability?: "stable" | "experimental" | "deprecated";
1144
+ stability?: 'stable' | 'experimental' | 'deprecated';
1100
1145
  tags?: string[];
1101
1146
  metamodels?: ManifestEffectMetamodelSpec;
1102
1147
  }
@@ -1157,7 +1202,7 @@ interface ManifestImport {
1157
1202
  }
1158
1203
  interface ManifestVolume {
1159
1204
  name: string;
1160
- scope: "sandbox" | "build" | "user";
1205
+ scope: 'sandbox' | 'build' | 'user';
1161
1206
  imports?: ManifestImport[];
1162
1207
  operations: ManifestOperation[];
1163
1208
  }
@@ -1200,7 +1245,7 @@ interface StreamEvent {
1200
1245
  environmentId: string;
1201
1246
  sessionId?: string;
1202
1247
  subjectId?: string;
1203
- source: "sandbox" | "api";
1248
+ source: 'sandbox' | 'api';
1204
1249
  isAcked: boolean;
1205
1250
  createdAt: number;
1206
1251
  }
@@ -1432,7 +1477,7 @@ declare class Session {
1432
1477
  /**
1433
1478
  * Subscribe to session events
1434
1479
  */
1435
- on(event: string, handler: (data: unknown) => void): void;
1480
+ on(event: string, handler: (data: unknown) => void): () => void;
1436
1481
  /**
1437
1482
  * Unsubscribe from session events
1438
1483
  */
@@ -1447,27 +1492,18 @@ declare class Session {
1447
1492
  }
1448
1493
 
1449
1494
  /**
1450
- * Environment represents a connected session to a sandbox for a specific user.
1451
- *
1452
- * After connecting, you can:
1453
- * 1. Define your domain ontology via `applyManifest()` (classes, properties, relationships)
1454
- * 2. Record object instances via `recordObject()` (with fields and relationship attachments)
1455
- * 3. Register sandbox-scoped effects via `granular.registerEffect()` / `granular.registerEffects()`
1456
- * 4. Submit jobs via `submitJob()` that import auto-generated typed classes from `./sandbox-tools`
1457
- * 5. Execute GraphQL queries via `graphql()` (authenticated automatically)
1458
- * 6. List available effects via `getEffects()` and listen for updates via `onEffectsChanged()`
1495
+ * Environment is the sessionless handle for one resolved ontology environment.
1459
1496
  *
1460
- * Tool calls from the sandbox automatically invoke your handlers via reverse-RPC.
1461
- *
1462
- * Object IDs are unique per class. Internally, the graph path is `{className}_{id}`
1463
- * (e.g., `author_tolkien`). Use `Environment.toGraphPath()` and
1464
- * `Environment.extractIdFromGraphPath()` for conversions.
1497
+ * Use it to query or mutate environment data directly, or to open live runtime
1498
+ * sessions through `environment.sessions.*` when you need jobs, prompts, or a
1499
+ * synced Automerge document.
1465
1500
  */
1466
- declare class Environment extends Session {
1501
+ declare class Environment {
1502
+ private granular;
1467
1503
  private envData;
1468
1504
  private _apiKey;
1469
1505
  private _apiEndpoint;
1470
- constructor(client: WSClient, envData: EnvironmentData, clientId: string, apiKey: string, apiEndpoint: string);
1506
+ constructor(granular: Granular, envData: EnvironmentData, apiKey: string, apiEndpoint: string);
1471
1507
  /** The environment ID */
1472
1508
  get environmentId(): string;
1473
1509
  /** The sandbox ID */
@@ -1486,65 +1522,68 @@ declare class Environment extends Session {
1486
1522
  get granularId(): string;
1487
1523
  /** The permission profile ID */
1488
1524
  get permissionProfileId(): string;
1525
+ /** The current build policy backing this environment */
1526
+ get buildPolicy(): BuildPolicy;
1527
+ /** The current update state relative to the followed tag */
1528
+ get updateState(): EnvironmentData["updateState"];
1529
+ /** Convenience flag for whether this environment trails the current tag target */
1530
+ get isOutdated(): boolean;
1531
+ /** The followed tag name when this environment is tag-tracked */
1532
+ get tag(): string | null;
1489
1533
  /** The GraphQL API endpoint URL */
1490
1534
  get apiEndpoint(): string;
1535
+ /** Internal auth token used for control-plane and runtime fallback requests */
1536
+ get authToken(): string;
1537
+ /** Base runtime URL derived from the GraphQL endpoint */
1538
+ get runtimeBaseUrl(): string;
1539
+ get sessions(): {
1540
+ list: (options?: {
1541
+ status?: "active" | "closed" | "all";
1542
+ }) => Promise<ConversationSessionInfo[]>;
1543
+ create: (options?: CreateSessionOptions) => Promise<EnvironmentSession>;
1544
+ connect: (sessionId: string, options?: {
1545
+ clientId?: string;
1546
+ }) => Promise<EnvironmentSession>;
1547
+ reopen: (sessionId: string, options?: {
1548
+ clientId?: string;
1549
+ }) => Promise<EnvironmentSession>;
1550
+ close: (sessionId: string, session?: EnvironmentSession | null) => Promise<void>;
1551
+ };
1552
+ get data(): {
1553
+ record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
1554
+ recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
1555
+ import: (records: RecordObjectOptions[], options?: {
1556
+ batchSize?: number;
1557
+ }) => Promise<RecordImport>;
1558
+ listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
1559
+ getImport: (importId: string) => Promise<RecordImport>;
1560
+ getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
1561
+ cancelImport: (importId: string) => Promise<RecordImport>;
1562
+ getAwaitingCount: () => Promise<number>;
1563
+ };
1564
+ get feedback(): {
1565
+ list: () => Promise<EnvironmentFeedbackRecord[]>;
1566
+ };
1491
1567
  /**
1492
- * Return a plain JS snapshot of the synced session heap.
1493
- *
1494
- * The heap lives in the Automerge document, so this method does not perform
1495
- * any extra network roundtrip.
1568
+ * Sessionless environments do not own a live transport, so disconnecting the
1569
+ * environment handle itself is a no-op. This keeps the public surface
1570
+ * symmetric with `EnvironmentSession.disconnect()` and lets callers always
1571
+ * clean up safely without tracking whether they currently hold an environment
1572
+ * or a session.
1496
1573
  */
1497
- getHeap(): SessionHeapSnapshot;
1574
+ disconnect(): Promise<void>;
1575
+ listSessions(status?: "active" | "closed" | "all"): Promise<ConversationSessionInfo[]>;
1576
+ createSession(options?: CreateSessionOptions): Promise<EnvironmentSession>;
1577
+ connectSession(sessionId: string, options?: {
1578
+ clientId?: string;
1579
+ }): Promise<EnvironmentSession>;
1580
+ reopenSession(sessionId: string, options?: {
1581
+ clientId?: string;
1582
+ }): Promise<EnvironmentSession>;
1583
+ closeSession(sessionId: string, session?: EnvironmentSession | null): Promise<void>;
1584
+ listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
1498
1585
  private getRuntimeBaseUrl;
1499
1586
  private controlPlaneRequest;
1500
- /**
1501
- * Close the session and disconnect from the sandbox.
1502
- *
1503
- * Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
1504
- * to the runtime goodbye endpoint if no definitive WS-side runtime notify
1505
- * acknowledgement was observed.
1506
- */
1507
- disconnect(): Promise<void>;
1508
- /**
1509
- * Close only the socket transport without sending `client.goodbye`.
1510
- *
1511
- * Use this when the caller intends to immediately reattach to the same
1512
- * session after an unexpected disconnect.
1513
- */
1514
- disconnectTransport(): void;
1515
- /** The last known graph container status, updated by checkReadiness() or on heartbeat */
1516
- graphContainerStatus: {
1517
- lastKeepAliveAt: number;
1518
- status: "warming" | "hot" | "unknown";
1519
- } | null;
1520
- /**
1521
- * Check if the graph container is ready and warm.
1522
- *
1523
- * Sends a lightweight heartbeat RPC to the Session DO which internally
1524
- * pings the FalkorDB container. The response includes `graphContainerStatus`,
1525
- * which is stored locally and emitted as a `readiness` event.
1526
- *
1527
- * Use this method to proactively warm the graph container before any
1528
- * GraphQL query that requires it, or to poll the container's state in
1529
- * the background.
1530
- *
1531
- * @returns The current graph container status object
1532
- *
1533
- * @example
1534
- * ```typescript
1535
- * const status = await env.checkReadiness();
1536
- * console.log(status.status); // 'hot' | 'warming' | 'unknown'
1537
- *
1538
- * // Or listen for live updates
1539
- * env.on('readiness', (status) => {
1540
- * console.log('Graph is now:', status.status);
1541
- * });
1542
- * ```
1543
- */
1544
- checkReadiness(): Promise<{
1545
- lastKeepAliveAt: number;
1546
- status: "warming" | "hot" | "unknown";
1547
- }>;
1548
1587
  /**
1549
1588
  * Convert a class name + real-world ID into a unique graph path.
1550
1589
  *
@@ -1822,26 +1861,107 @@ declare class Environment extends Session {
1822
1861
  * Cancel a queued/background record import.
1823
1862
  */
1824
1863
  cancelRecordImport(importId: string): Promise<RecordImport>;
1864
+ }
1865
+ /**
1866
+ * Live runtime session attached to one opened environment.
1867
+ *
1868
+ * This is the object returned by `environment.sessions.create()` and friends.
1869
+ * It owns websocket state, prompts, job execution, and the synced Automerge
1870
+ * document while delegating environment-level data APIs back to
1871
+ * `session.environment`.
1872
+ */
1873
+ declare class EnvironmentSession extends Session {
1874
+ readonly environment: Environment;
1875
+ /** The last known graph container status, updated by checkReadiness() or on heartbeat */
1876
+ graphContainerStatus: {
1877
+ lastKeepAliveAt: number;
1878
+ status: "warming" | "hot" | "unknown";
1879
+ } | null;
1880
+ constructor(client: WSClient, environment: Environment, clientId: string);
1881
+ get environmentId(): string;
1882
+ get sandboxId(): string;
1883
+ get ontologyId(): string;
1884
+ get subjectId(): string;
1885
+ get envName(): string;
1886
+ get versionId(): string;
1887
+ get granularId(): string;
1888
+ get permissionProfileId(): string;
1889
+ get apiEndpoint(): string;
1890
+ get data(): {
1891
+ record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
1892
+ recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
1893
+ import: (records: RecordObjectOptions[], options?: {
1894
+ batchSize?: number;
1895
+ } | undefined) => Promise<RecordImport>;
1896
+ listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
1897
+ getImport: (importId: string) => Promise<RecordImport>;
1898
+ getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
1899
+ cancelImport: (importId: string) => Promise<RecordImport>;
1900
+ getAwaitingCount: () => Promise<number>;
1901
+ };
1902
+ get feedback(): {
1903
+ list: () => Promise<EnvironmentFeedbackRecord[]>;
1904
+ };
1825
1905
  /**
1826
- * Removed: environment-scoped effect publication is no longer supported.
1906
+ * Return a plain JS snapshot of the synced session heap.
1827
1907
  */
1828
- publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
1908
+ getHeap(): SessionHeapSnapshot;
1909
+ graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
1910
+ defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
1911
+ getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
1912
+ attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
1913
+ detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
1914
+ listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
1915
+ applyManifest(manifest: ManifestContent): Promise<{
1916
+ applied: number;
1917
+ errors: string[];
1918
+ }>;
1919
+ recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
1920
+ recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
1921
+ enqueueRecordImport(records: RecordObjectOptions[], options?: {
1922
+ batchSize?: number;
1923
+ }): Promise<RecordImport>;
1924
+ listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
1925
+ getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
1926
+ getAwaitingRecordCount(): Promise<number>;
1927
+ getRecordImport(importId: string): Promise<RecordImport>;
1928
+ cancelRecordImport(importId: string): Promise<RecordImport>;
1929
+ listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
1829
1930
  /**
1830
- * Removed: environment-scoped effect publication is no longer supported.
1931
+ * Close the session and disconnect from the sandbox.
1932
+ *
1933
+ * Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
1934
+ * to the runtime goodbye endpoint if no definitive WS-side runtime notify
1935
+ * acknowledgement was observed.
1831
1936
  */
1832
- publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
1937
+ disconnect(): Promise<void>;
1833
1938
  /**
1834
- * Removed: environment-scoped effect publication is no longer supported.
1939
+ * Close only the socket transport without sending `client.goodbye`.
1835
1940
  */
1836
- publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
1941
+ disconnectTransport(): void;
1837
1942
  /**
1838
- * Removed: environment-scoped effect publication is no longer supported.
1943
+ * Backwards-compatible alias for `disconnect()`.
1839
1944
  */
1840
- unpublishEffect(name: string): Promise<PublishToolsResult>;
1945
+ close(): Promise<void>;
1841
1946
  /**
1842
- * Removed: environment-scoped effect publication is no longer supported.
1947
+ * Check if the graph container is ready and warm.
1843
1948
  */
1844
- unpublishAllEffects(): Promise<PublishToolsResult>;
1949
+ checkReadiness(): Promise<{
1950
+ lastKeepAliveAt: number;
1951
+ status: "warming" | "hot" | "unknown";
1952
+ }>;
1953
+ }
1954
+ declare class OntologyHandle {
1955
+ private granular;
1956
+ private ontologyNameOrId;
1957
+ constructor(granular: Granular, ontologyNameOrId: string);
1958
+ get effects(): {
1959
+ register: (effect: ToolWithHandler) => Promise<void>;
1960
+ registerMany: (effects: ToolWithHandler[]) => Promise<void>;
1961
+ unregister: (name: string) => Promise<void>;
1962
+ clear: () => Promise<void>;
1963
+ disconnect: () => Promise<void>;
1964
+ };
1845
1965
  }
1846
1966
  declare class Granular {
1847
1967
  private apiKey;
@@ -1863,6 +1983,10 @@ declare class Granular {
1863
1983
  * @param options - Client configuration
1864
1984
  */
1865
1985
  constructor(options: GranularOptions);
1986
+ /**
1987
+ * Return an ontology-scoped handle for effects and other ontology-level APIs.
1988
+ */
1989
+ ontology(ontologyNameOrId: string): OntologyHandle;
1866
1990
  /**
1867
1991
  * Records/upserts a user and prepares them for sandbox connections
1868
1992
  *
@@ -1879,43 +2003,46 @@ declare class Granular {
1879
2003
  * ```
1880
2004
  */
1881
2005
  recordUser(options: RecordUserOptions): Promise<User>;
2006
+ /**
2007
+ * Alias for `recordUser()` with user-facing naming that matches upsert semantics.
2008
+ */
2009
+ upsertUser(options: RecordUserOptions): Promise<User>;
1882
2010
  private resolveConnectUser;
1883
2011
  /**
1884
- * Connect to an ontology environment and establish a real-time session.
1885
- *
1886
- * Effects are registered at the sandbox level via `granular.registerEffect()`
1887
- * or `granular.registerEffects()`. Sessions pick up live availability from
1888
- * the sandbox registry automatically.
1889
- *
1890
- * @param options - Connection options
1891
- * @returns An active environment session
2012
+ * Open or resolve an ontology environment for one user without opening a session.
1892
2013
  *
1893
2014
  * @example
1894
2015
  * ```typescript
1895
- * const environment = await granular.connect({
2016
+ * const environment = await granular.openEnvironment({
1896
2017
  * ontology: 'my-ontology',
1897
- * environment: 'dev',
2018
+ * tag: 'dev',
1898
2019
  * userId: 'user_123',
1899
2020
  * permissions: ['agent'],
1900
2021
  * });
1901
2022
  *
1902
- * await granular.registerEffect('my-sandbox', {
1903
- * name: 'greet',
1904
- * description: 'Say hello',
1905
- * inputSchema: { type: 'object', properties: {} },
1906
- * handler: async () => 'Hello!',
2023
+ * await environment.data.record({
2024
+ * className: 'customer',
2025
+ * id: 'acme',
2026
+ * fields: { name: 'Acme' },
1907
2027
  * });
1908
2028
  *
1909
- * // Submit job
1910
- * const job = await environment.submitJob(`
1911
- * import { tools } from './sandbox-tools';
1912
- * return await tools.greet({});
1913
- * `);
1914
- *
1915
- * console.log(await job.result); // 'Hello!'
2029
+ * const session = await environment.sessions.create();
2030
+ * const job = await session.submitJob(`return "hello";`);
2031
+ * console.log(await job.result);
1916
2032
  * ```
1917
2033
  */
2034
+ openEnvironment(options: OpenEnvironmentOptions): Promise<Environment>;
2035
+ /**
2036
+ * Deprecated compatibility alias for `openEnvironment()`.
2037
+ *
2038
+ * `connect()` no longer opens a runtime session automatically.
2039
+ */
1918
2040
  connect(options: ConnectOptions): Promise<Environment>;
2041
+ private resolveRequestedTag;
2042
+ private buildManagedEnvironmentName;
2043
+ private matchesTagTrackedEnvironment;
2044
+ private sortEnvironmentsByRecency;
2045
+ private resolveOpenEnvironmentData;
1919
2046
  /**
1920
2047
  * List active (open) sessions for an environment — each session is one agent conversation thread.
1921
2048
  */
@@ -1938,27 +2065,28 @@ declare class Granular {
1938
2065
  createSession(options: {
1939
2066
  environmentId: string;
1940
2067
  clientId?: string;
1941
- initialHeap?: ConnectOptions["initialHeap"];
1942
- }): Promise<Environment>;
2068
+ initialHeap?: CreateSessionOptions["initialHeap"];
2069
+ }): Promise<EnvironmentSession>;
1943
2070
  /**
1944
2071
  * Connect to an existing open session (same conversation thread) using a freshly minted WebSocket token.
1945
2072
  */
1946
2073
  connectSession(options: {
1947
2074
  sessionId: string;
1948
2075
  clientId?: string;
1949
- }): Promise<Environment>;
2076
+ }): Promise<EnvironmentSession>;
1950
2077
  /**
1951
2078
  * Mark a session closed in the control plane. If `environment` is the connected handle for that
1952
2079
  * `sessionId`, disconnects the WebSocket so the runtime tears down cleanly.
1953
2080
  */
1954
- closeSession(sessionId: string, environment?: Environment | null): Promise<void>;
2081
+ closeSession(sessionId: string, environment?: EnvironmentSession | null): Promise<void>;
1955
2082
  /**
1956
2083
  * Re-open a closed session in the index and connect to its existing runtime document.
1957
2084
  */
1958
2085
  reopenSession(sessionId: string, options?: {
1959
2086
  clientId?: string;
1960
- }): Promise<Environment>;
1961
- private bindWebSocketEnvironment;
2087
+ }): Promise<EnvironmentSession>;
2088
+ private bindEnvironmentHandle;
2089
+ private bindWebSocketEnvironmentSession;
1962
2090
  private activateEnvironment;
1963
2091
  private getSandboxEffectMap;
1964
2092
  private serializeEffect;
@@ -2102,4 +2230,4 @@ declare class Granular {
2102
2230
  private request;
2103
2231
  }
2104
2232
 
2105
- export { type ResolvedEffectApprovalRequired as $, type AccessTokenProvider as A, type BuildPolicy as B, type ConnectOptions as C, type DomainState as D, type EndpointMode as E, type EnvironmentListResponse as F, Granular as G, type Manifest as H, type InstanceToolHandler as I, type ManifestListResponse as J, type BuildStatus as K, type Build as L, type ManifestEffectMetamodelSpec as M, type Version as N, type BuildListResponse as O, type Prompt as P, type SemanticVersionDiffEntry as Q, type ResolvedEffectBehaviors as R, type SessionHeapEntry as S, type ToolWithHandler as T, type User as U, type VersionTracking as V, WSClient as W, type SemanticVersionDiff as X, type ResolvedEffectPostCondition as Y, type ResolvedEffectDryRun as Z, type ResolvedEffectReverse as _, type EffectHandlerContext as a, type ManifestEventStreamDef as a$, type EffectInvocationMode as a0, type EffectInvocationMetadata as a1, type EffectSchema as a2, type EffectWithHandler as a3, type PublishEffectsResult as a4, type ToolInfo as a5, type EffectInfo as a6, type ToolsChangedEvent as a7, type EffectsChangedEvent as a8, type EffectHandler as a9, type DefineRelationshipOptions as aA, type RecordObjectOptions as aB, type RecordObjectResult as aC, type RecordObjectsChunkInfo as aD, type RecordObjectsOptions as aE, type RecordImportStatus as aF, type RecordImportItemStatus as aG, type RecordImportStats as aH, type RecordImportItem as aI, type RecordImport as aJ, type EnvironmentRecordImportSummary as aK, type ManifestPropertySpec as aL, type ManifestValidationOperator as aM, type ManifestEnumRuleSpec as aN, type ManifestFilterBySpec as aO, type ManifestValidationRuleSpec as aP, type ManifestStateMachineStateSpec as aQ, type ManifestStateMachineTransitionSpec as aR, type ManifestStateMachineSpec as aS, type ManifestPostConditionSpec as aT, type ManifestDryRunSpec as aU, type ManifestReverseSpec as aV, type ManifestApprovalRequiredSpec as aW, type ManifestRelationshipDef as aX, type ManifestEffectSchema as aY, type ManifestEffectDeclaration as aZ, type ManifestEventTypeDef as a_, type InstanceEffectHandler as aa, type JobStatus as ab, type JobFeedbackSentiment as ac, type JobFeedbackToolCall as ad, type JobFeedbackMetadata as ae, type JobFeedbackInput as af, type JobFeedbackRecord as ag, type JobSubmitResult as ah, type Job as ai, type ConversationMessageShowRefs as aj, type ConversationMessageInput as ak, type ConversationAppendResult as al, type SessionHeapFieldType as am, type SessionHeapFieldValue as an, type SessionHeapVariable as ao, type WSDisconnectInfo as ap, type WSReconnectErrorInfo as aq, type WSClientOptions as ar, type RPCRequest as as, type RPCResponse as at, type SyncMessage as au, type RPCRequestFromServer as av, type ToolInvokeParams as aw, type ToolResultParams as ax, type ModelRef as ay, type RelationshipInfo as az, type SessionHeapList as b, type ManifestOperation as b0, type ManifestImport as b1, type ManifestVolume as b2, type ManifestContent as b3, type GraphQLResult as b4, type APIError as b5, type DeleteResponse as b6, type StreamEvent as b7, type StreamSubscription as b8, type StreamStats as b9, type SessionHeapSnapshot as c, type SessionTranscriptEntry as d, Environment as e, Session as f, type ToolSchema as g, type PublishToolsResult as h, type ToolHandler as i, type GranularOptions as j, type GranularAuth as k, type RecordUserOptions as l, type Subject as m, type ConversationSessionInfo as n, type Sandbox as o, type CreateSandboxData as p, type SandboxListResponse as q, type PermissionRules as r, type PermissionProfile as s, type CreatePermissionProfileData as t, type PermissionProfileListResponse as u, type Assignment as v, type AssignmentListResponse as w, type VersionTag as x, type EnvironmentData as y, type CreateEnvironmentData as z };
2233
+ export { type SemanticVersionDiff as $, type AccessTokenProvider as A, type BuildPolicy as B, type ConnectOptions as C, type DomainState as D, type EndpointMode as E, type VersionTag as F, Granular as G, type EnvironmentData as H, type InstanceToolHandler as I, type CreateEnvironmentData as J, type EnvironmentListResponse as K, type Manifest as L, type ManifestEffectMetamodelSpec as M, type ManifestListResponse as N, OntologyHandle as O, type Prompt as P, type BuildStatus as Q, type ResolvedEffectBehaviors as R, type SessionHeapEntry as S, type ToolWithHandler as T, type User as U, type VersionTracking as V, WSClient as W, type Build as X, type Version as Y, type BuildListResponse as Z, type SemanticVersionDiffEntry as _, type EffectHandlerContext as a, type ManifestApprovalRequiredSpec as a$, type ResolvedEffectPostCondition as a0, type ResolvedEffectDryRun as a1, type ResolvedEffectReverse as a2, type ResolvedEffectApprovalRequired as a3, type EffectInvocationMode as a4, type EffectInvocationMetadata as a5, type EffectSchema as a6, type EffectWithHandler as a7, type PublishEffectsResult as a8, type ToolInfo as a9, type RPCRequestFromServer as aA, type ToolInvokeParams as aB, type ToolResultParams as aC, type ModelRef as aD, type RelationshipInfo as aE, type DefineRelationshipOptions as aF, type RecordObjectOptions as aG, type RecordObjectResult as aH, type RecordObjectsChunkInfo as aI, type RecordObjectsOptions as aJ, type RecordImportStatus as aK, type RecordImportItemStatus as aL, type RecordImportStats as aM, type RecordImportItem as aN, type RecordImport as aO, type EnvironmentRecordImportSummary as aP, type ManifestPropertySpec as aQ, type ManifestValidationOperator as aR, type ManifestEnumRuleSpec as aS, type ManifestFilterBySpec as aT, type ManifestValidationRuleSpec as aU, type ManifestStateMachineStateSpec as aV, type ManifestStateMachineTransitionSpec as aW, type ManifestStateMachineSpec as aX, type ManifestPostConditionSpec as aY, type ManifestDryRunSpec as aZ, type ManifestReverseSpec as a_, type EffectInfo as aa, type ToolsChangedEvent as ab, type EffectsChangedEvent as ac, type EffectHandler as ad, type InstanceEffectHandler as ae, type JobStatus as af, type JobFeedbackSentiment as ag, type JobFeedbackToolCall as ah, type JobFeedbackMetadata as ai, type JobFeedbackInput as aj, type JobFeedbackRecord as ak, type EnvironmentFeedbackRecord as al, type JobSubmitResult as am, type Job as an, type ConversationMessageShowRefs as ao, type ConversationMessageInput as ap, type ConversationAppendResult as aq, type SessionHeapFieldType as ar, type SessionHeapFieldValue as as, type SessionHeapVariable as at, type WSDisconnectInfo as au, type WSReconnectErrorInfo as av, type WSClientOptions as aw, type RPCRequest as ax, type RPCResponse as ay, type SyncMessage as az, type SessionHeapList as b, type ManifestRelationshipDef as b0, type ManifestEffectSchema as b1, type ManifestEffectDeclaration as b2, type ManifestEventTypeDef as b3, type ManifestEventStreamDef as b4, type ManifestOperation as b5, type ManifestImport as b6, type ManifestVolume as b7, type ManifestContent as b8, type GraphQLResult as b9, type APIError as ba, type DeleteResponse as bb, type StreamEvent as bc, type StreamSubscription as bd, type StreamStats as be, type SessionHeapSnapshot as c, type SessionTranscriptEntry as d, Environment as e, EnvironmentSession as f, Session as g, type ToolSchema as h, type PublishToolsResult as i, type ToolHandler as j, type GranularOptions as k, type GranularAuth as l, type RecordUserOptions as m, type Subject as n, type OpenEnvironmentOptions as o, type CreateSessionOptions as p, type ConversationSessionInfo as q, type Sandbox as r, type CreateSandboxData as s, type SandboxListResponse as t, type PermissionRules as u, type PermissionProfile as v, type CreatePermissionProfileData as w, type PermissionProfileListResponse as x, type Assignment as y, type AssignmentListResponse as z };