@elevasis/sdk 1.37.0 → 1.39.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.
Files changed (57) hide show
  1. package/dist/cli.cjs +4 -2
  2. package/dist/index.d.ts +32 -0
  3. package/dist/index.js +3 -1
  4. package/dist/node/index.d.ts +20 -0
  5. package/dist/test-utils/index.d.ts +22 -1
  6. package/dist/test-utils/index.js +73 -33
  7. package/dist/types/worker/index.d.ts +2 -1
  8. package/dist/worker/index.js +70 -32
  9. package/package.json +4 -4
  10. package/reference/claude-config/Overview.md +140 -32
  11. package/reference/claude-config/rules/active-change-index.md +13 -2
  12. package/reference/claude-config/rules/agent-start-here.md +13 -2
  13. package/reference/claude-config/rules/deployment.md +13 -2
  14. package/reference/claude-config/rules/error-handling.md +13 -2
  15. package/reference/claude-config/rules/execution.md +13 -2
  16. package/reference/claude-config/rules/frontend.md +13 -2
  17. package/reference/claude-config/rules/observability.md +13 -2
  18. package/reference/claude-config/rules/operations.md +13 -2
  19. package/reference/claude-config/rules/organization-model.md +1 -1
  20. package/reference/claude-config/rules/organization-os.md +1 -1
  21. package/reference/claude-config/rules/package-taxonomy.md +13 -2
  22. package/reference/claude-config/rules/platform.md +13 -2
  23. package/reference/claude-config/rules/shared-types.md +13 -2
  24. package/reference/claude-config/rules/task-tracking.md +13 -2
  25. package/reference/claude-config/rules/topbar-actions.md +2 -2
  26. package/reference/claude-config/rules/ui.md +13 -2
  27. package/reference/claude-config/rules/vibe.md +13 -2
  28. package/reference/claude-config/settings.json +30 -34
  29. package/reference/claude-config/skills/deploy/SKILL.md +159 -156
  30. package/reference/claude-config/skills/elevasis/SKILL.md +11 -4
  31. package/reference/claude-config/skills/explore/SKILL.md +78 -78
  32. package/reference/claude-config/skills/git-sync/SKILL.md +166 -126
  33. package/reference/claude-config/skills/om/SKILL.md +15 -15
  34. package/reference/claude-config/skills/om/operations/build.md +2 -2
  35. package/reference/claude-config/skills/project/SKILL.md +1 -1
  36. package/reference/claude-config/skills/save/SKILL.md +183 -183
  37. package/reference/claude-config/skills/setup/SKILL.md +9 -3
  38. package/reference/claude-config/skills/status/SKILL.md +59 -59
  39. package/reference/claude-config/skills/sync/SKILL.md +47 -47
  40. package/reference/claude-config/skills/tutorial/SKILL.md +1 -1
  41. package/reference/claude-config/skills/tutorial/technical.md +11 -11
  42. package/reference/claude-config/sync-notes/2026-06-25-shared-page-scroll-contract-guard.md +52 -0
  43. package/reference/claude-config/sync-notes/2026-06-26-leadgen-overview-om-telemetry.md +47 -0
  44. package/reference/claude-config/sync-notes/2026-07-21-agent-scaffold-hardening.md +75 -0
  45. package/reference/claude-config/sync-notes/2026-07-23-agent-session-memory.md +49 -0
  46. package/reference/claude-config/sync-notes/2026-07-23-workos-org-marker.md +50 -0
  47. package/reference/rules/active-change-index.md +5 -5
  48. package/reference/rules/agent-start-here.md +34 -30
  49. package/reference/rules/deployment.md +21 -8
  50. package/reference/rules/frontend.md +4 -4
  51. package/reference/rules/observability.md +1 -1
  52. package/reference/rules/organization-model.md +1 -1
  53. package/reference/rules/organization-os.md +29 -29
  54. package/reference/rules/ui.md +205 -202
  55. package/reference/rules/vibe.md +4 -4
  56. package/reference/scaffold/operations/propagation-pipeline.md +1 -1
  57. package/reference/scaffold/recipes/extend-lead-gen.md +13 -0
package/dist/cli.cjs CHANGED
@@ -40054,6 +40054,7 @@ function getLeadGenStageCatalog(model) {
40054
40054
  );
40055
40055
  const recordEntity = entry.recordEntity === "company" || entry.recordEntity === "contact" ? entry.recordEntity : void 0;
40056
40056
  const recordStageKey = stringValue(entry.recordStageKey);
40057
+ const readinessTarget = entry.readinessTarget === true ? true : void 0;
40057
40058
  results[entryId] = {
40058
40059
  key: entryId,
40059
40060
  label: stringValue(entry.label) ?? entryId,
@@ -40062,7 +40063,8 @@ function getLeadGenStageCatalog(model) {
40062
40063
  entity,
40063
40064
  ...additionalEntities.length > 0 ? { additionalEntities } : {},
40064
40065
  ...recordEntity ? { recordEntity } : {},
40065
- ...recordStageKey ? { recordStageKey } : {}
40066
+ ...recordStageKey ? { recordStageKey } : {},
40067
+ ...readinessTarget ? { readinessTarget } : {}
40066
40068
  };
40067
40069
  }
