@granular-software/sdk 0.4.34 → 0.4.36

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as EndpointMode, T as ToolWithHandler, a as EffectHandlerContext, M as ManifestEffectMetamodelSpec, R as ResolvedEffectBehaviors, S as SessionHeapEntry, b as SessionHeapList, c as SessionHeapSnapshot, P as Prompt, d as SessionTranscriptEntry } from './client-iw76FL_8.js';
2
- export { bi as APIError, A as AccessTokenProvider, y as Assignment, z as AssignmentListResponse, X as Build, Z as BuildListResponse, B as BuildPolicy, Q as BuildStatus, C as ConnectOptions, ar as ConversationAppendResult, aq as ConversationMessageInput, ap as ConversationMessageShowRefs, q as ConversationSessionInfo, J as CreateEnvironmentData, w as CreatePermissionProfileData, s as CreateSandboxData, p as CreateSessionOptions, aN as DefineRelationshipOptions, bj as DeleteResponse, D as DomainState, ae as EffectHandler, ab as EffectInfo, a5 as EffectInvocationMetadata, a4 as EffectInvocationMode, a6 as EffectSchema, a9 as EffectVersionSelector, a7 as EffectWithHandler, ad as EffectsChangedEvent, e as Environment, H as EnvironmentData, am as EnvironmentFeedbackRecord, K as EnvironmentListResponse, aX as EnvironmentRecordImportSummary, f as EnvironmentSession, G as Granular, l as GranularAuth, k as GranularOptions, bh as GraphQLResult, af as InstanceEffectHandler, I as InstanceToolHandler, ao as Job, ak as JobFeedbackInput, aj as JobFeedbackMetadata, al as JobFeedbackRecord, ah as JobFeedbackSentiment, ai as JobFeedbackToolCall, ag as JobStatus, an as JobSubmitResult, L as Manifest, b7 as ManifestApprovalRequiredSpec, bg as ManifestContent, b5 as ManifestDryRunSpec, ba as ManifestEffectDeclaration, b9 as ManifestEffectSchema, a_ as ManifestEnumRuleSpec, bc as ManifestEventStreamDef, bb as ManifestEventTypeDef, a$ as ManifestFilterBySpec, be as ManifestImport, N as ManifestListResponse, bd as ManifestOperation, b4 as ManifestPostConditionSpec, aY as ManifestPropertySpec, b8 as ManifestRelationshipDef, b6 as ManifestReverseSpec, b3 as ManifestStateMachineSpec, b1 as ManifestStateMachineStateSpec, b2 as ManifestStateMachineTransitionSpec, aZ as ManifestValidationOperator, b0 as ManifestValidationRuleSpec, bf as ManifestVolume, aL as ModelRef, O as OntologyHandle, o as OpenEnvironmentOptions, v as PermissionProfile, x as PermissionProfileListResponse, u as PermissionRules, a8 as PublishEffectsResult, i as PublishToolsResult, aF as RPCRequest, aI as RPCRequestFromServer, aG as RPCResponse, aW as RecordImport, aV as RecordImportItem, aT as RecordImportItemStatus, aU as RecordImportStats, aS as RecordImportStatus, aO as RecordObjectOptions, aP as RecordObjectResult, aQ as RecordObjectsChunkInfo, aR as RecordObjectsOptions, m as RecordUserOptions, aM as RelationshipInfo, a3 as ResolvedEffectApprovalRequired, a1 as ResolvedEffectDryRun, a0 as ResolvedEffectPostCondition, a2 as ResolvedEffectReverse, r as Sandbox, t as SandboxListResponse, $ as SemanticVersionDiff, _ as SemanticVersionDiffEntry, g as Session, az as SessionCollectionListOptions, aB as SessionCollectionListResult, as as SessionConversationMessage, ay as SessionDocumentResult, av as SessionHeapFieldType, aw as SessionHeapFieldValue, ax as SessionHeapVariable, aA as SessionJobListOptions, au as SessionJobRecord, at as SessionTimelineEvent, bk as StreamEvent, bm as StreamStats, bl as StreamSubscription, n as Subject, aH as SyncMessage, j as ToolHandler, aa as ToolInfo, aJ as ToolInvokeParams, aK as ToolResultParams, h as ToolSchema, ac as ToolsChangedEvent, U as User, Y as Version, F as VersionTag, V as VersionTracking, W as WSClient, aE as WSClientOptions, aC as WSDisconnectInfo, aD as WSReconnectErrorInfo } from './client-iw76FL_8.js';
1
+ import { E as EndpointMode, T as ToolWithHandler, a as EffectHandlerContext, M as ManifestEffectMetamodelSpec, R as ResolvedEffectBehaviors, S as SessionHeapEntry, b as SessionHeapList, c as SessionHeapSnapshot, P as Prompt, d as SessionTranscriptEntry } from './client-Cq8onk2D.js';
2
+ export { bn as APIError, A as AccessTokenProvider, y as Assignment, z as AssignmentListResponse, X as Build, Z as BuildListResponse, B as BuildPolicy, Q as BuildStatus, C as ConnectOptions, ar as ConversationAppendResult, aq as ConversationMessageInput, ap as ConversationMessageShowRefs, q as ConversationSessionInfo, J as CreateEnvironmentData, w as CreatePermissionProfileData, s as CreateSandboxData, p as CreateSessionOptions, aN as DefineRelationshipOptions, bo as DeleteResponse, D as DomainState, ae as EffectHandler, ab as EffectInfo, a5 as EffectInvocationMetadata, a4 as EffectInvocationMode, a6 as EffectSchema, a9 as EffectVersionSelector, a7 as EffectWithHandler, ad as EffectsChangedEvent, e as Environment, H as EnvironmentData, am as EnvironmentFeedbackRecord, b0 as EnvironmentImporter, a$ as EnvironmentImporterImportOptions, K as EnvironmentListResponse, aX as EnvironmentRecordImportSummary, f as EnvironmentSession, aZ as EnvironmentSetupLifecycleStatus, a_ as EnvironmentSetupSummary, aY as EnvironmentSetupTriggerReason, G as Granular, l as GranularAuth, k as GranularOptions, bm as GraphQLResult, af as InstanceEffectHandler, I as InstanceToolHandler, ao as Job, ak as JobFeedbackInput, aj as JobFeedbackMetadata, al as JobFeedbackRecord, ah as JobFeedbackSentiment, ai as JobFeedbackToolCall, ag as JobStatus, an as JobSubmitResult, L as Manifest, bc as ManifestApprovalRequiredSpec, bl as ManifestContent, ba as ManifestDryRunSpec, bf as ManifestEffectDeclaration, be as ManifestEffectSchema, b3 as ManifestEnumRuleSpec, bh as ManifestEventStreamDef, bg as ManifestEventTypeDef, b4 as ManifestFilterBySpec, bj as ManifestImport, N as ManifestListResponse, bi as ManifestOperation, b9 as ManifestPostConditionSpec, b1 as ManifestPropertySpec, bd as ManifestRelationshipDef, bb as ManifestReverseSpec, b8 as ManifestStateMachineSpec, b6 as ManifestStateMachineStateSpec, b7 as ManifestStateMachineTransitionSpec, b2 as ManifestValidationOperator, b5 as ManifestValidationRuleSpec, bk as ManifestVolume, aL as ModelRef, O as OntologyHandle, o as OpenEnvironmentOptions, v as PermissionProfile, x as PermissionProfileListResponse, u as PermissionRules, a8 as PublishEffectsResult, i as PublishToolsResult, aF as RPCRequest, aI as RPCRequestFromServer, aG as RPCResponse, aW as RecordImport, aV as RecordImportItem, aT as RecordImportItemStatus, aU as RecordImportStats, aS as RecordImportStatus, aO as RecordObjectOptions, aP as RecordObjectResult, aQ as RecordObjectsChunkInfo, aR as RecordObjectsOptions, m as RecordUserOptions, aM as RelationshipInfo, a3 as ResolvedEffectApprovalRequired, a1 as ResolvedEffectDryRun, a0 as ResolvedEffectPostCondition, a2 as ResolvedEffectReverse, r as Sandbox, t as SandboxListResponse, $ as SemanticVersionDiff, _ as SemanticVersionDiffEntry, g as Session, az as SessionCollectionListOptions, aB as SessionCollectionListResult, as as SessionConversationMessage, ay as SessionDocumentResult, av as SessionHeapFieldType, aw as SessionHeapFieldValue, ax as SessionHeapVariable, aA as SessionJobListOptions, au as SessionJobRecord, at as SessionTimelineEvent, bp as StreamEvent, br as StreamStats, bq as StreamSubscription, n as Subject, aH as SyncMessage, j as ToolHandler, aa as ToolInfo, aJ as ToolInvokeParams, aK as ToolResultParams, h as ToolSchema, ac as ToolsChangedEvent, U as User, Y as Version, F as VersionTag, V as VersionTracking, W as WSClient, aE as WSClientOptions, aC as WSDisconnectInfo, aD as WSReconnectErrorInfo } from './client-Cq8onk2D.js';
3
3
  export { BuildGranularAgentSystemPromptInput, GeneratedJobCodeIssue, GranularAgentExecutionCheckpoint, GranularAgentHeapSummaryOptions, GranularAgentReferentFocus, GranularAgentSessionContext, GranularAgentToolInfo, GranularAgentWorkflowFocus, HarnessContinuationDecision, HarnessControllerBudgets, HarnessProjectionOptions, HarnessPromptLike, HarnessVerifierSnapshot, HarnessVerifierSnapshotInput, buildContinuationInstruction, buildGranularAgentCheckpointBlock, buildGranularAgentDomainBlock, buildGranularAgentHeapBlock, buildGranularAgentLoopBlock, buildGranularAgentReferentBlock, buildGranularAgentSessionBlock, buildGranularAgentSystemPrompt, buildGranularAgentToolBlock, buildGranularAgentWorkflowBlock, createHarnessVerifierSnapshot, evaluateContinuation, getCurrentClosureId, getExclusivePromptTarget, hasOpenPrompt, projectConversationReferentFocus, projectConversationReferentSummary, projectHeapSummary, projectLoopSummary, projectWorkflowFocus, projectWorkflowSummary, reviewGeneratedJobCode } from './agent-harness.js';
