@mojir/dvala 0.0.9 → 0.0.10

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 (37) hide show
  1. package/dist/cli/cli.js +71 -23
  2. package/dist/cli/src/evaluator/effectTypes.d.ts +19 -1
  3. package/dist/cli/src/evaluator/suspension.d.ts +6 -0
  4. package/dist/cli/src/evaluator/trampoline.d.ts +5 -0
  5. package/dist/debug.esm.js +1 -1
  6. package/dist/debug.esm.js.map +1 -1
  7. package/dist/debug.js +1 -1
  8. package/dist/debug.js.map +1 -1
  9. package/dist/dvala.iife.js +1 -1
  10. package/dist/dvala.iife.js.map +1 -1
  11. package/dist/full.esm.js +1 -1
  12. package/dist/full.esm.js.map +1 -1
  13. package/dist/full.js +1 -1
  14. package/dist/full.js.map +1 -1
  15. package/dist/index.esm.js +1 -1
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/mcp-server/server.js +116 -69
  20. package/dist/mcp-server/src/evaluator/effectTypes.d.ts +19 -1
  21. package/dist/mcp-server/src/evaluator/suspension.d.ts +6 -0
  22. package/dist/mcp-server/src/evaluator/trampoline.d.ts +5 -0
  23. package/dist/modules/src/evaluator/effectTypes.d.ts +19 -1
  24. package/dist/modules/src/evaluator/suspension.d.ts +6 -0
  25. package/dist/modules/src/evaluator/trampoline.d.ts +5 -0
  26. package/dist/modules/src/index.d.ts +2 -0
  27. package/dist/modules/src/retrigger.d.ts +39 -0
  28. package/dist/src/evaluator/effectTypes.d.ts +19 -1
  29. package/dist/src/evaluator/suspension.d.ts +6 -0
  30. package/dist/src/evaluator/trampoline.d.ts +5 -0
  31. package/dist/src/index.d.ts +2 -0
  32. package/dist/src/retrigger.d.ts +39 -0
  33. package/dist/testFramework.esm.js +1 -1
  34. package/dist/testFramework.esm.js.map +1 -1
  35. package/dist/testFramework.js +1 -1
  36. package/dist/testFramework.js.map +1 -1
  37. package/package.json +1 -1
@@ -6,7 +6,7 @@ var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
6
6
  var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
7
7
  var zod = require('zod');
8
8
 
9
- var version = "0.0.9";
9
+ var version = "0.0.10";
10
10
 