40068
40070
  }
@@ -45848,7 +45850,7 @@ function wrapAction(commandName, fn) {
45848
45850
  // package.json
45849
45851
  var package_default = {
45850
45852
  name: "@elevasis/sdk",
45851
- version: "1.37.0",
45853
+ version: "1.39.0",
45852
45854
  description: "SDK for building Elevasis organization resources",
45853
45855
  type: "module",
45854
45856
  bin: {
package/dist/index.d.ts CHANGED
@@ -5062,6 +5062,18 @@ interface LeadGenStageCatalogEntry {
5062
5062
  recordEntity?: 'company' | 'contact';
5063
5063
  /** Stage key to read from recordEntity.processing_state for Records views. */
5064
5064
  recordStageKey?: string;
5065
+ /**
5066
+ * Marks this stage as the pipeline objective ("ready" target).
5067
+ *
5068
+ * When declared, the platform UI uses the preceding stage (derived from
5069
+ * `order`) as the backlog source and this stage as the drain, producing a
5070
+ * "contacts ready for <next step>" count without hardcoding tenant-specific
5071
+ * stage keys. Only one stage per catalog should set this to `true`.
5072
+ *
5073
+ * Absent (undefined) when not declared — no tenant authoring is required;
5074
+ * the UI falls back to a generic last-incomplete-stage backlog.
5075
+ */
5076
+ readinessTarget?: boolean;
5065
5077
  }
5066
5078
 
5067
5079
  declare const ProcessingStageStatusSchema: z.ZodEnum<{
@@ -11227,6 +11239,17 @@ type MessageEvent = {
11227
11239
  result?: unknown;
11228
11240
  error?: string;
11229
11241
  };
11242
+ /**
11243
+ * A message from an earlier turn of this session.
11244
+ *
11245
+ * Deliberately lean (no ids, timestamps, or event metadata): this crosses the
11246
+ * parent -> worker payload boundary and is replayed verbatim into the model's message
11247
+ * array, so it carries only what the model needs to read the conversation.
11248
+ */
11249
+ interface ConversationMessage {
11250
+ role: 'user' | 'assistant';
11251
+ content: string;
11252
+ }
11230
11253
  /**
11231
11254
  * Execution context for all resources
11232
11255
  * Unified callback replaces SessionTurnMessages (removed)
@@ -11234,6 +11257,15 @@ type MessageEvent = {
11234
11257
  interface ExecutionContext extends ExecutionMetadata {
11235
11258
  logger: IExecutionLogger;
11236
11259
  signal?: AbortSignal;
11260
+ /**
11261
+ * This session's earlier turns, oldest first, as actually said.
11262
+ *
11263
+ * A session agent is handed its own conversation: these are replayed into the model's
11264
+ * message array as real user/assistant turns. Absent for one-off (non-session)
11265
+ * executions. The session layer bounds this before it is sent -- see
11266
+ * `selectConversationHistory`.
11267
+ */
11268
+ conversationHistory?: ConversationMessage[];
11237
11269
  onMessageEvent?: (event: MessageEvent) => Promise<void>;
11238
11270
  /** Called per iteration to write heartbeat + check stall status. Non-fatal if it throws. */
11239
11271
  onHeartbeat?: () => Promise<void>;
package/dist/index.js CHANGED
@@ -1144,6 +1144,7 @@ function getLeadGenStageCatalog(model) {
1144
1144
  );
1145
1145
  const recordEntity = entry.recordEntity === "company" || entry.recordEntity === "contact" ? entry.recordEntity : void 0;
1146
1146
  const recordStageKey = stringValue(entry.recordStageKey);
1147
+ const readinessTarget = entry.readinessTarget === true ? true : void 0;
1147
1148
  results[entryId] = {
1148
1149
  key: entryId,
1149
1150
  label: stringValue(entry.label) ?? entryId,
@@ -1152,7 +1153,8 @@ function getLeadGenStageCatalog(model) {
1152
1153
  entity,
1153
1154
  ...additionalEntities.length > 0 ? { additionalEntities } : {},
1154
1155
  ...recordEntity ? { recordEntity } : {},
1155
- ...recordStageKey ? { recordStageKey } : {}
1156
+ ...recordStageKey ? { recordStageKey } : {},
1157
+ ...readinessTarget ? { readinessTarget } : {}
1156
1158
  };
1157
1159
  }
1158
1160
  }
@@ -2760,6 +2760,17 @@ type MessageEvent = {
2760
2760
  result?: unknown;
2761
2761
  error?: string;
2762
2762
  };
2763
+ /**
2764
+ * A message from an earlier turn of this session.
2765
+ *
2766
+ * Deliberately lean (no ids, timestamps, or event metadata): this crosses the
2767
+ * parent -> worker payload boundary and is replayed verbatim into the model's message
2768
+ * array, so it carries only what the model needs to read the conversation.
2769
+ */
2770
+ interface ConversationMessage {
2771
+ role: 'user' | 'assistant';
2772
+ content: string;
2773
+ }
2763
2774
  /**
2764
2775
  * Execution context for all resources
2765
2776
  * Unified callback replaces SessionTurnMessages (removed)
@@ -2767,6 +2778,15 @@ type MessageEvent = {
2767
2778
  interface ExecutionContext extends ExecutionMetadata {
2768
2779
  logger: IExecutionLogger;
2769
2780
  signal?: AbortSignal;
2781
+ /**
2782
+ * This session's earlier turns, oldest first, as actually said.
2783
+ *
2784
+ * A session agent is handed its own conversation: these are replayed into the model's
2785
+ * message array as real user/assistant turns. Absent for one-off (non-session)
2786
+ * executions. The session layer bounds this before it is sent -- see
2787
+ * `selectConversationHistory`.
2788
+ */
2789
+ conversationHistory?: ConversationMessage[];
2770
2790
  onMessageEvent?: (event: MessageEvent) => Promise<void>;
2771
2791
  /** Called per iteration to write heartbeat + check stall status. Non-fatal if it throws. */
2772
2792
  onHeartbeat?: () => Promise<void>;
@@ -10313,6 +10313,17 @@ type MessageEvent = {
10313
10313
  result?: unknown;
10314
10314
  error?: string;
10315
10315
  };
10316
+ /**
10317
+ * A message from an earlier turn of this session.
10318
+ *
10319
+ * Deliberately lean (no ids, timestamps, or event metadata): this crosses the
10320
+ * parent -> worker payload boundary and is replayed verbatim into the model's message
10321
+ * array, so it carries only what the model needs to read the conversation.
10322
+ */
10323
+ interface ConversationMessage {
10324
+ role: 'user' | 'assistant';
10325
+ content: string;
10326
+ }
10316
10327
  /**
10317
10328
  * Execution context for all resources
10318
10329
  * Unified callback replaces SessionTurnMessages (removed)
@@ -10320,6 +10331,15 @@ type MessageEvent = {
10320
10331
  interface ExecutionContext extends ExecutionMetadata {
10321
10332
  logger: IExecutionLogger;
10322
10333
  signal?: AbortSignal;
10334
+ /**
10335
+ * This session's earlier turns, oldest first, as actually said.
10336
+ *
10337
+ * A session agent is handed its own conversation: these are replayed into the model's
10338
+ * message array as real user/assistant turns. Absent for one-off (non-session)
10339
+ * executions. The session layer bounds this before it is sent -- see
10340
+ * `selectConversationHistory`.
10341
+ */
10342
+ conversationHistory?: ConversationMessage[];
10323
10343
  onMessageEvent?: (event: MessageEvent) => Promise<void>;
10324
10344
  /** Called per iteration to write heartbeat + check stall status. Non-fatal if it throws. */
10325
10345
  onHeartbeat?: () => Promise<void>;
@@ -10793,7 +10813,8 @@ type TypedAdapter<TMap extends ToolMethodMap$1> = {
10793
10813
  * humanCheckpoints?: [...], relationships?: {...} }
10794
10814
  *
10795
10815
  * Parent -> Worker: { type: 'execute', resourceId, executionId, input, organizationId?, organizationName?,
10796
- * sessionId?, sessionTurnNumber?, parentExecutionId?, executionDepth }
10816
+ * sessionId?, sessionTurnNumber?, sessionMemory?, conversationHistory?,
10817
+ * parentExecutionId?, executionDepth }
10797
10818
  * Worker -> Parent: { type: 'result', status, output?, memorySnapshot?, error?, logs, metrics: { durationMs } }
10798
10819
  *
10799
10820
  * Parent -> Worker: { type: 'abort' } (graceful abort before terminate)
@@ -4768,6 +4768,8 @@ function buildReasoningRequest(iterationContext) {
4768
4768
  iterationContext.iteration,
4769
4769
  iterationContext.executionContext.sessionTurnNumber
4770
4770
  ),
4771
+ // A session agent gets its own conversation. Non-session executions have none.
4772
+ conversationHistory: iterationContext.executionContext.conversationHistory ?? [],
4771
4773
  includeMessageAction: isSessionCapable,
4772
4774
  includeNavigateKnowledge: hasKnowledgeMap,
4773
4775
  includeMemoryOps
@@ -5214,12 +5216,16 @@ function validateTokenConfiguration(model, maxOutputTokens) {
5214
5216
  );
5215
5217
  }
5216
5218
  }