4
4
  import '@automerge/automerge';
5
5
  import '@automerge/automerge/slim';
package/dist/index.js CHANGED
@@ -12372,6 +12372,38 @@ function normalizeUser(user) {
12372
12372
  permissions: Array.isArray(user.permissions) ? user.permissions : []
12373
12373
  };
12374
12374
  }
12375
+ function normalizeEnvironmentSetupSummary(setup) {
12376
+ if (!setup) {
12377
+ return null;
12378
+ }
12379
+ const queuedRecords = Number(setup.queuedRecords || 0);
12380
+ const processingRecords = Number(setup.processingRecords || 0);
12381
+ return {
12382
+ ...setup,
12383
+ setupRunId: String(setup.setupRunId || ""),
12384
+ environmentId: String(setup.environmentId || ""),
12385
+ sandboxId: String(setup.sandboxId || ""),
12386
+ subjectId: String(setup.subjectId || ""),
12387
+ triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : "new_environment",
12388
+ lifecycleStatus: setup.lifecycleStatus === "completed" || setup.lifecycleStatus === "failed" ? setup.lifecycleStatus : "running",
12389
+ stage: typeof setup.stage === "string" ? setup.stage : null,
12390
+ totalObjectsToImport: Number(setup.totalObjectsToImport || 0),
12391
+ totalImports: Number(setup.totalImports || 0),
12392
+ activeImports: Number(setup.activeImports || 0),
12393
+ totalRecords: Number(setup.totalRecords || 0),
12394
+ queuedRecords,
12395
+ processingRecords,
12396
+ completedRecords: Number(setup.completedRecords || 0),
12397
+ failedRecords: Number(setup.failedRecords || 0),
12398
+ canceledRecords: Number(setup.canceledRecords || 0),
12399
+ awaitingRecords: Number(setup.awaitingRecords || 0) || queuedRecords + processingRecords,
12400
+ errorMessage: typeof setup.errorMessage === "string" ? setup.errorMessage : null,
12401
+ startedAt: Number(setup.startedAt || Date.now()),
12402
+ hookCompletedAt: setup.hookCompletedAt == null ? null : Number(setup.hookCompletedAt),
12403
+ finishedAt: setup.finishedAt == null ? null : Number(setup.finishedAt),
12404
+ updatedAt: Number(setup.updatedAt || Date.now())
12405
+ };
12406
+ }
12375
12407
  function normalizeEnvironmentData(environment) {
12376
12408
  const buildPolicy = environment.buildPolicy || environment.tracking || (environment.tagId ? { mode: "tag", tagId: environment.tagId } : {
12377
12409
  mode: "pinned",
@@ -12385,7 +12417,8 @@ function normalizeEnvironmentData(environment) {
12385
12417
  envName: environmentName,
12386
12418
  environment: environmentName,
12387
12419
  buildPolicy,
12388
- tracking: environment.tracking || buildPolicy
12420
+ tracking: environment.tracking || buildPolicy,
12421
+ setup: normalizeEnvironmentSetupSummary(environment.setup)
12389
12422
  };
12390
12423
  }
12391
12424
  var Environment = class {
@@ -12443,6 +12476,10 @@ var Environment = class {
12443
12476
  get updateState() {
12444
12477
  return this.envData.updateState;
12445
12478
  }
12479
+ /** The latest setup/import run summary for this environment, when available. */
12480
+ get setup() {
12481
+ return this.envData.setup || null;
12482
+ }
12446
12483
  /** Convenience flag for whether this environment trails the current tag target */
12447
12484
  get isOutdated() {
12448
12485
  return this.envData.updateState === "update_available";
@@ -12463,6 +12500,9 @@ var Environment = class {
12463
12500
  get runtimeBaseUrl() {
12464
12501
  return this.getRuntimeBaseUrl();
12465
12502
  }
12503
+ syncEnvironmentData(envData) {
12504
+ this.envData = normalizeEnvironmentData(envData);
12505
+ }
12466
12506
  get sessions() {
12467
12507
  return {
12468
12508
  list: async (options) => this.listSessions(options?.status || "active"),
@@ -13408,7 +13448,8 @@ var Environment = class {
13408
13448
  method: "POST",
13409
13449
  body: JSON.stringify({
13410
13450
  records,
13411
- batchSize: options.batchSize
13451
+ batchSize: options.batchSize,
13452
+ setupRunId: options.setupRunId
13412
13453
  })
13413
13454
  }
13414
13455
  );
@@ -13556,18 +13597,12 @@ var EnvironmentSession = class extends Session {
13556
13597
  }
13557
13598
  get messages() {
13558
13599
  return {
13559
- list: (options = {}) => this.sessionDataRequest(
13560
- "/messages",
13561
- options
13562
- )
13600
+ list: (options = {}) => this.sessionDataRequest("/messages", options)
13563
13601
  };
13564
13602
  }
13565
13603
  get timeline() {
13566
13604
  return {
13567
- list: (options = {}) => this.sessionDataRequest(
13568
- "/timeline",
13569
- options
13570
- )
13605
+ list: (options = {}) => this.sessionDataRequest("/timeline", options)
13571
13606
  };
13572
13607
  }
13573
13608
  get jobs() {
@@ -13584,10 +13619,7 @@ var EnvironmentSession = class extends Session {
13584
13619
  get heap() {
13585
13620
  return {
13586
13621
  entries: {
13587
- list: (options = {}) => this.sessionDataRequest(
13588
- "/heap/entries",
13589
- options
13590
- ),
13622
+ list: (options = {}) => this.sessionDataRequest("/heap/entries", options),
13591
13623
  get: (path) => this.sessionDataRequest(
13592
13624
  `/heap/entries/${encodeURIComponent(path)}`
13593
13625
  )
@@ -13631,10 +13663,7 @@ var EnvironmentSession = class extends Session {
13631
13663
  const heap = normalizeHeapSnapshot({
13632
13664
  entriesByPath: Object.fromEntries(
13633
13665
  entries.map((entry) => {
13634
- return entry?.path ? [
13635
- entry.path,
13636
- entry
13637
- ] : null;
13666
+ return entry?.path ? [entry.path, entry] : null;
13638
13667
  }).filter(
13639
13668
  (entry) => Boolean(entry)
13640
13669
  )
@@ -13800,6 +13829,15 @@ var OntologyHandle = class {
13800
13829
  disconnect: async () => this.granular.disconnectEffects(this.ontologyNameOrId)
13801
13830
  };
13802
13831
  }
13832
+ get importer() {
13833
+ return {
13834
+ onEnvironmentCreate: (handler) => this.granular.registerEnvironmentImporter(
13835
+ this.ontologyNameOrId,
13836
+ handler
13837
+ ),
13838
+ clear: () => this.granular.clearEnvironmentImporter(this.ontologyNameOrId)
13839
+ };
13840
+ }
13803
13841
  };
13804
13842
  var Granular = class _Granular {
13805
13843
  apiKey;
@@ -13816,6 +13854,10 @@ var Granular = class _Granular {
13816
13854
  sandboxEffectHosts = /* @__PURE__ */ new Map();
13817
13855
  /** In-flight host connection promises to avoid duplicate concurrent connects */
13818
13856
  sandboxEffectHostPromises = /* @__PURE__ */ new Map();
13857
+ /** Ontology-bound environment importer hooks keyed by the caller's ontology identifier. */
13858
+ ontologyImporters = /* @__PURE__ */ new Map();
13859
+ /** Resolved importer hooks keyed by sandboxId for fast lookups during openEnvironment(). */
13860
+ sandboxImporters = /* @__PURE__ */ new Map();
13819
13861
  /**
13820
13862
  * Create a new Granular client
13821
13863
  * @param options - Client configuration
@@ -13841,6 +13883,32 @@ var Granular = class _Granular {
13841
13883
  ontology(ontologyNameOrId) {
13842
13884
  return new OntologyHandle(this, ontologyNameOrId);
13843
13885
  }
13886
+ registerEnvironmentImporter(ontologyNameOrId, handler) {
13887
+ this.ontologyImporters.set(ontologyNameOrId, handler);
13888
+ if (ontologyNameOrId.startsWith("sbx_")) {
13889
+ this.sandboxImporters.set(ontologyNameOrId, {
13890
+ handler,
13891
+ sourceOntology: ontologyNameOrId
13892
+ });
13893
+ return;
13894
+ }
13895
+ for (const [sandboxId, importer] of this.sandboxImporters.entries()) {
13896
+ if (importer.sourceOntology === ontologyNameOrId) {
13897
+ this.sandboxImporters.set(sandboxId, {
13898
+ handler,
13899
+ sourceOntology: ontologyNameOrId
13900
+ });
13901
+ }
13902
+ }
13903
+ }
13904
+ clearEnvironmentImporter(ontologyNameOrId) {
13905
+ this.ontologyImporters.delete(ontologyNameOrId);
13906
+ for (const [sandboxId, importer] of this.sandboxImporters.entries()) {
13907
+ if (importer.sourceOntology === ontologyNameOrId) {
13908
+ this.sandboxImporters.delete(sandboxId);
13909
+ }
13910
+ }
13911
+ }
13844
13912
  /**
13845
13913
  * Records/upserts a user and prepares them for sandbox connections
13846
13914
  *
@@ -13957,11 +14025,13 @@ var Granular = class _Granular {
13957
14025
  * ```
13958
14026
  */
13959
14027
  async openEnvironment(options) {
13960
- const envData = await this.resolveOpenEnvironmentData(
14028
+ const resolved = await this.resolveOpenEnvironmentData(
13961
14029
  options,
13962
14030
  "openEnvironment"
13963
14031
  );
13964
- return this.bindEnvironmentHandle(envData);
14032
+ const environment = this.bindEnvironmentHandle(resolved.environment);
14033
+ await this.maybeRunEnvironmentImporter(resolved, environment);
14034
+ return environment;
13965
14035
  }
13966
14036
  /**
13967
14037
  * Deprecated compatibility alias for `openEnvironment()`.
@@ -14048,7 +14118,12 @@ var Granular = class _Granular {
14048
14118
  )
14049
14119
  );
14050
14120
  if (currentMatches.length > 0) {
14051
- return currentMatches[0];
14121
+ return {
14122
+ environment: currentMatches[0],
14123
+ requestedOntology: ontology,
14124
+ sandboxId: sandbox.sandboxId,
14125
+ subjectId: user.granularId
14126
+ };
14052
14127
  }
14053
14128
  const outdatedMatches = this.sortEnvironmentsByRecency(
14054
14129
  userEnvironments.filter(
@@ -14056,14 +14131,25 @@ var Granular = class _Granular {
14056
14131
  )
14057
14132
  );
14058
14133
  if (outdatedMatches.length > 0 && options.createFreshIfOutdated !== true) {
14059
- return outdatedMatches[0];
14134
+ return {
14135
+ environment: outdatedMatches[0],
14136
+ requestedOntology: ontology,
14137
+ sandboxId: sandbox.sandboxId,
14138
+ subjectId: user.granularId
14139
+ };
14060
14140
  }
14061
- return this.environments.create(sandbox.sandboxId, {
14141
+ return {
14142
+ environment: await this.environments.create(sandbox.sandboxId, {
14143
+ subjectId: user.granularId,
14144
+ environment: this.buildManagedEnvironmentName(tagName, targetVersionId),
14145
+ tagId: tag.tagId,
14146
+ permissionProfileId: null
14147
+ }),
14148
+ requestedOntology: ontology,
14149
+ sandboxId: sandbox.sandboxId,
14062
14150
  subjectId: user.granularId,
14063
- environment: this.buildManagedEnvironmentName(tagName, targetVersionId),
14064
- tagId: tag.tagId,
14065
- permissionProfileId: null
14066
- });
14151
+ setupTriggerReason: outdatedMatches.length > 0 ? "fresh_after_version_update" : "new_environment"
14152
+ };
14067
14153
  }
14068
14154
  /**
14069
14155
  * List active (open) sessions for an environment — each session is one agent conversation thread.
@@ -14180,6 +14266,94 @@ var Granular = class _Granular {
14180
14266
  });
14181
14267
  return this.connectSession({ sessionId, clientId: options?.clientId });
14182
14268
  }
14269
+ resolveEnvironmentImporter(requestedOntology, sandboxId) {
14270
+ const sandboxImporter = this.sandboxImporters.get(sandboxId);
14271
+ if (sandboxImporter) {
14272
+ const sourceImporter = this.ontologyImporters.get(
14273
+ sandboxImporter.sourceOntology
14274
+ );
14275
+ if (sourceImporter === sandboxImporter.handler) {
14276
+ return sandboxImporter.handler;
14277
+ }
14278
+ this.sandboxImporters.delete(sandboxId);
14279
+ }
14280
+ const ontologyImporter = this.ontologyImporters.get(requestedOntology);
14281
+ if (!ontologyImporter) {
14282
+ return void 0;
14283
+ }
14284
+ this.sandboxImporters.set(sandboxId, {
14285
+ handler: ontologyImporter,
14286
+ sourceOntology: requestedOntology
14287
+ });
14288
+ return ontologyImporter;
14289
+ }
14290
+ async maybeRunEnvironmentImporter(resolved, environment) {
14291
+ if (!resolved.setupTriggerReason) {
14292
+ return;
14293
+ }
14294
+ const importer = this.resolveEnvironmentImporter(
14295
+ resolved.requestedOntology,
14296
+ resolved.sandboxId
14297
+ );
14298
+ if (!importer) {
14299
+ return;
14300
+ }
14301
+ const setupRun = await this.request(
14302
+ `/control/environments/${environment.environmentId}/setup-runs`,
14303
+ {
14304
+ method: "POST",
14305
+ body: JSON.stringify({
14306
+ triggerReason: resolved.setupTriggerReason
14307
+ })
14308
+ }
14309
+ );
14310
+ const setupRunId = setupRun.setupRunId;
14311
+ const updateSetupRun = async (patch) => {
14312
+ await this.request(
14313
+ `/control/environment-setup-runs/${setupRunId}`,
14314
+ {
14315
+ method: "PATCH",
14316
+ body: JSON.stringify(patch)
14317
+ }
14318
+ );
14319
+ };
14320
+ const importerContext = {
14321
+ environmentId: environment.environmentId,
14322
+ sandboxId: environment.sandboxId,
14323
+ subjectId: environment.subjectId,
14324
+ reason: resolved.setupTriggerReason,
14325
+ incrementTotalObjectsToImportCount: async (n) => {
14326
+ const safeIncrement = Math.max(0, Math.trunc(n));
14327
+ if (safeIncrement <= 0) {
14328
+ return;
14329
+ }
14330
+ await updateSetupRun({
14331
+ incrementTotalObjectsToImportCount: safeIncrement
14332
+ });
14333
+ },
14334
+ setStage: async (stage) => {
14335
+ await updateSetupRun({ stage });
14336
+ },
14337
+ importRecords: async (records, options) => environment.enqueueRecordImport(records, {
14338
+ batchSize: options?.batchSize,
14339
+ setupRunId
14340
+ })
14341
+ };
14342
+ try {
14343
+ await importer(importerContext);
14344
+ await updateSetupRun({ markHookCompleted: true });
14345
+ const refreshedEnvironment = await this.environments.get(
14346
+ environment.environmentId
14347
+ );
14348
+ environment.syncEnvironmentData(refreshedEnvironment);
14349
+ } catch (error) {
14350
+ await updateSetupRun({
14351
+ status: "failed",
14352
+ errorMessage: error instanceof Error ? error.message : String(error)
14353
+ }).catch(() => void 0);
14354
+ throw error;
14355
+ }
14356
+ }
14183
14357
  bindEnvironmentHandle(envData) {
14184
14358
  const graphqlEndpoint = `${this.httpUrl}/orchestrator/graphql`;
14185
14359
  return new Environment(this, envData, this.apiKey, graphqlEndpoint);
@@ -15821,12 +15995,11 @@ function buildContinuationInstruction(resultPreview) {
15821
15995
  "Continue the same user request using the latest structured session state.",
15822
15996
  "Take only the minimum next step that directly helps the user.",
15823
15997
  "Use the active tasks, decisions, prompts, and heap references as the source of truth instead of replaying old work.",
15824
- "If the user names a concrete record that is not already in the heap, fetch it from the graph instead of replying that it is not in context.",
15998
+ "If the user names a concrete record that is not already in the heap, resolve it from the graph before saying it is missing: try a broad search, then a small set of normalized/fuzzy variants or a paged scan when the domain supports it.",
15999
+ "If the request needs all matching records, use iterate(...) or page until hasMore is false. A single list(...) or page(...) call is only one page.",
15825
16000
  "If this request clearly spans multiple steps and there are no active tasks yet, create 2-4 short user-visible tasks now.",
15826
16001
  "Reuse any existing taskId and decisionId values exactly as they appear in AGENT LOOP STATE.",
15827
- "Use ask_user with type input for open-ended preferences or missing text. Use type choice only for a short explicit shortlist.",
15828
- "Do not ask for confirmation in plain text. Use loop.confirm(...) when approval is needed.",
15829
- "Await loop.ask_user(...) and loop.confirm(...). Those helpers pause the current job and resume it after the user answers.",
16002
+ "When progress depends on the user's choice, missing detail, or approval, use loop.ask_user(...) or loop.confirm(...) so the job pauses and resumes through the live workflow.",
15830
16003
  "After a resumed ask_user or confirm call, continue the same job and perform the newly authorized action when the answer is sufficient. Do not stop with placeholder text like 'I'm ready to do it next.'",
15831
16004
  "If you ask the user a new question in this job, do not also close the loop in the same job.",
15832
16005
  "Write the smallest straightforward code for the current step. Avoid defensive fallback branches for hypothetical states that are not currently true.",
@@ -16014,12 +16187,13 @@ ${loopBlock}
16014
16187
  - Continue from the latest structured state. Treat WORKFLOW SNAPSHOT, EXECUTION CHECKPOINT, RECENT REFERENTS, SESSION HEAP, and AGENT LOOP STATE as the working memory for this request.
16015
16188
  - Use CAPABILITY SNAPSHOT to choose the next step, then use DOMAIN REFERENCE for exact signatures and query shapes.
16016
16189
  - Take the minimum next step that directly helps the user. Avoid duplicate work, speculative cleanup, or extra fetching that is not needed yet.
16017
- - If the user names a record that is not already in the heap, fetch it from the graph instead of saying it is not in context.
16018
- - Treat user-provided names as human references, not exact keys. If one strong partial match exists, use it. If several plausible matches exist, ask the user to choose.
16019
16190
  - Use RECENT REFERENTS to resolve follow-up references across turns, such as "that invoice", "that customer", "those products", or "the other one".
16191
+ - Treat user-provided names, numbers, and labels as human references, not exact keys. Resolve them with code: check recent referents/heap first, then query the graph with the broadest supported \`search\` or \`filter\`, then retry with a few normalized/fuzzy/prefix variants when the first pass is empty or ambiguous. Only say a record does not exist after a reasonable lookup across the relevant class.
16192
+ - If one strong match exists, use it. If several plausible matches remain, use \`loop.ask_user({ type: 'choice', ... })\` with the grounded candidates instead of guessing.
16020
16193
  - If the request has more than one reasonable interpretation, ask the user to clarify instead of guessing.
16021
16194
  - For comparisons, rankings, selections, or summaries, first identify the rule you are using. If that rule is not clear from the user request and DOMAIN REFERENCE, ask the user before choosing anything.
16022
16195
  - When the ranking, comparison, or selection rule is unclear, the minimum next step is the clarification itself. Do not run a placeholder query for a provisional winner before asking.
16196
+ - If a user request matches both a domain type/effect and a loop helper, prioritize the domain type/effect. For example, if DOMAIN REFERENCE contains a \`Task\` class and the user asks to create a task, create the domain task record; do not call \`loop.create_task(...)\` unless you are only tracking your own workflow.
16023
16197
  - Reuse exact \`taskId\`, \`decisionId\`, and \`closureId\` values from AGENT LOOP STATE. Never invent or rewrite them.
16024
16198
  - If the request is ambiguous or clearly multi-step, create 2-4 short user-visible tasks and keep them updated as the workflow advances.
16025
16199
  - Use \`loop.ask_user({ type: 'choice', options: [...] })\` when you have a short, grounded shortlist the user can choose from. Otherwise use \`type: 'input'\`.
@@ -16030,6 +16204,14 @@ ${loopBlock}
16030
16204
  - Use \`loop.open_decision(...)\` to persist grounded candidates, \`loop.close_decision(...)\` to resolve one, and \`loop.close_loop(...)\` when the workflow is completed, canceled, or blocked.
16031
16205
  - If you ask a new question in the current job, do not also close the loop in that same job.
16032
16206
 
16207
+ \u2500\u2500\u2500 LOOP HELPER REFERENCE \u2500\u2500\u2500
16208
+ - \`loop.ask_user(...)\`: pause the current job for missing input; use \`type: 'choice'\` only for a short grounded shortlist.
16209
+ - \`loop.confirm(...)\`: pause for yes/no approval before a consequential action, then branch on the returned boolean.
16210
+ - \`loop.open_decision(...)\`: save explicit candidates that later jobs can revisit; each candidate needs an \`id\`.
16211
+ - \`loop.close_decision(...)\`: resolve an open decision with a stored \`selectedId\` and optional rationale.
16212
+ - \`loop.create_task(...)\`, \`loop.update_task(...)\`, \`loop.complete_task(...)\`: keep a short resumable task list for the agent's workflow; these are not domain \`Task\` records.
16213
+ - \`loop.close_loop(...)\`: record the workflow outcome when it is completed, canceled, or blocked.
16214
+
16033
16215
  \u2500\u2500\u2500 CODE RULES \u2500\u2500\u2500
16034
16216
  - Import from \`./sandbox-tools\`.
16035
16217
  - If you use \`heap\`, \`loop\`, \`agent_text_message\`, or \`agent_heap_objects\`, import them explicitly from \`./sandbox-tools\`.
@@ -16039,6 +16221,7 @@ ${loopBlock}
16039
16221
  - Use \`ClassName.get({ path })\` only for known graph paths when you want a direct graph fetch.
16040
16222
  - Use \`ClassName.count()\` for totals, \`ClassName.page({ page, perPage, saveAs })\` when you need \`items\` plus \`totalCount\` or \`hasMore\`, \`ClassName.list({ page, perPage, saveAs })\` for one page of records, and \`ClassName.iterate({ perPage, maxItems })\` for large scans.
16041
16223
  - \`perPage\` defaults to \`100\` and is capped at \`100\`.
16224
+ - A single \`list(...)\` or \`page(...)\` call never proves there are no more records. For "all", "every", exports, broad scans, or exhaustive searches, use \`iterate(...)\` when available or loop \`page(...)\` until \`hasMore\` is false.
16042
16225
  - Push \`filter\`, \`search\`, and \`sort\` into graph queries instead of fetching a page and processing it locally.
16043
16226
  - A property appearing on a record does not make it valid in \`filter\` or \`sort\`; only use fields and operators that are explicitly exposed in DOMAIN REFERENCE.
16044
16227
  - Choose \`sort.field\` verbatim from the sortable fields listed in DOMAIN REFERENCE. Do not sort by relationship names, related-record collections, counts, totals, or other derived metrics unless they are explicitly listed as sortable.