@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.
- package/dist/cli/cli.js +71 -23
- package/dist/cli/src/evaluator/effectTypes.d.ts +19 -1
- package/dist/cli/src/evaluator/suspension.d.ts +6 -0
- package/dist/cli/src/evaluator/trampoline.d.ts +5 -0
- package/dist/debug.esm.js +1 -1
- package/dist/debug.esm.js.map +1 -1
- package/dist/debug.js +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/dvala.iife.js +1 -1
- package/dist/dvala.iife.js.map +1 -1
- package/dist/full.esm.js +1 -1
- package/dist/full.esm.js.map +1 -1
- package/dist/full.js +1 -1
- package/dist/full.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/server.js +116 -69
- package/dist/mcp-server/src/evaluator/effectTypes.d.ts +19 -1
- package/dist/mcp-server/src/evaluator/suspension.d.ts +6 -0
- package/dist/mcp-server/src/evaluator/trampoline.d.ts +5 -0
- package/dist/modules/src/evaluator/effectTypes.d.ts +19 -1
- package/dist/modules/src/evaluator/suspension.d.ts +6 -0
- package/dist/modules/src/evaluator/trampoline.d.ts +5 -0
- package/dist/modules/src/index.d.ts +2 -0
- package/dist/modules/src/retrigger.d.ts +39 -0
- package/dist/src/evaluator/effectTypes.d.ts +19 -1
- package/dist/src/evaluator/suspension.d.ts +6 -0
- package/dist/src/evaluator/trampoline.d.ts +5 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/retrigger.d.ts +39 -0
- package/dist/testFramework.esm.js +1 -1
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +1 -1
- package/dist/testFramework.js.map +1 -1
- 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
|
+
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
|
-
|
|
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
|
-
|
|
12067
|
-
//
|
|
12068
|
-
const
|
|
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 (
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
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
|
|
12082
|
-
switch (
|
|
12127
|
+
const { index, result } = settled.value;
|
|
12128
|
+
switch (result.type) {
|
|
12083
12129
|
case 'completed':
|
|
12084
|
-
completedBranches.push({ index
|
|
12130
|
+
completedBranches.push({ index, value: result.value });
|
|
12085
12131
|
break;
|
|
12086
12132
|
case 'suspended':
|
|
12087
|
-
suspendedBranches.push({ index
|
|
12133
|
+
suspendedBranches.push({ index, snapshot: result.snapshot });
|
|
12088
12134
|
break;
|
|
12089
12135
|
case 'error':
|
|
12090
|
-
errors.push(
|
|
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.
|
|
35150
|
-
perform(effect(dvala.io.
|
|
35151
|
-
perform(effect(dvala.io.
|
|
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.
|
|
35154
|
-
perform(effect(dvala.io.
|
|
35155
|
-
perform(effect(dvala.io.
|
|
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.
|
|
35250
|
+
perform(effect(dvala.io.print), "Waiting 500ms...");
|
|
35203
35251
|
perform(effect(host.delay), 500);
|
|
35204
|
-
perform(effect(dvala.io.
|
|
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.
|
|
35209
|
-
perform(effect(dvala.io.
|
|
35210
|
-
perform(effect(dvala.io.
|
|
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.
|
|
35215
|
-
doseq (post in posts) -> perform(effect(dvala.io.
|
|
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
|
|
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.
|
|
35296
|
+
perform(effect(dvala.io.print), "Invalid user ID: " ++ id-str ++ ". Please enter 1-10.");
|
|
35250
35297
|
else
|
|
35251
|
-
perform(effect(dvala.io.
|
|
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.
|
|
35301
|
+
perform(effect(dvala.io.print), "User not found.");
|
|
35255
35302
|
else
|
|
35256
|
-
perform(effect(dvala.io.
|
|
35257
|
-
perform(effect(dvala.io.
|
|
35258
|
-
perform(effect(dvala.io.
|
|
35259
|
-
perform(effect(dvala.io.
|
|
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.
|
|
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.
|
|
35272
|
-
doseq (t in done take 5) -> perform(effect(dvala.io.
|
|
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.
|
|
35275
|
-
end
|
|
35321
|
+
perform(effect(dvala.io.print), " ... and " ++ str(count(done) - 5) ++ " more");
|
|
35322
|
+
end;
|
|
35276
35323
|
|
|
35277
|
-
perform(effect(dvala.io.
|
|
35278
|
-
doseq (t in pending take 5) -> perform(effect(dvala.io.
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
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(
|
|
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.
|
|
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.
|
|
35691
|
+
perform(effect(dvala.io.print), "\\n" ++ message ++ "\\n");
|
|
35645
35692
|
|
|
35646
35693
|
if new-state.game-over then
|
|
35647
|
-
perform(effect(dvala.io.
|
|
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.
|
|
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.
|
|
35861
|
-
perform(effect(dvala.io.
|
|
35862
|
-
perform(effect(dvala.io.
|
|
35863
|
-
perform(effect(dvala.io.
|
|
35864
|
-
perform(effect(dvala.io.
|
|
35865
|
-
perform(effect(dvala.io.
|
|
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.
|
|
35926
|
-
perform(effect(dvala.io.
|
|
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>;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -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';
|