5219
+ function buildAgentMessages(systemPrompt, memoryContext, conversationHistory = []) {
5220
+ return [
5221
+ { role: "system", content: systemPrompt },
5222
+ ...conversationHistory.map(({ role, content }) => ({ role, content })),
5223
+ { role: "user", content: memoryContext }
5224
+ ];
5225
+ }
5217
5226
  async function callLLMForAgentIteration(adapter, request) {
5218
5227
  validateTokenConfiguration(request.model, request.constraints.maxOutputTokens);
5219
- const messages = [
5220
- { role: "system", content: request.systemPrompt },
5221
- { role: "user", content: request.memoryContext }
5222
- ];
5228
+ const messages = buildAgentMessages(request.systemPrompt, request.memoryContext, request.conversationHistory);
5223
5229
  const response = await adapter.generate({
5224
5230
  messages,
5225
5231
  responseSchema: buildIterationResponseSchema(
@@ -5248,10 +5254,7 @@ async function callLLMForAgentIteration(adapter, request) {
5248
5254
  async function callLLMForAgentCompletion(adapter, request) {
5249
5255
  validateTokenConfiguration(request.model, request.constraints.maxOutputTokens);
5250
5256
  const response = await adapter.generate({
5251
- messages: [
5252
- { role: "system", content: request.systemPrompt },
5253
- { role: "user", content: request.memoryContext }
5254
- ],
5257
+ messages: buildAgentMessages(request.systemPrompt, request.memoryContext, request.conversationHistory),
5255
5258
  responseSchema: request.outputSchema,
5256
5259
  // Use output schema directly
5257
5260
  temperature: request.constraints.temperature || 0.3,
@@ -5385,6 +5388,7 @@ async function processReasoning(iterationContext) {
5385
5388
  const { reasoning, memoryOps, nextActions } = await callLLMForAgentIteration(adapter, {
5386
5389
  systemPrompt: request.systemPrompt,
5387
5390
  memoryContext: request.memoryContext,
5391
+ conversationHistory: request.conversationHistory,
5388
5392
  tools: request.tools,
5389
5393
  constraints: request.constraints,
5390
5394
  model: iterationContext.modelConfig.model,
@@ -6257,11 +6261,10 @@ var MemoryManager = class {
6257
6261
  */
6258
6262
  toContext(currentIteration, currentTurn) {
6259
6263
  const status = this.getStatus();
6260
- const currentContext = this.memory.history.filter(
6261
- (entry) => (!currentTurn || entry.turnNumber === currentTurn || entry.turnNumber === void 0) && entry.iterationNumber === currentIteration
6262
- ).reverse();
6264
+ const inTurnScope = (entry) => !currentTurn || entry.turnNumber === currentTurn || entry.turnNumber == null;
6265
+ const currentContext = this.memory.history.filter((entry) => inTurnScope(entry) && entry.iterationNumber === currentIteration).reverse();
6263
6266
  const earlierContext = this.memory.history.filter(
6264
- (entry) => (!currentTurn || entry.turnNumber === currentTurn || entry.turnNumber === void 0) && entry.iterationNumber !== null && entry.iterationNumber < currentIteration
6267
+ (entry) => inTurnScope(entry) && entry.iterationNumber !== null && entry.iterationNumber < currentIteration
6265
6268
  );
6266
6269
  const formatEntry = (entry) => {
6267
6270
  const label = `[${entry.type.toUpperCase()}]`;
@@ -6338,6 +6341,9 @@ function initializeKnowledgeMap(knowledgeMap) {
6338
6341
  nodes: Object.fromEntries(Object.entries(knowledgeMap.nodes).map(([id, node]) => [id, { ...node }]))
6339
6342
  };
6340
6343
  }
6344
+ function hasMemoryContent(memory) {
6345
+ return Object.keys(memory.sessionMemory).length > 0 || memory.history.length > 0;
6346
+ }
6341
6347
  var Agent = class {
6342
6348
  // Base properties from definition
6343
6349
  config;
@@ -6347,6 +6353,7 @@ var Agent = class {
6347
6353
  knowledgeMap;
6348
6354
  definition;
6349
6355
  adapterFactory;
6356
+ initialMemory;
6350
6357
  // Derived properties (computed from definition)
6351
6358
  shouldGenerateOutput;
6352
6359
  // Runtime state (initialized during execution)
@@ -6361,10 +6368,12 @@ var Agent = class {
6361
6368
  *
6362
6369
  * @param definition - Agent definition with config, contract, tools, and optional preloadMemory
6363
6370
  * @param adapterFactory - Factory for creating LLM adapters (decouples engine from provider SDKs)
6371
+ * @param options - Per-execution options (e.g. restored session memory)
6364
6372
  */
6365
- constructor(definition, adapterFactory) {
6373
+ constructor(definition, adapterFactory, options = {}) {
6366
6374
  this.definition = definition;
6367
6375
  this.adapterFactory = adapterFactory;
6376
+ this.initialMemory = options.initialMemory;
6368
6377
  this.config = definition.config;
6369
6378
  this.contract = definition.contract;
6370
6379
  this.modelConfig = definition.modelConfig;
@@ -6458,25 +6467,9 @@ var Agent = class {
6458
6467
  * @returns Initialized MemoryManager instance
6459
6468
  */
6460
6469
  async initializeMemoryManager(validatedInput, context) {
6461
- let memory;
6462
- if (this.definition.preloadMemory) {
6463
- const preloadStartTime = Date.now();
6464
- memory = await this.definition.preloadMemory(context);
6465
- const preloadEndTime = Date.now();
6466
- this.logger.action(
6467
- "memory-preload",
6468
- `Preloaded ${Object.keys(memory.sessionMemory).length} session memory entries`,
6469
- 0,
6470
- preloadStartTime,
6471
- preloadEndTime,
6472
- preloadEndTime - preloadStartTime
6473
- );
6470
+ const memory = await this.resolveInitialMemory(context);
6471
+ if (hasMemoryContent(memory)) {
6474
6472
  await this.reloadKnowledgeMapTools(memory, context);
6475
- } else {
6476
- memory = {
6477
- sessionMemory: {},
6478
- history: []
6479
- };
6480
6473
  }
6481
6474
  const inputStartTime = Date.now();
6482
6475
  memory.history.push({
@@ -6497,6 +6490,44 @@ var Agent = class {
6497
6490
  );
6498
6491
  return new MemoryManager(memory, this.config.constraints, this.logger);
6499
6492
  }
6493
+ /**
6494
+ * Resolve the memory this execution starts from.
6495
+ *
6496
+ * Precedence: caller-supplied `initialMemory` (session restore) > the definition's
6497
+ * `preloadMemory` author hook > empty. Returns a detached copy in the restore case so
6498
+ * the agent's mutations cannot corrupt the caller's snapshot.
6499
+ */
6500
+ async resolveInitialMemory(context) {
6501
+ if (this.initialMemory) {
6502
+ const restoreStartTime = Date.now();
6503
+ const memory = structuredClone(this.initialMemory);
6504
+ const restoreEndTime = Date.now();
6505
+ this.logger.action(
6506
+ "memory-restore",
6507
+ `Restored ${Object.keys(memory.sessionMemory).length} session memory entries`,
6508
+ 0,
6509
+ restoreStartTime,
6510
+ restoreEndTime,
6511
+ restoreEndTime - restoreStartTime
6512
+ );
6513
+ return memory;
6514
+ }
6515
+ if (this.definition.preloadMemory) {
6516
+ const preloadStartTime = Date.now();
6517
+ const memory = await this.definition.preloadMemory(context);
6518
+ const preloadEndTime = Date.now();
6519
+ this.logger.action(
6520
+ "memory-preload",
6521
+ `Preloaded ${Object.keys(memory.sessionMemory).length} session memory entries`,
6522
+ 0,
6523
+ preloadStartTime,
6524
+ preloadEndTime,
6525
+ preloadEndTime - preloadStartTime
6526
+ );
6527
+ return memory;
6528
+ }
6529
+ return { sessionMemory: {}, history: [] };
6530
+ }
6500
6531
  /**
6501
6532
  * Reload tools from knowledge map state (cross-turn persistence)
6502
6533
  *
@@ -6776,6 +6807,7 @@ var Agent = class {
6776
6807
  const structuredOutput = await callLLMForAgentCompletion(adapter, {
6777
6808
  systemPrompt,
6778
6809
  memoryContext: this.memoryManager.toContext(this.iterationNumber, this.executionContext?.sessionTurnNumber),
6810
+ conversationHistory: this.executionContext?.conversationHistory,
6779
6811
  outputSchema,
6780
6812
  constraints: {
6781
6813
  maxOutputTokens: this.modelConfig.maxOutputTokens,
@@ -8953,6 +8985,7 @@ function getLeadGenStageCatalog(model) {
8953
8985
  );
8954
8986
  const recordEntity = entry.recordEntity === "company" || entry.recordEntity === "contact" ? entry.recordEntity : void 0;
8955
8987
  const recordStageKey = stringValue(entry.recordStageKey);
8988
+ const readinessTarget = entry.readinessTarget === true ? true : void 0;
8956
8989
  results[entryId] = {
8957
8990
  key: entryId,
8958
8991
  label: stringValue(entry.label) ?? entryId,
@@ -8961,7 +8994,8 @@ function getLeadGenStageCatalog(model) {
8961
8994
  entity,
8962
8995
  ...additionalEntities.length > 0 ? { additionalEntities } : {},
8963
8996
  ...recordEntity ? { recordEntity } : {},
8964
- ...recordStageKey ? { recordStageKey } : {}
8997
+ ...recordStageKey ? { recordStageKey } : {},
8998
+ ...readinessTarget ? { readinessTarget } : {}
8965
8999
  };
8966
9000
  }
8967
9001
  }
@@ -10252,6 +10286,7 @@ function buildWorkerExecutionContext(params) {
10252
10286
  resourceId: params.resourceId,
10253
10287
  sessionId: params.sessionId,
10254
10288
  sessionTurnNumber: params.sessionTurnNumber,
10289
+ conversationHistory: params.conversationHistory,
10255
10290
  parentExecutionId: params.parentExecutionId,
10256
10291
  executionDepth: params.executionDepth,
10257
10292
  signal: params.signal,
@@ -10358,6 +10393,8 @@ function startWorker(org) {
10358
10393
  organizationName,
10359
10394
  sessionId,
10360
10395
  sessionTurnNumber,
10396
+ sessionMemory,
10397
+ conversationHistory,
10361
10398
  parentExecutionId,
10362
10399
  executionDepth
10363
10400
  } = msg;
@@ -10403,7 +10440,9 @@ function startWorker(org) {
10403
10440
  try {
10404
10441
  console.log(`[SDK-WORKER] Running agent '${resourceId}' (${agentDef.tools.length} tools)`);
10405
10442
  const adapterFactory = createPostMessageAdapterFactory();
10406
- const agentInstance = new Agent(agentDef, adapterFactory);
10443
+ const agentInstance = new Agent(agentDef, adapterFactory, {
10444
+ initialMemory: sessionMemory
10445
+ });
10407
10446
  const context = buildWorkerExecutionContext({
10408
10447
  executionId,
10409
10448
  organizationId: organizationId ?? "",
@@ -10411,6 +10450,7 @@ function startWorker(org) {
10411
10450
  resourceId,
10412
10451
  sessionId,
10413
10452
  sessionTurnNumber,
10453
+ conversationHistory,
10414
10454
  parentExecutionId,
10415
10455
  executionDepth: executionDepth ?? 0,
10416
10456
  signal: localAbortController.signal
@@ -11,7 +11,8 @@
11
11
  * humanCheckpoints?: [...], relationships?: {...} }
12
12
  *
13
13
  * Parent -> Worker: { type: 'execute', resourceId, executionId, input, organizationId?, organizationName?,
14
- * sessionId?, sessionTurnNumber?, parentExecutionId?, executionDepth }
14
+ * sessionId?, sessionTurnNumber?, sessionMemory?, conversationHistory?,
15
+ * parentExecutionId?, executionDepth }
15
16
  * Worker -> Parent: { type: 'result', status, output?, memorySnapshot?, error?, logs, metrics: { durationMs } }
16
17
  *
17
18
  * Parent -> Worker: { type: 'abort' } (graceful abort before terminate)
@@ -2890,6 +2890,8 @@ function buildReasoningRequest(iterationContext) {
2890
2890
  iterationContext.iteration,
2891
2891
  iterationContext.executionContext.sessionTurnNumber
2892
2892
  ),
2893
+ // A session agent gets its own conversation. Non-session executions have none.
2894
+ conversationHistory: iterationContext.executionContext.conversationHistory ?? [],
2893
2895
  includeMessageAction: isSessionCapable,
2894
2896
  includeNavigateKnowledge: hasKnowledgeMap,
2895
2897
  includeMemoryOps
@@ -3306,12 +3308,16 @@ function validateTokenConfiguration(model, maxOutputTokens) {
3306
3308
  );
3307
3309
  }
3308
3310
  }
3311
+ function buildAgentMessages(systemPrompt, memoryContext, conversationHistory = []) {
3312
+ return [
3313
+ { role: "system", content: systemPrompt },
3314
+ ...conversationHistory.map(({ role, content }) => ({ role, content })),
3315
+ { role: "user", content: memoryContext }
3316
+ ];
3317
+ }
3309
3318
  async function callLLMForAgentIteration(adapter, request) {
3310
3319
  validateTokenConfiguration(request.model, request.constraints.maxOutputTokens);
3311
- const messages = [
3312
- { role: "system", content: request.systemPrompt },
3313
- { role: "user", content: request.memoryContext }
3314
- ];
3320
+ const messages = buildAgentMessages(request.systemPrompt, request.memoryContext, request.conversationHistory);
3315
3321
  const response = await adapter.generate({
3316
3322
  messages,
3317
3323
  responseSchema: buildIterationResponseSchema(
@@ -3340,10 +3346,7 @@ async function callLLMForAgentIteration(adapter, request) {
3340
3346
  async function callLLMForAgentCompletion(adapter, request) {
3341
3347
  validateTokenConfiguration(request.model, request.constraints.maxOutputTokens);
3342
3348
  const response = await adapter.generate({
3343
- messages: [
3344
- { role: "system", content: request.systemPrompt },
3345
- { role: "user", content: request.memoryContext }
3346
- ],
3349
+ messages: buildAgentMessages(request.systemPrompt, request.memoryContext, request.conversationHistory),
3347
3350
  responseSchema: request.outputSchema,
3348
3351
  // Use output schema directly
3349
3352
  temperature: request.constraints.temperature || 0.3,
@@ -3477,6 +3480,7 @@ async function processReasoning(iterationContext) {
3477
3480
  const { reasoning, memoryOps, nextActions } = await callLLMForAgentIteration(adapter, {
3478
3481
  systemPrompt: request.systemPrompt,
3479
3482
  memoryContext: request.memoryContext,
3483
+ conversationHistory: request.conversationHistory,
3480
3484
  tools: request.tools,
3481
3485
  constraints: request.constraints,
3482
3486
  model: iterationContext.modelConfig.model,
@@ -4349,11 +4353,10 @@ var MemoryManager = class {
4349
4353
  */
4350
4354
  toContext(currentIteration, currentTurn) {
4351
4355
  const status = this.getStatus();
4352
- const currentContext = this.memory.history.filter(
4353
- (entry) => (!currentTurn || entry.turnNumber === currentTurn || entry.turnNumber === void 0) && entry.iterationNumber === currentIteration
4354
- ).reverse();
4356
+ const inTurnScope = (entry) => !currentTurn || entry.turnNumber === currentTurn || entry.turnNumber == null;
4357
+ const currentContext = this.memory.history.filter((entry) => inTurnScope(entry) && entry.iterationNumber === currentIteration).reverse();
4355
4358
  const earlierContext = this.memory.history.filter(
4356
- (entry) => (!currentTurn || entry.turnNumber === currentTurn || entry.turnNumber === void 0) && entry.iterationNumber !== null && entry.iterationNumber < currentIteration
4359
+ (entry) => inTurnScope(entry) && entry.iterationNumber !== null && entry.iterationNumber < currentIteration
4357
4360
  );
4358
4361
  const formatEntry = (entry) => {
4359
4362
  const label = `[${entry.type.toUpperCase()}]`;
@@ -4430,6 +4433,9 @@ function initializeKnowledgeMap(knowledgeMap) {
4430
4433
  nodes: Object.fromEntries(Object.entries(knowledgeMap.nodes).map(([id, node]) => [id, { ...node }]))
4431
4434
  };
4432
4435
  }
4436
+ function hasMemoryContent(memory) {
4437
+ return Object.keys(memory.sessionMemory).length > 0 || memory.history.length > 0;
4438
+ }
4433
4439
  var Agent = class {
4434
4440
  // Base properties from definition
4435
4441
  config;
@@ -4439,6 +4445,7 @@ var Agent = class {
4439
4445
  knowledgeMap;
4440
4446
  definition;
4441
4447
  adapterFactory;
4448
+ initialMemory;
4442
4449
  // Derived properties (computed from definition)
4443
4450
  shouldGenerateOutput;
4444
4451
  // Runtime state (initialized during execution)
@@ -4453,10 +4460,12 @@ var Agent = class {
4453
4460
  *
4454
4461
  * @param definition - Agent definition with config, contract, tools, and optional preloadMemory
4455
4462
  * @param adapterFactory - Factory for creating LLM adapters (decouples engine from provider SDKs)
4463
+ * @param options - Per-execution options (e.g. restored session memory)
4456
4464
  */
4457
- constructor(definition, adapterFactory) {
4465
+ constructor(definition, adapterFactory, options = {}) {
4458
4466
  this.definition = definition;
4459
4467
  this.adapterFactory = adapterFactory;
4468
+ this.initialMemory = options.initialMemory;
4460
4469
  this.config = definition.config;
4461
4470
  this.contract = definition.contract;
4462
4471
  this.modelConfig = definition.modelConfig;
@@ -4550,25 +4559,9 @@ var Agent = class {
4550
4559
  * @returns Initialized MemoryManager instance
4551
4560
  */
4552
4561
  async initializeMemoryManager(validatedInput, context) {
4553
- let memory;
4554
- if (this.definition.preloadMemory) {
4555
- const preloadStartTime = Date.now();
4556
- memory = await this.definition.preloadMemory(context);
4557
- const preloadEndTime = Date.now();
4558
- this.logger.action(
4559
- "memory-preload",
4560
- `Preloaded ${Object.keys(memory.sessionMemory).length} session memory entries`,
4561
- 0,
4562
- preloadStartTime,
4563
- preloadEndTime,
4564
- preloadEndTime - preloadStartTime
4565
- );
4562
+ const memory = await this.resolveInitialMemory(context);
4563
+ if (hasMemoryContent(memory)) {
4566
4564
  await this.reloadKnowledgeMapTools(memory, context);
4567
- } else {
4568
- memory = {
4569
- sessionMemory: {},
4570
- history: []
4571
- };
4572
4565
  }
4573
4566
  const inputStartTime = Date.now();
4574
4567
  memory.history.push({
@@ -4589,6 +4582,44 @@ var Agent = class {
4589
4582
  );
4590
4583
  return new MemoryManager(memory, this.config.constraints, this.logger);
4591
4584
  }
4585
+ /**
4586
+ * Resolve the memory this execution starts from.
4587
+ *
4588
+ * Precedence: caller-supplied `initialMemory` (session restore) > the definition's
4589
+ * `preloadMemory` author hook > empty. Returns a detached copy in the restore case so
4590
+ * the agent's mutations cannot corrupt the caller's snapshot.
4591
+ */
4592
+ async resolveInitialMemory(context) {
4593
+ if (this.initialMemory) {
4594
+ const restoreStartTime = Date.now();
4595
+ const memory = structuredClone(this.initialMemory);
4596
+ const restoreEndTime = Date.now();
4597
+ this.logger.action(
4598
+ "memory-restore",
4599
+ `Restored ${Object.keys(memory.sessionMemory).length} session memory entries`,
4600
+ 0,
4601
+ restoreStartTime,
4602
+ restoreEndTime,
4603
+ restoreEndTime - restoreStartTime
4604
+ );
4605
+ return memory;
4606
+ }
4607
+ if (this.definition.preloadMemory) {
4608
+ const preloadStartTime = Date.now();
4609
+ const memory = await this.definition.preloadMemory(context);
4610
+ const preloadEndTime = Date.now();
4611
+ this.logger.action(
4612
+ "memory-preload",
4613
+ `Preloaded ${Object.keys(memory.sessionMemory).length} session memory entries`,
4614
+ 0,
4615
+ preloadStartTime,
4616
+ preloadEndTime,
4617
+ preloadEndTime - preloadStartTime
4618
+ );
4619
+ return memory;
4620
+ }
4621
+ return { sessionMemory: {}, history: [] };
4622
+ }
4592
4623
  /**
4593
4624
  * Reload tools from knowledge map state (cross-turn persistence)
4594
4625
  *
@@ -4868,6 +4899,7 @@ var Agent = class {
4868
4899
  const structuredOutput = await callLLMForAgentCompletion(adapter, {
4869
4900
  systemPrompt,
4870
4901
  memoryContext: this.memoryManager.toContext(this.iterationNumber, this.executionContext?.sessionTurnNumber),
4902
+ conversationHistory: this.executionContext?.conversationHistory,
4871
4903
  outputSchema,
4872
4904
  constraints: {
4873
4905
  maxOutputTokens: this.modelConfig.maxOutputTokens,
@@ -6883,6 +6915,7 @@ function buildWorkerExecutionContext(params) {
6883
6915
  resourceId: params.resourceId,
6884
6916
  sessionId: params.sessionId,
6885
6917
  sessionTurnNumber: params.sessionTurnNumber,
6918
+ conversationHistory: params.conversationHistory,
6886
6919
  parentExecutionId: params.parentExecutionId,
6887
6920
  executionDepth: params.executionDepth,
6888
6921
  signal: params.signal,
@@ -6989,6 +7022,8 @@ function startWorker(org) {
6989
7022
  organizationName,
6990
7023
  sessionId,
6991
7024
  sessionTurnNumber,
7025
+ sessionMemory,
7026
+ conversationHistory,
6992
7027
  parentExecutionId,
6993
7028
  executionDepth
6994
7029
  } = msg;
@@ -7034,7 +7069,9 @@ function startWorker(org) {
7034
7069
  try {
7035
7070
  console.log(`[SDK-WORKER] Running agent '${resourceId}' (${agentDef.tools.length} tools)`);
7036
7071
  const adapterFactory = createPostMessageAdapterFactory();
7037
- const agentInstance = new Agent(agentDef, adapterFactory);
7072
+ const agentInstance = new Agent(agentDef, adapterFactory, {
7073
+ initialMemory: sessionMemory
7074
+ });
7038
7075
  const context = buildWorkerExecutionContext({
7039
7076
  executionId,
7040
7077
  organizationId: organizationId ?? "",
@@ -7042,6 +7079,7 @@ function startWorker(org) {
7042
7079
  resourceId,
7043
7080
  sessionId,
7044
7081
  sessionTurnNumber,
7082
+ conversationHistory,
7045
7083
  parentExecutionId,
7046
7084
  executionDepth: executionDepth ?? 0,
7047
7085
  signal: localAbortController.signal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.37.0",
3
+ "version": "1.39.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,9 +58,9 @@
58
58
  "tsup": "^8.0.0",
59
59
  "typescript": "5.9.2",
60
60
  "zod": "^4.1.0",
61
- "@repo/core": "0.53.0",
62
- "@repo/eslint-config": "0.0.0",
63
- "@repo/typescript-config": "0.0.0"
61
+ "@repo/core": "0.55.0",
62
+ "@repo/typescript-config": "0.0.0",
63
+ "@repo/eslint-config": "0.0.0"
64
64
  },
65
65
  "scripts": {
66
66
  "lint": "eslint src --max-warnings 0",