11
11
  function getCodeMarker(sourceCodeInfo) {
12
12
  if (!sourceCodeInfo.position || !sourceCodeInfo.code)
@@ -8707,6 +8707,8 @@ class SuspensionSignal {
8707
8707
  snapshots;
8708
8708
  nextSnapshotIndex;
8709
8709
  meta;
8710
+ effectName;
8711
+ effectArgs;
8710
8712
  _brand = 'SuspensionSignal';
8711
8713
  constructor(
8712
8714
  /** The captured continuation stack at the point of suspension. */
@@ -8716,11 +8718,17 @@ class SuspensionSignal {
8716
8718
  /** High-water mark for snapshot indices at the point of suspension. */
8717
8719
  nextSnapshotIndex,
8718
8720
  /** Optional domain metadata passed through to RunResult. */
8719
- meta) {
8721
+ meta,
8722
+ /** The effect name being handled when suspend() was called. */
8723
+ effectName,
8724
+ /** The effect arguments being handled when suspend() was called. */
8725
+ effectArgs) {
8720
8726
  this.k = k;
8721
8727
  this.snapshots = snapshots;
8722
8728
  this.nextSnapshotIndex = nextSnapshotIndex;
8723
8729
  this.meta = meta;
8730
+ this.effectName = effectName;
8731
+ this.effectArgs = effectArgs;
8724
8732
  }
8725
8733
  }
8726
8734
  function isSuspensionSignal(value) {
@@ -11896,6 +11904,12 @@ function dispatchPerform(effect, args, k, sourceCodeInfo, handlers, signal, snap
11896
11904
  function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sourceCodeInfo, snapshotState) {
11897
11905
  const effectSignal = signal ?? new AbortController().signal;
11898
11906
  const argsArray = Array.from(args);
11907
+ // If the abort signal already fired before the handler was called, auto-suspend immediately.
11908
+ // This happens when a parallel group aborts (e.g. another branch suspended) before this
11909
+ // branch's dispatchHostHandler runs.
11910
+ if (effectSignal.aborted) {
11911
+ throwSuspension(k, undefined, effectName, argsArray);
11912
+ }
11899
11913
  function resolveOutcome(o, nextIndex) {
11900
11914
  switch (o.kind) {
11901
11915
  case 'step': return o.step;
@@ -11911,9 +11925,20 @@ function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sour
11911
11925
  const message = typeof argsArray[0] === 'string' ? argsArray[0] : String(argsArray[0] ?? 'Unknown error');
11912
11926
  throw new UserDefinedError(message, sourceCodeInfo);
11913
11927
  }
11928
+ // dvala.checkpoint resolves to null when all handlers call next() without resuming.
11929
+ if (effectName === 'dvala.checkpoint') {
11930
+ return { type: 'Value', value: null, k };
11931
+ }
11914
11932
  throw new DvalaError(`Unhandled effect: '${effectName}'`, sourceCodeInfo);
11915
11933
  }
11916
- const [, handler] = matchingHandlers[index];
11934
+ const [pattern, handler] = matchingHandlers[index];
11935
+ // Before trying a "*" catch-all, fall back to standard effects.
11936
+ if (pattern === '*') {
11937
+ const standardHandler = getStandardEffectHandler(effectName);
11938
+ if (standardHandler) {
11939
+ return standardHandler(args, k, sourceCodeInfo);
11940
+ }
11941
+ }
11917
11942
  let outcome;
11918
11943
  let settled = false;
11919
11944
  function assertNotSettled(operation) {
@@ -11944,7 +11969,7 @@ function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sour
11944
11969
  assertNotSettled('suspend');
11945
11970
  outcome = {
11946
11971
  kind: 'throw',
11947
- error: new SuspensionSignal(k, snapshotState ? snapshotState.snapshots : [], snapshotState ? snapshotState.nextSnapshotIndex : 0, meta),
11972
+ error: new SuspensionSignal(k, snapshotState ? snapshotState.snapshots : [], snapshotState ? snapshotState.nextSnapshotIndex : 0, meta, effectName, argsArray),
11948
11973
  };
11949
11974
  },
11950
11975
  next: () => {
@@ -12031,9 +12056,20 @@ function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sour
12031
12056
  * Throw a SuspensionSignal. Factored out to a helper so ESLint's
12032
12057
  * `only-throw-literal` rule can be suppressed in one place.
12033
12058
  */
12034
- function throwSuspension(k, meta) {
12059
+ /** Combine two AbortSignals: aborts when either fires (or already aborted). */
12060
+ function combineSignals(a, b) {
12061
+ const controller = new AbortController();
12062
+ if (a.aborted || b.aborted) {
12063
+ controller.abort();
12064
+ return controller.signal;
12065
+ }
12066
+ a.addEventListener('abort', () => controller.abort(), { once: true });
12067
+ b.addEventListener('abort', () => controller.abort(), { once: true });
12068
+ return controller.signal;
12069
+ }
12070
+ function throwSuspension(k, meta, effectName, effectArgs) {
12035
12071
  // eslint-disable-next-line ts/no-throw-literal -- SuspensionSignal is a signaling mechanism, not an error
12036
- throw new SuspensionSignal(k, [], 0, meta);
12072
+ throw new SuspensionSignal(k, [], 0, meta, effectName, effectArgs);
12037
12073
  }
12038
12074
  /**
12039
12075
  * Run a single trampoline branch to completion with effect handler support.
@@ -12063,31 +12099,41 @@ async function runBranch(node, env, handlers, signal) {
12063
12099
  * but errors take priority)
12064
12100
  */
12065
12101
  async function executeParallelBranches(branches, env, k, handlers, signal) {
12066
- const effectSignal = signal ?? new AbortController().signal;
12067
- // Run all branches concurrently
12068
- const branchPromises = branches.map(branch => runBranch(branch, env, handlers, effectSignal));
12102
+ // AbortController for this parallel group — aborted when any branch suspends,
12103
+ // which signals remaining effect handlers to auto-suspend via ctx.signal.
12104
+ const parallelAbort = new AbortController();
12105
+ const effectSignal = signal
12106
+ ? combineSignals(signal, parallelAbort.signal)
12107
+ : parallelAbort.signal;
12108
+ // Run all branches concurrently; abort the group when a branch suspends
12109
+ const branchPromises = branches.map(async (branch, i) => {
12110
+ const result = await runBranch(branch, env, handlers, effectSignal);
12111
+ if (result.type === 'suspended') {
12112
+ parallelAbort.abort();
12113
+ }
12114
+ return { index: i, result };
12115
+ });
12069
12116
  const results = await Promise.allSettled(branchPromises);
12070
12117
  // Collect outcomes
12071
12118
  const completedBranches = [];
12072
12119
  const suspendedBranches = [];
12073
12120
  const errors = [];
12074
- for (let i = 0; i < results.length; i++) {
12075
- const result = results[i];
12076
- if (result.status === 'rejected') {
12077
- // runEffectLoop should never reject, but handle defensively
12078
- errors.push(new DvalaError(`${result.reason}`, undefined));
12121
+ for (const settled of results) {
12122
+ if (settled.status === 'rejected') {
12123
+ // branchPromises should never reject, but handle defensively
12124
+ errors.push(new DvalaError(`${settled.reason}`, undefined));
12079
12125
  }
12080
12126
  else {
12081
- const r = result.value;
12082
- switch (r.type) {
12127
+ const { index, result } = settled.value;
12128
+ switch (result.type) {
12083
12129
  case 'completed':
12084
- completedBranches.push({ index: i, value: r.value });
12130
+ completedBranches.push({ index, value: result.value });
12085
12131
  break;
12086
12132
  case 'suspended':
12087
- suspendedBranches.push({ index: i, snapshot: r.snapshot });
12133
+ suspendedBranches.push({ index, snapshot: result.snapshot });
12088
12134
  break;
12089
12135
  case 'error':
12090
- errors.push(r.error);
12136
+ errors.push(result.error);
12091
12137
  break;
12092
12138
  }
12093
12139
  }
@@ -12106,9 +12152,9 @@ async function executeParallelBranches(branches, env, k, handlers, signal) {
12106
12152
  suspendedBranches: suspendedBranches.slice(1), // remaining after the first
12107
12153
  };
12108
12154
  const resumeK = [parallelResumeFrame, ...k];
12109
- // Throw SuspensionSignal with the first suspended branch's meta
12155
+ // Throw SuspensionSignal with the first suspended branch's meta and effect info
12110
12156
  const firstSuspended = suspendedBranches[0];
12111
- return throwSuspension(resumeK, firstSuspended.snapshot.meta);
12157
+ return throwSuspension(resumeK, firstSuspended.snapshot.meta, firstSuspended.snapshot.effectName, firstSuspended.snapshot.effectArgs);
12112
12158
  }
12113
12159
  // All branches completed — build the result array in original order
12114
12160
  const resultArray = Array.from({ length: branches.length });
@@ -12261,7 +12307,7 @@ function handleParallelResume(step, _handlers, _signal) {
12261
12307
  suspendedBranches: remaining,
12262
12308
  };
12263
12309
  const resumeK = [parallelResumeFrame, ...k];
12264
- return throwSuspension(resumeK, nextSuspended.snapshot.meta);
12310
+ return throwSuspension(resumeK, nextSuspended.snapshot.meta, nextSuspended.snapshot.effectName, nextSuspended.snapshot.effectArgs);
12265
12311
  }
12266
12312
  // All branches now completed — build the result array in original order
12267
12313
  const resultArray = Array.from({ length: branchCount });
@@ -12724,6 +12770,8 @@ async function runEffectLoop(initial, handlers, signal, initialSnapshotState, ma
12724
12770
  index: snapshotState.nextSnapshotIndex++,
12725
12771
  runId: snapshotState.runId,
12726
12772
  meta: error.meta,
12773
+ effectName: error.effectName,
12774
+ effectArgs: error.effectArgs,
12727
12775
  };
12728
12776
  return { type: 'suspended', snapshot };
12729
12777
  }
@@ -34936,7 +34984,7 @@ function specialExpressionDocsToReference() {
34936
34984
  }
34937
34985
  const specialExpressionsReference = specialExpressionDocsToReference();
34938
34986
  function isFunctionReference(ref) {
34939
- return 'returns' in ref && 'args' in ref && 'variants' in ref;
34987
+ return 'returns' in ref && 'args' in ref && 'variants' in ref && !('effect' in ref);
34940
34988
  }
34941
34989
  function isCustomReference(ref) {
34942
34990
  return 'customVariants' in ref;
@@ -35146,13 +35194,13 @@ let data = {
35146
35194
  string: "Albert"
35147
35195
  };
35148
35196
 
35149
- perform(effect(dvala.io.println), data.numbers[0]);
35150
- perform(effect(dvala.io.println), data.chars[2]);
35151
- perform(effect(dvala.io.println), data.string[0]);
35197
+ perform(effect(dvala.io.print), data.numbers[0]);
35198
+ perform(effect(dvala.io.print), data.chars[2]);
35199
+ perform(effect(dvala.io.print), data.string[0]);
35152
35200
 
35153
- perform(effect(dvala.io.println), {a: 1, b: 2, c: 3}.b);
35154
- perform(effect(dvala.io.println), "Albert"[3]);
35155
- perform(effect(dvala.io.println), [1, 2, 3][2]);
35201
+ perform(effect(dvala.io.print), {a: 1, b: 2, c: 3}.b);
35202
+ perform(effect(dvala.io.print), "Albert"[3]);
35203
+ perform(effect(dvala.io.print), [1, 2, 3][2]);
35156
35204
  `.trim(),
35157
35205
  },
35158
35206
  {
@@ -35199,20 +35247,20 @@ perform(effect(host.plus), x, y)
35199
35247
  // Call async host effects with perform(effect(...), args...)
35200
35248
 
35201
35249
  // Simulate a delay
35202
- perform(effect(dvala.io.println), "Waiting 500ms...");
35250
+ perform(effect(dvala.io.print), "Waiting 500ms...");
35203
35251
  perform(effect(host.delay), 500);
35204
- perform(effect(dvala.io.println), "Done waiting!");
35252
+ perform(effect(dvala.io.print), "Done waiting!");
35205
35253
 
35206
35254
  // Fetch a user from a REST API
35207
35255
  let user = perform(effect(host.fetch-user), 1);
35208
- perform(effect(dvala.io.println), "User: " ++ user.name);
35209
- perform(effect(dvala.io.println), "Email: " ++ user.email);
35210
- perform(effect(dvala.io.println), "City: " ++ user.city);
35256
+ perform(effect(dvala.io.print), "User: " ++ user.name);
35257
+ perform(effect(dvala.io.print), "Email: " ++ user.email);
35258
+ perform(effect(dvala.io.print), "City: " ++ user.city);
35211
35259
 
35212
35260
  // Fetch their posts
35213
35261
  let posts = perform(effect(host.fetch-posts), 1);
35214
- perform(effect(dvala.io.println), "\\nFirst " ++ str(count(posts)) ++ " posts by " ++ user.name ++ ":");
35215
- doseq (post in posts) -> perform(effect(dvala.io.println), "- " ++ post.title);
35262
+ perform(effect(dvala.io.print), "\\nFirst " ++ str(count(posts)) ++ " posts by " ++ user.name ++ ":");
35263
+ doseq (post in posts) -> perform(effect(dvala.io.print), "- " ++ post.title);
35216
35264
  `.trim(),
35217
35265
  },
35218
35266
  {
@@ -35221,7 +35269,6 @@ doseq (post in posts) -> perform(effect(dvala.io.println), "- " ++ post.title);
35221
35269
  description: 'A more complex async example with user interactions. Uses prompt for input and fetch for API calls.',
35222
35270
  context: {
35223
35271
  effectHandlers: {
35224
- 'host.prompt': 'async ({ args: [title], resume }) => { resume(prompt(title)) }',
35225
35272
  'host.fetch-user': `async ({ args: [id], resume, fail }) => {
35226
35273
  try {
35227
35274
  const response = await fetch('https://jsonplaceholder.typicode.com/users/' + id);
@@ -35241,62 +35288,62 @@ doseq (post in posts) -> perform(effect(dvala.io.println), "- " ++ post.title);
35241
35288
  },
35242
35289
  code: `
35243
35290
  // Interactive async example
35244
- // Uses host.prompt for user input and host.fetch-* for API calls
35291
+ // Uses dvala.io.read-line for user input and host.fetch-* for API calls
35245
35292
 
35246
35293
  let lookup-user! = (id-str) -> do
35247
35294
  let id = number(id-str);
35248
35295
  if not(number?(id)) || id < 1 || id > 10 then
35249
- perform(effect(dvala.io.println), "Invalid user ID: " ++ id-str ++ ". Please enter 1-10.");
35296
+ perform(effect(dvala.io.print), "Invalid user ID: " ++ id-str ++ ". Please enter 1-10.");
35250
35297
  else
35251
- perform(effect(dvala.io.println), "Fetching user " ++ str(id) ++ "...");
35298
+ perform(effect(dvala.io.print), "Fetching user " ++ str(id) ++ "...");
35252
35299
  let user = perform(effect(host.fetch-user), id);
35253
35300
  if null?(user) then
35254
- perform(effect(dvala.io.println), "User not found.");
35301
+ perform(effect(dvala.io.print), "User not found.");
35255
35302
  else
35256
- perform(effect(dvala.io.println), "Name: " ++ user.name);
35257
- perform(effect(dvala.io.println), "Email: " ++ user.email);
35258
- perform(effect(dvala.io.println), "City: " ++ user.city);
35259
- perform(effect(dvala.io.println), "Company: " ++ user.company);
35303
+ perform(effect(dvala.io.print), "Name: " ++ user.name);
35304
+ perform(effect(dvala.io.print), "Email: " ++ user.email);
35305
+ perform(effect(dvala.io.print), "City: " ++ user.city);
35306
+ perform(effect(dvala.io.print), "Company: " ++ user.company);
35260
35307
  user;
35261
35308
  end
35262
35309
  end
35263
35310
  end;
35264
35311
 
35265
35312
  let show-todos! = (user) -> do
35266
- perform(effect(dvala.io.println), "\\nFetching todos for " ++ user.name ++ "...");
35313
+ perform(effect(dvala.io.print), "\\nFetching todos for " ++ user.name ++ "...");
35267
35314
  let todos = perform(effect(host.fetch-todos), user.id);
35268
35315
  let done = filter(todos, -> $.completed);
35269
35316
  let pending = filter(todos, -> not($.completed));
35270
35317
 
35271
- perform(effect(dvala.io.println), "\\nCompleted (" ++ str(count(done)) ++ "/" ++ str(count(todos)) ++ "):");
35272
- doseq (t in done take 5) -> perform(effect(dvala.io.println), " ✓ " ++ t.title);
35318
+ perform(effect(dvala.io.print), "\\nCompleted (" ++ str(count(done)) ++ "/" ++ str(count(todos)) ++ "):");
35319
+ doseq (t in done take 5) -> perform(effect(dvala.io.print), " ✓ " ++ t.title);
35273
35320
  if count(done) > 5 then
35274
- perform(effect(dvala.io.println), " ... and " ++ str(count(done) - 5) ++ " more");
35275
- end
35321
+ perform(effect(dvala.io.print), " ... and " ++ str(count(done) - 5) ++ " more");
35322
+ end;
35276
35323
 
35277
- perform(effect(dvala.io.println), "\\nPending (" ++ str(count(pending)) ++ "):");
35278
- doseq (t in pending take 5) -> perform(effect(dvala.io.println), " ○ " ++ t.title);
35324
+ perform(effect(dvala.io.print), "\\nPending (" ++ str(count(pending)) ++ "):");
35325
+ doseq (t in pending take 5) -> perform(effect(dvala.io.print), " ○ " ++ t.title);
35279
35326
  if count(pending) > 5 then
35280
- perform(effect(dvala.io.println), " ... and " ++ str(count(pending) - 5) ++ " more");
35327
+ perform(effect(dvala.io.print), " ... and " ++ str(count(pending) - 5) ++ " more");
35281
35328
  end
35282
35329
  end;
35283
35330
 
35284
35331
  // Main interaction loop
35285
35332
  let main! = () -> do
35286
- perform(effect(dvala.io.println), "=== User Lookup Tool ===\\n");
35333
+ perform(effect(dvala.io.print), "=== User Lookup Tool ===\\n");
35287
35334
 
35288
35335
  loop (continue? = true) ->
35289
35336
  if continue? then
35290
- let input = perform(effect(host.prompt), "Enter a user ID (1-10), or cancel to quit:");
35337
+ let input = perform(effect(dvala.io.read-line), "Enter a user ID (1-10), or cancel to quit:");
35291
35338
  if null?(input) || input == "" then
35292
- perform(effect(dvala.io.println), "Goodbye!");
35339
+ perform(effect(dvala.io.print), "Goodbye!");
35293
35340
  else
35294
35341
  let user = lookup-user!(input);
35295
35342
  if user then
35296
- let show = perform(effect(host.prompt), "Show todos for " ++ user.name ++ "? (yes/no)");
35343
+ let show = perform(effect(dvala.io.read-line), "Show todos for " ++ user.name ++ "? (yes/no)");
35297
35344
  if show == "yes" then show-todos!(user) end;
35298
35345
  end;
35299
- perform(effect(dvala.io.println), "");
35346
+ perform(effect(dvala.io.print), "");
35300
35347
  recur(true)
35301
35348
  end
35302
35349
 
@@ -35641,10 +35688,10 @@ let game-loop = (state) -> do
35641
35688
  let new-state = first(command_result);
35642
35689
  let message = second(command_result);
35643
35690
 
35644
- perform(effect(dvala.io.println), "\\n" ++ message ++ "\\n");
35691
+ perform(effect(dvala.io.print), "\\n" ++ message ++ "\\n");
35645
35692
 
35646
35693
  if new-state.game-over then
35647
- perform(effect(dvala.io.println), "\\nGame over! You made " ++ str(new-state.moves) ++ " moves.");
35694
+ perform(effect(dvala.io.print), "\\nGame over! You made " ++ str(new-state.moves) ++ " moves.");
35648
35695
  new-state
35649
35696
  else
35650
35697
  game-loop(new-state)
@@ -35653,7 +35700,7 @@ end;
35653
35700
 
35654
35701
  // Start game
35655
35702
  let start-game = () -> do
35656
- perform(effect(dvala.io.println), "=== Dvala Adventure Game ===\\n" ++ "Type 'help' for a list of commands.\\n\\n");
35703
+ perform(effect(dvala.io.print), "=== Dvala Adventure Game ===\\n" ++ "Type 'help' for a list of commands.\\n\\n");
35657
35704
  game-loop(initial-state)
35658
35705
  end;
35659
35706
 
@@ -35857,12 +35904,12 @@ let formatPhoneNumber = (data) -> do
35857
35904
  end;
35858
35905
 
35859
35906
 
35860
- perform(effect(dvala.io.println), formatPhoneNumber);
35861
- perform(effect(dvala.io.println), formatPhoneNumber(123234));
35862
- perform(effect(dvala.io.println), formatPhoneNumber("123234"));
35863
- perform(effect(dvala.io.println), formatPhoneNumber("1232343456"));
35864
- perform(effect(dvala.io.println), formatPhoneNumber("+11232343456789"));
35865
- perform(effect(dvala.io.println), formatPhoneNumber("+11232343456"));
35907
+ perform(effect(dvala.io.print), formatPhoneNumber);
35908
+ perform(effect(dvala.io.print), formatPhoneNumber(123234));
35909
+ perform(effect(dvala.io.print), formatPhoneNumber("123234"));
35910
+ perform(effect(dvala.io.print), formatPhoneNumber("1232343456"));
35911
+ perform(effect(dvala.io.print), formatPhoneNumber("+11232343456789"));
35912
+ perform(effect(dvala.io.print), formatPhoneNumber("+11232343456"));
35866
35913
  `.trim(),
35867
35914
  },
35868
35915
  {
@@ -35922,8 +35969,8 @@ let isoDateString? = (data) -> do
35922
35969
  end
35923
35970
  end;
35924
35971
 
35925
- perform(effect(dvala.io.println), isoDateString?("1978-12-21"));
35926
- perform(effect(dvala.io.println), isoDateString?("197-12-21"));
35972
+ perform(effect(dvala.io.print), isoDateString?("1978-12-21"));
35973
+ perform(effect(dvala.io.print), isoDateString?("197-12-21"));
35927
35974
  `.trim(),
35928
35975
  },
35929
35976
  {
@@ -23,6 +23,16 @@ export interface Snapshot {
23
23
  readonly runId: string;
24
24
  /** Optional domain metadata from the perform call or suspend call. */
25
25
  readonly meta?: Any;
26
+ /**
27
+ * The name of the effect that was being handled when the program suspended.
28
+ * Undefined when suspension occurred outside of an effect handler (e.g. in parallel/race branches).
29
+ */
30
+ readonly effectName?: string;
31
+ /**
32
+ * The arguments passed to the suspended effect's perform call.
33
+ * Undefined when suspension occurred outside of an effect handler.
34
+ */
35
+ readonly effectArgs?: Any[];
26
36
  }
27
37
  /**
28
38
  * Generate a UUID for identifying a run() or resume() call.
@@ -144,6 +154,10 @@ export declare class SuspensionSignal {
144
154
  readonly nextSnapshotIndex: number;
145
155
  /** Optional domain metadata passed through to RunResult. */
146
156
  readonly meta?: Any | undefined;
157
+ /** The effect name being handled when suspend() was called. */
158
+ readonly effectName?: string | undefined;
159
+ /** The effect arguments being handled when suspend() was called. */
160
+ readonly effectArgs?: Any[] | undefined;
147
161
  readonly _brand: "SuspensionSignal";
148
162
  constructor(
149
163
  /** The captured continuation stack at the point of suspension. */
@@ -153,7 +167,11 @@ export declare class SuspensionSignal {
153
167
  /** High-water mark for snapshot indices at the point of suspension. */
154
168
  nextSnapshotIndex: number,
155
169
  /** Optional domain metadata passed through to RunResult. */
156
- meta?: Any | undefined);
170
+ meta?: Any | undefined,
171
+ /** The effect name being handled when suspend() was called. */
172
+ effectName?: string | undefined,
173
+ /** The effect arguments being handled when suspend() was called. */
174
+ effectArgs?: Any[] | undefined);
157
175
  }
158
176
  export declare function isSuspensionSignal(value: unknown): value is SuspensionSignal;
159
177
  /**
@@ -83,4 +83,10 @@ export declare function deserializeFromObject(blobData: unknown, options?: Deser
83
83
  snapshots: Snapshot[];
84
84
  nextSnapshotIndex: number;
85
85
  };
86
+ /**
87
+ * Extract checkpoint snapshots from a serialized continuation blob,
88
+ * expanding any pool references so each snapshot is a self-contained blob
89
+ * that can be passed directly to `resume()`.
90
+ */
91
+ export declare function extractCheckpointSnapshots(continuation: unknown): Snapshot[];
86
92
  export {};
@@ -131,3 +131,8 @@ export declare function resumeWithEffects(k: ContinuationStack, value: Any, hand
131
131
  nextSnapshotIndex: number;
132
132
  maxSnapshots?: number;
133
133
  }, deserializeOptions?: DeserializeOptions): Promise<RunResult>;
134
+ export declare function retriggerWithEffects(k: ContinuationStack, effectName: string, effectArgs: Any[], handlers?: Handlers, initialSnapshotState?: {
135
+ snapshots: Snapshot[];
136
+ nextSnapshotIndex: number;
137
+ maxSnapshots?: number;
138
+ }, deserializeOptions?: DeserializeOptions, outerSignal?: AbortSignal): Promise<RunResult>;
@@ -23,6 +23,16 @@ export interface Snapshot {
23
23
  readonly runId: string;
24
24
  /** Optional domain metadata from the perform call or suspend call. */
25
25
  readonly meta?: Any;
26
+ /**
27
+ * The name of the effect that was being handled when the program suspended.
28
+ * Undefined when suspension occurred outside of an effect handler (e.g. in parallel/race branches).
29
+ */
30
+ readonly effectName?: string;
31
+ /**
32
+ * The arguments passed to the suspended effect's perform call.
33
+ * Undefined when suspension occurred outside of an effect handler.
34
+ */
35
+ readonly effectArgs?: Any[];
26
36
  }
27
37
  /**
28
38
  * Generate a UUID for identifying a run() or resume() call.
@@ -144,6 +154,10 @@ export declare class SuspensionSignal {
144
154
  readonly nextSnapshotIndex: number;
145
155
  /** Optional domain metadata passed through to RunResult. */
146
156
  readonly meta?: Any | undefined;
157
+ /** The effect name being handled when suspend() was called. */
158
+ readonly effectName?: string | undefined;
159
+ /** The effect arguments being handled when suspend() was called. */
160
+ readonly effectArgs?: Any[] | undefined;
147
161
  readonly _brand: "SuspensionSignal";
148
162
  constructor(
149
163
  /** The captured continuation stack at the point of suspension. */
@@ -153,7 +167,11 @@ export declare class SuspensionSignal {
153
167
  /** High-water mark for snapshot indices at the point of suspension. */
154
168
  nextSnapshotIndex: number,
155
169
  /** Optional domain metadata passed through to RunResult. */
156
- meta?: Any | undefined);
170
+ meta?: Any | undefined,
171
+ /** The effect name being handled when suspend() was called. */
172
+ effectName?: string | undefined,
173
+ /** The effect arguments being handled when suspend() was called. */
174
+ effectArgs?: Any[] | undefined);
157
175
  }
158
176
  export declare function isSuspensionSignal(value: unknown): value is SuspensionSignal;
159
177
  /**
@@ -83,4 +83,10 @@ export declare function deserializeFromObject(blobData: unknown, options?: Deser
83
83
  snapshots: Snapshot[];
84
84
  nextSnapshotIndex: number;
85
85
  };
86
+ /**
87
+ * Extract checkpoint snapshots from a serialized continuation blob,
88
+ * expanding any pool references so each snapshot is a self-contained blob
89
+ * that can be passed directly to `resume()`.
90
+ */
91
+ export declare function extractCheckpointSnapshots(continuation: unknown): Snapshot[];
86
92
  export {};
@@ -131,3 +131,8 @@ export declare function resumeWithEffects(k: ContinuationStack, value: Any, hand
131
131
  nextSnapshotIndex: number;
132
132
  maxSnapshots?: number;
133
133
  }, deserializeOptions?: DeserializeOptions): Promise<RunResult>;
134
+ export declare function retriggerWithEffects(k: ContinuationStack, effectName: string, effectArgs: Any[], handlers?: Handlers, initialSnapshotState?: {
135
+ snapshots: Snapshot[];
136
+ nextSnapshotIndex: number;
137
+ maxSnapshots?: number;
138
+ }, deserializeOptions?: DeserializeOptions, outerSignal?: AbortSignal): Promise<RunResult>;
@@ -14,6 +14,8 @@ export { isGrid, isMatrix, isVector } from './typeGuards/annotatedCollections';
14
14
  export type { AutoCompleter, AutoCompleterParams } from './AutoCompleter/AutoCompleter';
15
15
  export { resume } from './resume';
16
16
  export type { ResumeOptions } from './resume';
17
+ export { retrigger } from './retrigger';
18
+ export type { RetriggerOptions } from './retrigger';
17
19
  export type { EffectContext, EffectHandler, Handlers, RunResult, Snapshot } from './evaluator/effectTypes';
18
20
  export { createDvala } from './createDvala';
19
21
  export type { CreateDvalaOptions, DvalaRunOptions, DvalaRunAsyncOptions, DvalaRunner } from './createDvala';
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Standalone `retrigger()` function for resuming suspended continuations
3
+ * by re-firing the original effect to the host handlers.
4
+ *
5
+ * The primary API for running Dvala programs is `createDvala()` from `./createDvala`.
6
+ */
7
+ import type { Any } from './interface';
8
+ import type { DvalaModule } from './builtin/modules/interface';
9
+ import type { Handlers, RunResult, Snapshot } from './evaluator/effectTypes';
10
+ /**
11
+ * Options for `retrigger()` — resume a suspended continuation by re-firing
12
+ * the original effect to the host handlers.
13
+ */
14
+ export interface RetriggerOptions {
15
+ bindings?: Record<string, Any>;
16
+ handlers?: Handlers;
17
+ modules?: DvalaModule[];
18
+ maxSnapshots?: number;
19
+ }
20
+ /**
21
+ * Resume a suspended continuation by re-triggering the original effect.
22
+ *
23
+ * Takes a `Snapshot` from a previous `RunResult` of type `'suspended'` and
24
+ * re-dispatches the original effect (captured in `snapshot.effectName` /
25
+ * `snapshot.effectArgs`) to the registered host handlers. The handler then
26
+ * calls `resume(value)`, `fail()`, or `suspend()` as normal.
27
+ *
28
+ * Throws if the snapshot has no captured effect (i.e. suspension occurred
29
+ * outside of an effect handler, such as in a parallel/race branch).
30
+ *
31
+ * Always resolves — never rejects. May return `completed`, `suspended`
32
+ * (if the handler suspends again), or `error`.
33
+ *
34
+ * ```typescript
35
+ * const { snapshot } = suspendedResult
36
+ * const next = await retrigger(snapshot, { handlers })
37
+ * ```
38
+ */
39
+ export declare function retrigger(snapshot: Snapshot, options?: RetriggerOptions): Promise<RunResult>;
@@ -23,6 +23,16 @@ export interface Snapshot {
23
23
  readonly runId: string;
24
24
  /** Optional domain metadata from the perform call or suspend call. */
25
25
  readonly meta?: Any;
26
+ /**
27
+ * The name of the effect that was being handled when the program suspended.
28
+ * Undefined when suspension occurred outside of an effect handler (e.g. in parallel/race branches).
29
+ */
30
+ readonly effectName?: string;
31
+ /**
32
+ * The arguments passed to the suspended effect's perform call.
33
+ * Undefined when suspension occurred outside of an effect handler.
34
+ */
35
+ readonly effectArgs?: Any[];
26
36
  }
27
37
  /**
28
38
  * Generate a UUID for identifying a run() or resume() call.
@@ -144,6 +154,10 @@ export declare class SuspensionSignal {
144
154
  readonly nextSnapshotIndex: number;
145
155
  /** Optional domain metadata passed through to RunResult. */
146
156
  readonly meta?: Any | undefined;
157
+ /** The effect name being handled when suspend() was called. */
158
+ readonly effectName?: string | undefined;
159
+ /** The effect arguments being handled when suspend() was called. */
160
+ readonly effectArgs?: Any[] | undefined;
147
161
  readonly _brand: "SuspensionSignal";
148
162
  constructor(
149
163
  /** The captured continuation stack at the point of suspension. */
@@ -153,7 +167,11 @@ export declare class SuspensionSignal {
153
167
  /** High-water mark for snapshot indices at the point of suspension. */
154
168
  nextSnapshotIndex: number,
155
169
  /** Optional domain metadata passed through to RunResult. */
156
- meta?: Any | undefined);
170
+ meta?: Any | undefined,
171
+ /** The effect name being handled when suspend() was called. */
172
+ effectName?: string | undefined,
173
+ /** The effect arguments being handled when suspend() was called. */
174
+ effectArgs?: Any[] | undefined);
157
175
  }
158
176
  export declare function isSuspensionSignal(value: unknown): value is SuspensionSignal;
159
177
  /**
@@ -83,4 +83,10 @@ export declare function deserializeFromObject(blobData: unknown, options?: Deser
83
83
  snapshots: Snapshot[];
84
84
  nextSnapshotIndex: number;
85
85
  };
86
+ /**
87
+ * Extract checkpoint snapshots from a serialized continuation blob,
88
+ * expanding any pool references so each snapshot is a self-contained blob
89
+ * that can be passed directly to `resume()`.
90
+ */
91
+ export declare function extractCheckpointSnapshots(continuation: unknown): Snapshot[];
86
92
  export {};
@@ -131,3 +131,8 @@ export declare function resumeWithEffects(k: ContinuationStack, value: Any, hand
131
131
  nextSnapshotIndex: number;
132
132
  maxSnapshots?: number;
133
133
  }, deserializeOptions?: DeserializeOptions): Promise<RunResult>;
134
+ export declare function retriggerWithEffects(k: ContinuationStack, effectName: string, effectArgs: Any[], handlers?: Handlers, initialSnapshotState?: {
135
+ snapshots: Snapshot[];
136
+ nextSnapshotIndex: number;
137
+ maxSnapshots?: number;
138
+ }, deserializeOptions?: DeserializeOptions, outerSignal?: AbortSignal): Promise<RunResult>;
@@ -14,6 +14,8 @@ export { isGrid, isMatrix, isVector } from './typeGuards/annotatedCollections';
14
14
  export type { AutoCompleter, AutoCompleterParams } from './AutoCompleter/AutoCompleter';
15
15
  export { resume } from './resume';
16
16
  export type { ResumeOptions } from './resume';
17
+ export { retrigger } from './retrigger';
18
+ export type { RetriggerOptions } from './retrigger';
17
19
  export type { EffectContext, EffectHandler, Handlers, RunResult, Snapshot } from './evaluator/effectTypes';
18
20
  export { createDvala } from './createDvala';
19
21
  export type { CreateDvalaOptions, DvalaRunOptions, DvalaRunAsyncOptions, DvalaRunner } from './createDvala';