agency-lang 0.0.104 → 0.0.105
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/lib/backends/typescriptBuilder.d.ts +9 -9
- package/dist/lib/backends/typescriptBuilder.js +94 -168
- package/dist/lib/runtime/call.d.ts +3 -0
- package/dist/lib/runtime/call.js +30 -0
- package/dist/lib/runtime/call.test.d.ts +1 -0
- package/dist/lib/runtime/call.test.js +67 -0
- package/dist/lib/runtime/index.d.ts +1 -0
- package/dist/lib/runtime/index.js +1 -0
- package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/imports.js +1 -0
- package/package.json +1 -1
- package/stdlib/array.js +81 -23
- package/stdlib/clipboard.js +22 -2
- package/stdlib/fs.js +57 -7
- package/stdlib/http.js +25 -3
- package/stdlib/index.js +157 -17
- package/stdlib/object.js +11 -10
- package/stdlib/path.js +57 -7
- package/stdlib/shell.js +57 -7
- package/stdlib/speech.js +22 -2
- package/stdlib/strategy.js +11 -10
- package/stdlib/system.js +46 -5
- package/stdlib/ui.js +175 -13
- package/stdlib/weather.js +9 -1
- package/stdlib/wikipedia.js +25 -3
|
@@ -66,16 +66,14 @@ export declare class TypeScriptBuilder {
|
|
|
66
66
|
private checkpointOpts;
|
|
67
67
|
private getVisibleTypeAliases;
|
|
68
68
|
private forkBranchSetup;
|
|
69
|
-
private static
|
|
69
|
+
private static DIRECT_CALL_FUNCTIONS;
|
|
70
70
|
/**
|
|
71
|
-
* Returns true if
|
|
72
|
-
*
|
|
73
|
-
* non-Agency function (TS import, internal __ prefixed helper, or template function).
|
|
71
|
+
* Returns true if a function call should have interrupt-checking boilerplate.
|
|
72
|
+
* Everything gets interrupt handling UNLESS it's a known non-Agency function.
|
|
74
73
|
*/
|
|
75
|
-
private
|
|
74
|
+
private shouldHandleInterrupts;
|
|
76
75
|
private _plainTsImportNames;
|
|
77
76
|
private _agencyImportNames;
|
|
78
|
-
private isPlainTsImport;
|
|
79
77
|
private _buildImportNameSets;
|
|
80
78
|
private isGraphNode;
|
|
81
79
|
private isImpureImportedFunction;
|
|
@@ -129,9 +127,11 @@ export declare class TypeScriptBuilder {
|
|
|
129
127
|
*/
|
|
130
128
|
private isKnownClassMethod;
|
|
131
129
|
/**
|
|
132
|
-
* Build the
|
|
130
|
+
* Build the standard state config for __call/__callMethod dispatch.
|
|
131
|
+
* During global init, only ctx is available; otherwise includes threads
|
|
132
|
+
* and interruptData.
|
|
133
133
|
*/
|
|
134
|
-
private
|
|
134
|
+
private buildStateConfig;
|
|
135
135
|
/**
|
|
136
136
|
* Collect all fields for a class, walking the inheritance chain.
|
|
137
137
|
* Returns parent fields first, then own fields.
|
|
@@ -179,7 +179,7 @@ export declare class TypeScriptBuilder {
|
|
|
179
179
|
private processFunctionCallAsStatement;
|
|
180
180
|
private processFunctionCall;
|
|
181
181
|
private generateFunctionCallExpression;
|
|
182
|
-
private
|
|
182
|
+
private emitRuntimeDispatchCall;
|
|
183
183
|
private emitDirectFunctionCall;
|
|
184
184
|
/**
|
|
185
185
|
* Build a CallType descriptor TsNode for an Agency function call.
|
|
@@ -201,43 +201,29 @@ export class TypeScriptBuilder {
|
|
|
201
201
|
ts.assign(branchWithBranchKey, ts.obj({ stack: forked })),
|
|
202
202
|
];
|
|
203
203
|
}
|
|
204
|
-
// Plain JS functions
|
|
205
|
-
//
|
|
206
|
-
static
|
|
204
|
+
// Plain JS functions that bypass __call dispatch and are called directly.
|
|
205
|
+
// These are NOT AgencyFunction instances.
|
|
206
|
+
static DIRECT_CALL_FUNCTIONS = new Set([
|
|
207
207
|
"approve", "reject", "propagate",
|
|
208
208
|
"success", "failure",
|
|
209
209
|
"isInterrupt", "isDebugger", "isRejected", "isApproved",
|
|
210
210
|
"isSuccess", "isFailure", "mcp"
|
|
211
211
|
]);
|
|
212
212
|
/**
|
|
213
|
-
* Returns true if
|
|
214
|
-
*
|
|
215
|
-
* non-Agency function (TS import, internal __ prefixed helper, or template function).
|
|
213
|
+
* Returns true if a function call should have interrupt-checking boilerplate.
|
|
214
|
+
* Everything gets interrupt handling UNLESS it's a known non-Agency function.
|
|
216
215
|
*/
|
|
217
|
-
|
|
218
|
-
if (context === "valueAccess") {
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
// Internal machinery (builder-emitted helpers like __deepClone, __validateType, etc.)
|
|
216
|
+
shouldHandleInterrupts(functionName) {
|
|
222
217
|
if (functionName.startsWith("__"))
|
|
223
218
|
return false;
|
|
224
|
-
|
|
225
|
-
if (TypeScriptBuilder.TEMPLATE_FUNCTIONS.has(functionName))
|
|
219
|
+
if (TypeScriptBuilder.DIRECT_CALL_FUNCTIONS.has(functionName))
|
|
226
220
|
return false;
|
|
227
|
-
|
|
228
|
-
if (this.isPlainTsImport(functionName))
|
|
221
|
+
if (this.isGraphNode(functionName))
|
|
229
222
|
return false;
|
|
230
|
-
// Everything else is (or might be) an AgencyFunction
|
|
231
223
|
return true;
|
|
232
224
|
}
|
|
233
225
|
_plainTsImportNames = null;
|
|
234
226
|
_agencyImportNames = null;
|
|
235
|
-
isPlainTsImport(functionName) {
|
|
236
|
-
if (!this._plainTsImportNames) {
|
|
237
|
-
this._buildImportNameSets();
|
|
238
|
-
}
|
|
239
|
-
return this._plainTsImportNames.has(functionName);
|
|
240
|
-
}
|
|
241
227
|
_buildImportNameSets() {
|
|
242
228
|
this._plainTsImportNames = new Set();
|
|
243
229
|
this._agencyImportNames = new Set();
|
|
@@ -739,30 +725,19 @@ export class TypeScriptBuilder {
|
|
|
739
725
|
}
|
|
740
726
|
case "methodCall": {
|
|
741
727
|
const isLastInChain = element === node.chain[node.chain.length - 1];
|
|
742
|
-
const
|
|
743
|
-
//
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
const propNode = ts.prop(result, callNode.callee.name, { optional: element.optional });
|
|
751
|
-
const callExpr = ts.call(propNode, args);
|
|
752
|
-
// Parenthesize awaited calls when more chain elements follow,
|
|
753
|
-
// so .next() runs on the resolved value, not the Promise.
|
|
754
|
-
result = isLastInChain
|
|
755
|
-
? ts.await(callExpr)
|
|
756
|
-
: ts.raw(`(${this.str(ts.await(callExpr))})`);
|
|
757
|
-
}
|
|
758
|
-
else {
|
|
759
|
-
// Fallback for complex cases (e.g. await-wrapped)
|
|
760
|
-
const dot = element.optional ? "?." : ".";
|
|
761
|
-
const awaited = `await ${this.str(result)}${dot}${this.str(callNode)}`;
|
|
762
|
-
result = isLastInChain
|
|
763
|
-
? ts.raw(awaited)
|
|
764
|
-
: ts.raw(`(${awaited})`);
|
|
728
|
+
const fnCall = element.functionCall;
|
|
729
|
+
// Build descriptor from the method call's arguments
|
|
730
|
+
const descriptor = this.buildCallDescriptor(fnCall);
|
|
731
|
+
const configObj = this.buildStateConfig();
|
|
732
|
+
const propArg = ts.str(fnCall.functionName);
|
|
733
|
+
const callArgs = [result, propArg, descriptor, configObj];
|
|
734
|
+
if (element.optional) {
|
|
735
|
+
callArgs.push(ts.bool(true));
|
|
765
736
|
}
|
|
737
|
+
const callExpr = ts.call(ts.id("__callMethod"), callArgs);
|
|
738
|
+
result = isLastInChain
|
|
739
|
+
? ts.await(callExpr)
|
|
740
|
+
: ts.raw(`(${this.str(ts.await(callExpr))})`);
|
|
766
741
|
break;
|
|
767
742
|
}
|
|
768
743
|
}
|
|
@@ -856,16 +831,22 @@ export class TypeScriptBuilder {
|
|
|
856
831
|
return false;
|
|
857
832
|
}
|
|
858
833
|
/**
|
|
859
|
-
* Build the
|
|
834
|
+
* Build the standard state config for __call/__callMethod dispatch.
|
|
835
|
+
* During global init, only ctx is available; otherwise includes threads
|
|
836
|
+
* and interruptData.
|
|
860
837
|
*/
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
838
|
+
buildStateConfig(opts) {
|
|
839
|
+
if (this.insideGlobalInit) {
|
|
840
|
+
return ts.functionCallConfig({ ctx: ts.runtime.ctx });
|
|
841
|
+
}
|
|
842
|
+
return ts.functionCallConfig({
|
|
843
|
+
ctx: ts.runtime.ctx,
|
|
844
|
+
threads: ts.runtime.threads,
|
|
845
|
+
interruptData: ts.raw("__state?.interruptData"),
|
|
846
|
+
stateStack: opts?.stateStack,
|
|
847
|
+
isForked: opts?.isForked,
|
|
848
|
+
...opts?.extra,
|
|
849
|
+
});
|
|
869
850
|
}
|
|
870
851
|
/**
|
|
871
852
|
* Collect all fields for a class, walking the inheritance chain.
|
|
@@ -1396,14 +1377,12 @@ export class TypeScriptBuilder {
|
|
|
1396
1377
|
}
|
|
1397
1378
|
const callNode = this.processFunctionCall(node);
|
|
1398
1379
|
const scope = this.getCurrentScope();
|
|
1399
|
-
if (this.
|
|
1400
|
-
!this.isGraphNode(node.functionName) &&
|
|
1380
|
+
if (this.shouldHandleInterrupts(node.functionName) &&
|
|
1401
1381
|
scope.type !== "global") {
|
|
1402
1382
|
// Async unassigned calls: register with pending promise store, no interrupt check
|
|
1403
1383
|
if (node.async) {
|
|
1404
|
-
//
|
|
1405
|
-
if (this.
|
|
1406
|
-
!this.isGraphNode(node.functionName)) {
|
|
1384
|
+
// Fork the stack for per-thread isolation
|
|
1385
|
+
if (this.shouldHandleInterrupts(node.functionName)) {
|
|
1407
1386
|
this._asyncBranchCheckNeeded = true;
|
|
1408
1387
|
const branchKey = this._subStepPath.join(".");
|
|
1409
1388
|
let statements = ts.statements(this.forkBranchSetup(branchKey));
|
|
@@ -1488,49 +1467,40 @@ export class TypeScriptBuilder {
|
|
|
1488
1467
|
const functionName = context === "valueAccess"
|
|
1489
1468
|
? node.functionName
|
|
1490
1469
|
: mapFunctionName(node.functionName);
|
|
1491
|
-
const isAgency = this.isAgencyFunction(node.functionName, context);
|
|
1492
1470
|
const shouldAwait = !node.async && context !== "valueAccess";
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
}
|
|
1496
|
-
else if (node.functionName === "system") {
|
|
1471
|
+
// system() is a builder macro — not a real function call
|
|
1472
|
+
if (node.functionName === "system") {
|
|
1497
1473
|
const argNodes = node.arguments.map((a) => this.processCallArg(a));
|
|
1498
1474
|
return $(ts.threads.active())
|
|
1499
1475
|
.prop("push")
|
|
1500
1476
|
.call([ts.smoltalkSystemMessage(argNodes)])
|
|
1501
1477
|
.done();
|
|
1502
1478
|
}
|
|
1503
|
-
|
|
1479
|
+
// __-prefixed helpers and DIRECT_CALL_FUNCTIONS: emit plain direct call
|
|
1480
|
+
if (functionName.startsWith("__") ||
|
|
1481
|
+
TypeScriptBuilder.DIRECT_CALL_FUNCTIONS.has(node.functionName)) {
|
|
1504
1482
|
return this.emitDirectFunctionCall(node, functionName, shouldAwait);
|
|
1505
1483
|
}
|
|
1484
|
+
// Everything else goes through __call runtime dispatch
|
|
1485
|
+
return this.emitRuntimeDispatchCall(node, functionName, shouldAwait, options);
|
|
1506
1486
|
}
|
|
1507
|
-
|
|
1487
|
+
emitRuntimeDispatchCall(node, functionName, shouldAwait, options) {
|
|
1508
1488
|
const descriptor = this.buildCallDescriptor(node);
|
|
1509
1489
|
const locationOpts = node.functionName === "checkpoint" ? {
|
|
1510
1490
|
moduleId: ts.str(this.moduleId),
|
|
1511
1491
|
scopeName: ts.str(this.currentScopeName()),
|
|
1512
1492
|
stepPath: ts.str(this._subStepPath.join(".")),
|
|
1513
|
-
} :
|
|
1514
|
-
const configObj = this.
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
ctx: ts.runtime.ctx,
|
|
1520
|
-
threads: ts.runtime.threads,
|
|
1521
|
-
interruptData: ts.raw("__state?.interruptData"),
|
|
1522
|
-
stateStack: options?.stateStack,
|
|
1523
|
-
isForked: node.async,
|
|
1524
|
-
...locationOpts,
|
|
1525
|
-
});
|
|
1493
|
+
} : undefined;
|
|
1494
|
+
const configObj = this.buildStateConfig({
|
|
1495
|
+
stateStack: options?.stateStack,
|
|
1496
|
+
isForked: node.async,
|
|
1497
|
+
extra: locationOpts,
|
|
1498
|
+
});
|
|
1526
1499
|
const callee = node.scope
|
|
1527
1500
|
? ts.scopedVar(functionName, node.scope, this.moduleId)
|
|
1528
1501
|
: ts.id(functionName);
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1531
|
-
.call([descriptor, configObj])
|
|
1532
|
-
.done();
|
|
1533
|
-
return shouldAwait ? ts.await(invokeCall) : invokeCall;
|
|
1502
|
+
const callExpr = ts.call(ts.id("__call"), [callee, descriptor, configObj]);
|
|
1503
|
+
return shouldAwait ? ts.await(callExpr) : callExpr;
|
|
1534
1504
|
}
|
|
1535
1505
|
emitDirectFunctionCall(node, functionName, shouldAwait) {
|
|
1536
1506
|
const argNodes = node.arguments.map((a) => this.processCallArg(a));
|
|
@@ -1834,9 +1804,8 @@ export class TypeScriptBuilder {
|
|
|
1834
1804
|
this.scopedAssign(node.scope, variableName, this.processNode(value), node.accessChain),
|
|
1835
1805
|
];
|
|
1836
1806
|
if (value.async) {
|
|
1837
|
-
//
|
|
1838
|
-
if (this.
|
|
1839
|
-
!this.isGraphNode(value.functionName)) {
|
|
1807
|
+
// Fork the stack for per-thread isolation
|
|
1808
|
+
if (this.shouldHandleInterrupts(value.functionName)) {
|
|
1840
1809
|
this._asyncBranchCheckNeeded = true;
|
|
1841
1810
|
const branchKey = this._subStepPath.join(".");
|
|
1842
1811
|
stmts.unshift(...this.forkBranchSetup(branchKey));
|
|
@@ -1888,22 +1857,11 @@ export class TypeScriptBuilder {
|
|
|
1888
1857
|
result = ts.index(result, this.processNode(el.index));
|
|
1889
1858
|
break;
|
|
1890
1859
|
case "methodCall": {
|
|
1891
|
-
const
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
? [...callNode.arguments, this.buildMethodCallConfig()]
|
|
1897
|
-
: callNode.arguments;
|
|
1898
|
-
const call2 = $(result)
|
|
1899
|
-
.prop(callNode.callee.name)
|
|
1900
|
-
.call(args)
|
|
1901
|
-
.done();
|
|
1902
|
-
result = isClassMethod ? ts.await(call2) : call2;
|
|
1903
|
-
}
|
|
1904
|
-
else {
|
|
1905
|
-
result = ts.raw(`${this.str(result)}.${this.str(callNode)}`);
|
|
1906
|
-
}
|
|
1860
|
+
const fnCall = el.functionCall;
|
|
1861
|
+
const descriptor = this.buildCallDescriptor(fnCall);
|
|
1862
|
+
const configObj = this.buildStateConfig();
|
|
1863
|
+
const callExpr = ts.call(ts.id("__callMethod"), [result, ts.str(fnCall.functionName), descriptor, configObj]);
|
|
1864
|
+
result = ts.await(callExpr);
|
|
1907
1865
|
break;
|
|
1908
1866
|
}
|
|
1909
1867
|
}
|
|
@@ -2083,20 +2041,17 @@ export class TypeScriptBuilder {
|
|
|
2083
2041
|
}
|
|
2084
2042
|
buildHandlerArrow(handlerName) {
|
|
2085
2043
|
const args = handlerName === "propagate" ? [] : [ts.id("__data")];
|
|
2086
|
-
if (TypeScriptBuilder.
|
|
2044
|
+
if (TypeScriptBuilder.DIRECT_CALL_FUNCTIONS.has(handlerName)) {
|
|
2087
2045
|
// Built-in handler (approve/reject/propagate): plain JS function, call directly
|
|
2088
2046
|
return ts.arrowFn([{ name: "__data", typeAnnotation: "any" }], ts.call(ts.id(handlerName), args), { async: true });
|
|
2089
2047
|
}
|
|
2090
|
-
// User-defined
|
|
2048
|
+
// User-defined function handler: use __call
|
|
2091
2049
|
const descriptor = ts.obj({
|
|
2092
2050
|
type: ts.str("positional"),
|
|
2093
2051
|
args: ts.arr(args),
|
|
2094
2052
|
});
|
|
2095
|
-
const
|
|
2096
|
-
|
|
2097
|
-
.call([descriptor])
|
|
2098
|
-
.done();
|
|
2099
|
-
return ts.arrowFn([{ name: "__data", typeAnnotation: "any" }], ts.await(invokeCall), { async: true });
|
|
2053
|
+
const callExpr = ts.call(ts.id("__call"), [ts.id(handlerName), descriptor, this.buildStateConfig()]);
|
|
2054
|
+
return ts.arrowFn([{ name: "__data", typeAnnotation: "any" }], ts.await(callExpr), { async: true });
|
|
2100
2055
|
}
|
|
2101
2056
|
processHandleBlockWithSteps(node) {
|
|
2102
2057
|
const id = this._subStepPath[this._subStepPath.length - 1];
|
|
@@ -2223,78 +2178,49 @@ export class TypeScriptBuilder {
|
|
|
2223
2178
|
if (placeholderCount !== 1) {
|
|
2224
2179
|
throw new Error(`Method call on right side of |> must contain exactly one ? placeholder, got ${placeholderCount}`);
|
|
2225
2180
|
}
|
|
2226
|
-
// Build the receiver: base + all chain elements except the last method call
|
|
2227
2181
|
const receiver = this.processValueAccessPartial(stage);
|
|
2228
|
-
const
|
|
2182
|
+
const argNodes = methodArgs.map((a) => a.type === "placeholder" ? pipeArg : this.processNode(a));
|
|
2229
2183
|
const methodName = lastElement.functionCall.functionName;
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
});
|
|
2184
|
+
const descriptor = ts.obj({ type: ts.str("positional"), args: ts.arr(argNodes) });
|
|
2185
|
+
const callExpr = ts.call(ts.id("__callMethod"), [receiver, ts.str(methodName), descriptor, this.buildStateConfig()]);
|
|
2186
|
+
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(callExpr), { async: true });
|
|
2234
2187
|
}
|
|
2235
2188
|
}
|
|
2236
|
-
// No placeholder:
|
|
2189
|
+
// No placeholder: bare method/property reference — use __callMethod to preserve `this`
|
|
2190
|
+
const receiver = this.processValueAccessPartial(stage);
|
|
2191
|
+
const lastEl = stage.chain[stage.chain.length - 1];
|
|
2192
|
+
const propName = lastEl.kind === "property" ? lastEl.name
|
|
2193
|
+
: lastEl.kind === "methodCall" ? lastEl.functionCall.functionName
|
|
2194
|
+
: null;
|
|
2195
|
+
if (propName) {
|
|
2196
|
+
const descriptor = ts.obj({ type: ts.str("positional"), args: ts.arr([pipeArg]) });
|
|
2197
|
+
const callExpr = ts.call(ts.id("__callMethod"), [receiver, ts.str(propName), descriptor, this.buildStateConfig()]);
|
|
2198
|
+
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(callExpr), { async: true });
|
|
2199
|
+
}
|
|
2200
|
+
// Fallback for non-property access (e.g. index): use __call
|
|
2237
2201
|
const callee = this.processNode(stage);
|
|
2238
|
-
const
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
});
|
|
2202
|
+
const descriptor = ts.obj({ type: ts.str("positional"), args: ts.arr([pipeArg]) });
|
|
2203
|
+
const callExpr = ts.call(ts.id("__call"), [callee, descriptor, this.buildStateConfig()]);
|
|
2204
|
+
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(callExpr), { async: true });
|
|
2242
2205
|
}
|
|
2243
2206
|
if (stage.type === "variableName") {
|
|
2244
|
-
const isAgency = this.isAgencyFunction(stage.value, "topLevelStatement");
|
|
2245
|
-
if (isAgency) {
|
|
2246
|
-
// value |> fn → async (__pipeArg) => await fn.invoke({ type: "positional", args: [__pipeArg] }, __state)
|
|
2247
|
-
const callee = this.processNode(stage);
|
|
2248
|
-
const descriptor = ts.obj({
|
|
2249
|
-
type: ts.str("positional"),
|
|
2250
|
-
args: ts.arr([pipeArg]),
|
|
2251
|
-
});
|
|
2252
|
-
const stateConfig = ts.functionCallConfig({
|
|
2253
|
-
ctx: ts.runtime.ctx,
|
|
2254
|
-
threads: ts.runtime.threads,
|
|
2255
|
-
interruptData: ts.raw("__state?.interruptData"),
|
|
2256
|
-
});
|
|
2257
|
-
const invokeCall = $(callee).prop("invoke").call([descriptor, stateConfig]).done();
|
|
2258
|
-
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(invokeCall), {
|
|
2259
|
-
async: true,
|
|
2260
|
-
});
|
|
2261
|
-
}
|
|
2262
|
-
// Non-agency: direct call
|
|
2263
2207
|
const callee = this.processNode(stage);
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
});
|
|
2208
|
+
const descriptor = ts.obj({ type: ts.str("positional"), args: ts.arr([pipeArg]) });
|
|
2209
|
+
const callExpr = ts.call(ts.id("__call"), [callee, descriptor, this.buildStateConfig()]);
|
|
2210
|
+
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(callExpr), { async: true });
|
|
2267
2211
|
}
|
|
2268
2212
|
if (stage.type === "functionCall") {
|
|
2269
2213
|
const placeholderCount = stage.arguments.filter((a) => a.type === "placeholder").length;
|
|
2270
2214
|
if (placeholderCount !== 1) {
|
|
2271
2215
|
throw new Error(`Function call on right side of |> must contain exactly one ? placeholder, got ${placeholderCount}`);
|
|
2272
2216
|
}
|
|
2273
|
-
const
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
const descriptor = ts.obj({
|
|
2281
|
-
type: ts.str("positional"),
|
|
2282
|
-
args: ts.arr(argNodes),
|
|
2283
|
-
});
|
|
2284
|
-
const stateConfig = ts.functionCallConfig({
|
|
2285
|
-
ctx: ts.runtime.ctx,
|
|
2286
|
-
threads: ts.runtime.threads,
|
|
2287
|
-
interruptData: ts.raw("__state?.interruptData"),
|
|
2288
|
-
});
|
|
2289
|
-
const invokeCall = $(callee).prop("invoke").call([descriptor, stateConfig]).done();
|
|
2290
|
-
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(invokeCall), {
|
|
2291
|
-
async: true,
|
|
2292
|
-
});
|
|
2293
|
-
}
|
|
2294
|
-
// Non-agency: direct call
|
|
2295
|
-
const rawArgs = stage.arguments.map((a) => a.type === "placeholder" ? pipeArg : this.processNode(a));
|
|
2296
|
-
const callee = ts.raw(mapFunctionName(stage.functionName));
|
|
2297
|
-
return ts.arrowFn([{ name: "__pipeArg" }], ts.call(callee, rawArgs), { async: true });
|
|
2217
|
+
const argNodes = stage.arguments.map((a) => a.type === "placeholder" ? pipeArg : this.processNode(a));
|
|
2218
|
+
const callee = stage.scope
|
|
2219
|
+
? ts.scopedVar(mapFunctionName(stage.functionName), stage.scope, this.moduleId)
|
|
2220
|
+
: ts.raw(mapFunctionName(stage.functionName));
|
|
2221
|
+
const descriptor = ts.obj({ type: ts.str("positional"), args: ts.arr(argNodes) });
|
|
2222
|
+
const callExpr = ts.call(ts.id("__call"), [callee, descriptor, this.buildStateConfig()]);
|
|
2223
|
+
return ts.arrowFn([{ name: "__pipeArg" }], ts.await(callExpr), { async: true });
|
|
2298
2224
|
}
|
|
2299
2225
|
throw new Error(`Invalid pipe stage type: ${stage.type}`);
|
|
2300
2226
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CallType } from "./agencyFunction.js";
|
|
2
|
+
export declare function __call(target: unknown, descriptor: CallType, state?: unknown): Promise<unknown>;
|
|
3
|
+
export declare function __callMethod(obj: unknown, prop: string | number, descriptor: CallType, state?: unknown, optional?: boolean): Promise<unknown>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AgencyFunction } from "./agencyFunction.js";
|
|
2
|
+
export async function __call(target, descriptor, state) {
|
|
3
|
+
if (AgencyFunction.isAgencyFunction(target)) {
|
|
4
|
+
return target.invoke(descriptor, state);
|
|
5
|
+
}
|
|
6
|
+
if (typeof target !== "function") {
|
|
7
|
+
throw new Error(`Cannot call non-function value: ${String(target)}`);
|
|
8
|
+
}
|
|
9
|
+
if (descriptor.type === "named") {
|
|
10
|
+
throw new Error(`Named arguments are not supported for non-Agency function '${target.name || "(anonymous)"}'`);
|
|
11
|
+
}
|
|
12
|
+
return target(...descriptor.args);
|
|
13
|
+
}
|
|
14
|
+
export async function __callMethod(obj, prop, descriptor, state, optional) {
|
|
15
|
+
if (optional && (obj === null || obj === undefined)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const target = obj[prop];
|
|
19
|
+
if (AgencyFunction.isAgencyFunction(target)) {
|
|
20
|
+
return target.invoke(descriptor, state);
|
|
21
|
+
}
|
|
22
|
+
if (typeof target !== "function") {
|
|
23
|
+
throw new Error(`Cannot call non-function value at property '${String(prop)}': ${String(target)}`);
|
|
24
|
+
}
|
|
25
|
+
if (descriptor.type === "named") {
|
|
26
|
+
throw new Error(`Named arguments are not supported for non-Agency function '${String(prop)}'`);
|
|
27
|
+
}
|
|
28
|
+
// Reuse the single property lookup while preserving `this` binding.
|
|
29
|
+
return Reflect.apply(target, obj, descriptor.args);
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { __call, __callMethod } from "./call.js";
|
|
3
|
+
import { AgencyFunction } from "./agencyFunction.js";
|
|
4
|
+
function makeAgencyFn(fn, name = "testFn") {
|
|
5
|
+
return new AgencyFunction({
|
|
6
|
+
name,
|
|
7
|
+
module: "test.agency",
|
|
8
|
+
fn,
|
|
9
|
+
params: [{ name: "x", hasDefault: false, defaultValue: undefined, variadic: false }],
|
|
10
|
+
toolDefinition: null,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
describe("__call", () => {
|
|
14
|
+
it("calls AgencyFunction via .invoke() with descriptor and state", async () => {
|
|
15
|
+
const fn = makeAgencyFn(async (x, state) => ({ x, state }));
|
|
16
|
+
const result = await __call(fn, { type: "positional", args: [42] }, "myState");
|
|
17
|
+
expect(result).toEqual({ x: 42, state: "myState" });
|
|
18
|
+
});
|
|
19
|
+
it("calls plain TS function by spreading positional args", async () => {
|
|
20
|
+
const fn = (a, b) => a + b;
|
|
21
|
+
const result = await __call(fn, { type: "positional", args: [3, 4] });
|
|
22
|
+
expect(result).toBe(7);
|
|
23
|
+
});
|
|
24
|
+
it("throws on named args to a TS function", async () => {
|
|
25
|
+
const fn = (a) => a;
|
|
26
|
+
await expect(__call(fn, { type: "named", positionalArgs: [], namedArgs: { a: 1 } })).rejects.toThrow("Named arguments are not supported");
|
|
27
|
+
});
|
|
28
|
+
it("throws on non-callable target", async () => {
|
|
29
|
+
await expect(__call(42, { type: "positional", args: [] })).rejects.toThrow("Cannot call non-function value");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe("__callMethod", () => {
|
|
33
|
+
it("calls AgencyFunction stored as object property via .invoke()", async () => {
|
|
34
|
+
const fn = makeAgencyFn(async (x, state) => x * 2);
|
|
35
|
+
const obj = { myFunc: fn };
|
|
36
|
+
const result = await __callMethod(obj, "myFunc", { type: "positional", args: [5] });
|
|
37
|
+
expect(result).toBe(10);
|
|
38
|
+
});
|
|
39
|
+
it("calls TS method preserving this binding", async () => {
|
|
40
|
+
const s = new Set();
|
|
41
|
+
await __callMethod(s, "add", { type: "positional", args: [42] });
|
|
42
|
+
expect(s.has(42)).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
it("calls AgencyFunction stored in array by index", async () => {
|
|
45
|
+
const fn = makeAgencyFn(async (x, state) => x + 1);
|
|
46
|
+
const arr = [fn];
|
|
47
|
+
const result = await __callMethod(arr, 0, { type: "positional", args: [10] });
|
|
48
|
+
expect(result).toBe(11);
|
|
49
|
+
});
|
|
50
|
+
it("short-circuits to undefined when optional and obj is null", async () => {
|
|
51
|
+
const result = await __callMethod(null, "foo", { type: "positional", args: [] }, undefined, true);
|
|
52
|
+
expect(result).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
it("short-circuits to undefined when optional and obj is undefined", async () => {
|
|
55
|
+
const result = await __callMethod(undefined, "foo", { type: "positional", args: [] }, undefined, true);
|
|
56
|
+
expect(result).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
it("calls normally when optional and obj is non-nullish", async () => {
|
|
59
|
+
const obj = { greet: (name) => `hi ${name}` };
|
|
60
|
+
const result = await __callMethod(obj, "greet", { type: "positional", args: ["Bob"] }, undefined, true);
|
|
61
|
+
expect(result).toBe("hi Bob");
|
|
62
|
+
});
|
|
63
|
+
it("throws on named args to a TS method", async () => {
|
|
64
|
+
const obj = { fn: (a) => a };
|
|
65
|
+
await expect(__callMethod(obj, "fn", { type: "named", positionalArgs: [], namedArgs: { a: 1 } })).rejects.toThrow("Named arguments are not supported");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -15,6 +15,7 @@ export { deepClone, extractResponse, createReturnObject, updateTokenStats, } fro
|
|
|
15
15
|
export { functionRefReviver } from "./revivers/index.js";
|
|
16
16
|
export { AgencyFunction, UNSET } from "./agencyFunction.js";
|
|
17
17
|
export type { FuncParam, CallType, ToolDefinition, AgencyFunctionOpts } from "./agencyFunction.js";
|
|
18
|
+
export { __call, __callMethod } from "./call.js";
|
|
18
19
|
export { callHook } from "./hooks.js";
|
|
19
20
|
export type { AgencyCallbacks, CallbackMap, CallbackReturn } from "./hooks.js";
|
|
20
21
|
export { not, eq, neq, lt, lte, gt, gte, and, or, head, tail, empty, builtinRead, builtinSleep, readSkill, } from "./builtins.js";
|
|
@@ -10,6 +10,7 @@ export { FileSink, CallbackSink } from "./trace/sinks.js";
|
|
|
10
10
|
export { deepClone, extractResponse, createReturnObject, updateTokenStats, } from "./utils.js";
|
|
11
11
|
export { functionRefReviver } from "./revivers/index.js";
|
|
12
12
|
export { AgencyFunction, UNSET } from "./agencyFunction.js";
|
|
13
|
+
export { __call, __callMethod } from "./call.js";
|
|
13
14
|
export { callHook } from "./hooks.js";
|
|
14
15
|
export { not, eq, neq, lt, lte, gt, gte, and, or, head, tail, empty, builtinRead, builtinSleep, readSkill, } from "./builtins.js";
|
|
15
16
|
export { readSkillTool, readSkillToolParams } from "./builtinTools.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const template = "import { fileURLToPath } from \"url\";\nimport __process from \"process\";\nimport { readFileSync, writeFileSync } from \"fs\";\nimport { z } from \"zod\";\nimport { goToNode, color, nanoid } from \"agency-lang\";\nimport { smoltalk } from \"agency-lang\";\nimport path from \"path\";\nimport type { GraphState, InternalFunctionState, Interrupt, InterruptResponse, RewindCheckpoint } from \"agency-lang/runtime\";\nimport {\n RuntimeContext, MessageThread, ThreadStore, Runner, McpManager,\n setupNode, setupFunction, runNode, runPrompt, callHook,\n checkpoint as __checkpoint_impl, getCheckpoint as __getCheckpoint_impl, restore as __restore_impl,\n interrupt, isInterrupt, isDebugger, isRejected, isApproved, interruptWithHandlers, debugStep,\n respondToInterrupt as _respondToInterrupt,\n approveInterrupt as _approveInterrupt,\n rejectInterrupt as _rejectInterrupt,\n resolveInterrupt as _resolveInterrupt,\n modifyInterrupt as _modifyInterrupt,\n rewindFrom as _rewindFrom,\n RestoreSignal,\n deepClone as __deepClone,\n not, eq, neq, lt, lte, gt, gte, and, or,\n head, tail, empty,\n success, failure, isSuccess, isFailure, __pipeBind, __tryCall, __catchResult,\n Schema, __validateType,\n readSkill as _readSkillRaw,\n readSkillTool as __readSkillTool,\n readSkillToolParams as __readSkillToolParams,\n AgencyFunction as __AgencyFunction, UNSET as __UNSET,\n functionRefReviver as __functionRefReviver,\n} from \"agency-lang/runtime\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\nconst __cwd = __process.cwd();\n\nconst getDirname = () => __dirname;\n\n{{{runtimeContextCode:string}}}\n\n// Path-dependent builtin wrappers\nexport function readSkill({filepath}: {filepath: string}): string {\n return _readSkillRaw({ filepath, dirname: __dirname });\n}\n\n// Handler result builtins\nfunction approve(value?: any) { return { type: \"approved\" as const, value }; }\nfunction reject(value?: any) { return { type: \"rejected\" as const, value }; }\nfunction propagate() { return { type: \"propagated\" as const }; }\n\n// Interrupt and rewind re-exports bound to this module's context\nexport { interrupt, isInterrupt, isDebugger };\nexport const respondToInterrupt = (interrupt: Interrupt, response: InterruptResponse, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _respondToInterrupt({ ctx: __globalCtx, interrupt, interruptResponse: response, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const approveInterrupt = (interrupt: Interrupt, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _approveInterrupt({ ctx: __globalCtx, interrupt, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const rejectInterrupt = (interrupt: Interrupt, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _rejectInterrupt({ ctx: __globalCtx, interrupt, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const modifyInterrupt = (interrupt: Interrupt, newArguments: Record<string, any>, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _modifyInterrupt({ ctx: __globalCtx, interrupt, newArguments, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const resolveInterrupt = (interrupt: Interrupt, value: any, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _resolveInterrupt({ ctx: __globalCtx, interrupt, value, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const rewindFrom = (checkpoint: RewindCheckpoint, overrides: Record<string, unknown>, opts?: { metadata?: Record<string, any> }) => _rewindFrom({ ctx: __globalCtx, checkpoint, overrides, metadata: opts?.metadata });\n\nexport const __setDebugger = (dbg: any) => { __globalCtx.debuggerState = dbg; };\nexport const __setTraceWriter = (tw: any) => { __globalCtx.traceWriter = tw; };\nexport const __getCheckpoints = () => __globalCtx.checkpoints;\n\nconst __toolRegistry: Record<string, any> = {};\n\nfunction __registerTool(value: unknown, name?: string) {\n if (__AgencyFunction.isAgencyFunction(value)) {\n __toolRegistry[name ?? value.name] = value;\n }\n}\n\n// Wrap stateful runtime functions as AgencyFunction instances\nconst checkpoint = __AgencyFunction.create({ name: \"checkpoint\", module: \"__runtime\", fn: __checkpoint_impl, params: [], toolDefinition: null }, __toolRegistry);\nconst getCheckpoint = __AgencyFunction.create({ name: \"getCheckpoint\", module: \"__runtime\", fn: __getCheckpoint_impl, params: [{ name: \"checkpointId\", hasDefault: false, defaultValue: undefined, variadic: false }], toolDefinition: null }, __toolRegistry);\nconst restore = __AgencyFunction.create({ name: \"restore\", module: \"__runtime\", fn: __restore_impl, params: [{ name: \"checkpointIdOrCheckpoint\", hasDefault: false, defaultValue: undefined, variadic: false }, { name: \"options\", hasDefault: false, defaultValue: undefined, variadic: false }], toolDefinition: null }, __toolRegistry);";
|
|
1
|
+
export declare const template = "import { fileURLToPath } from \"url\";\nimport __process from \"process\";\nimport { readFileSync, writeFileSync } from \"fs\";\nimport { z } from \"zod\";\nimport { goToNode, color, nanoid } from \"agency-lang\";\nimport { smoltalk } from \"agency-lang\";\nimport path from \"path\";\nimport type { GraphState, InternalFunctionState, Interrupt, InterruptResponse, RewindCheckpoint } from \"agency-lang/runtime\";\nimport {\n RuntimeContext, MessageThread, ThreadStore, Runner, McpManager,\n setupNode, setupFunction, runNode, runPrompt, callHook,\n checkpoint as __checkpoint_impl, getCheckpoint as __getCheckpoint_impl, restore as __restore_impl,\n interrupt, isInterrupt, isDebugger, isRejected, isApproved, interruptWithHandlers, debugStep,\n respondToInterrupt as _respondToInterrupt,\n approveInterrupt as _approveInterrupt,\n rejectInterrupt as _rejectInterrupt,\n resolveInterrupt as _resolveInterrupt,\n modifyInterrupt as _modifyInterrupt,\n rewindFrom as _rewindFrom,\n RestoreSignal,\n deepClone as __deepClone,\n not, eq, neq, lt, lte, gt, gte, and, or,\n head, tail, empty,\n success, failure, isSuccess, isFailure, __pipeBind, __tryCall, __catchResult,\n Schema, __validateType,\n readSkill as _readSkillRaw,\n readSkillTool as __readSkillTool,\n readSkillToolParams as __readSkillToolParams,\n AgencyFunction as __AgencyFunction, UNSET as __UNSET,\n __call, __callMethod,\n functionRefReviver as __functionRefReviver,\n} from \"agency-lang/runtime\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\nconst __cwd = __process.cwd();\n\nconst getDirname = () => __dirname;\n\n{{{runtimeContextCode:string}}}\n\n// Path-dependent builtin wrappers\nexport function readSkill({filepath}: {filepath: string}): string {\n return _readSkillRaw({ filepath, dirname: __dirname });\n}\n\n// Handler result builtins\nfunction approve(value?: any) { return { type: \"approved\" as const, value }; }\nfunction reject(value?: any) { return { type: \"rejected\" as const, value }; }\nfunction propagate() { return { type: \"propagated\" as const }; }\n\n// Interrupt and rewind re-exports bound to this module's context\nexport { interrupt, isInterrupt, isDebugger };\nexport const respondToInterrupt = (interrupt: Interrupt, response: InterruptResponse, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _respondToInterrupt({ ctx: __globalCtx, interrupt, interruptResponse: response, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const approveInterrupt = (interrupt: Interrupt, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _approveInterrupt({ ctx: __globalCtx, interrupt, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const rejectInterrupt = (interrupt: Interrupt, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _rejectInterrupt({ ctx: __globalCtx, interrupt, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const modifyInterrupt = (interrupt: Interrupt, newArguments: Record<string, any>, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _modifyInterrupt({ ctx: __globalCtx, interrupt, newArguments, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const resolveInterrupt = (interrupt: Interrupt, value: any, opts?: { overrides?: Record<string, unknown>; metadata?: Record<string, any> }) => _resolveInterrupt({ ctx: __globalCtx, interrupt, value, overrides: opts?.overrides, metadata: opts?.metadata });\nexport const rewindFrom = (checkpoint: RewindCheckpoint, overrides: Record<string, unknown>, opts?: { metadata?: Record<string, any> }) => _rewindFrom({ ctx: __globalCtx, checkpoint, overrides, metadata: opts?.metadata });\n\nexport const __setDebugger = (dbg: any) => { __globalCtx.debuggerState = dbg; };\nexport const __setTraceWriter = (tw: any) => { __globalCtx.traceWriter = tw; };\nexport const __getCheckpoints = () => __globalCtx.checkpoints;\n\nconst __toolRegistry: Record<string, any> = {};\n\nfunction __registerTool(value: unknown, name?: string) {\n if (__AgencyFunction.isAgencyFunction(value)) {\n __toolRegistry[name ?? value.name] = value;\n }\n}\n\n// Wrap stateful runtime functions as AgencyFunction instances\nconst checkpoint = __AgencyFunction.create({ name: \"checkpoint\", module: \"__runtime\", fn: __checkpoint_impl, params: [], toolDefinition: null }, __toolRegistry);\nconst getCheckpoint = __AgencyFunction.create({ name: \"getCheckpoint\", module: \"__runtime\", fn: __getCheckpoint_impl, params: [{ name: \"checkpointId\", hasDefault: false, defaultValue: undefined, variadic: false }], toolDefinition: null }, __toolRegistry);\nconst restore = __AgencyFunction.create({ name: \"restore\", module: \"__runtime\", fn: __restore_impl, params: [{ name: \"checkpointIdOrCheckpoint\", hasDefault: false, defaultValue: undefined, variadic: false }, { name: \"options\", hasDefault: false, defaultValue: undefined, variadic: false }], toolDefinition: null }, __toolRegistry);";
|
|
2
2
|
export type TemplateType = {
|
|
3
3
|
runtimeContextCode: string;
|
|
4
4
|
};
|