dirac-lang 0.1.2
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/.env.example +8 -0
- package/COMMUNITY.md +465 -0
- package/LIBRARIES.md +172 -0
- package/NAMESPACES.md +366 -0
- package/PROMOTION.md +257 -0
- package/QUICKSTART-LIBRARY.md +93 -0
- package/README.md +257 -0
- package/config.yml +6 -0
- package/config.yml.openai +4 -0
- package/dirac-http/examples/demo.di +9 -0
- package/dirac-http/lib/index.di +12 -0
- package/dist/chunk-NDIRTD3D.js +217 -0
- package/dist/chunk-S625X7ME.js +1071 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +261 -0
- package/dist/index.d.ts +144 -0
- package/dist/index.js +22 -0
- package/dist/session-4QG7OERD.js +42 -0
- package/examples/add-demo.di +74 -0
- package/examples/add.bk +11 -0
- package/examples/advanced-math-demo.di +53 -0
- package/examples/calculator.di +32 -0
- package/examples/comprehensive.bk +29 -0
- package/examples/defvar-variable-demo.di +18 -0
- package/examples/direct-call.di +17 -0
- package/examples/disk-analysis.di +16 -0
- package/examples/executable-hello.di +7 -0
- package/examples/execute-demo.di +38 -0
- package/examples/file-manager.di +77 -0
- package/examples/file-stats.di +18 -0
- package/examples/hello.bk +1 -0
- package/examples/hello.di +5 -0
- package/examples/import-demo.di +31 -0
- package/examples/inline-test.bk +7 -0
- package/examples/lib/advanced-math.di +81 -0
- package/examples/lib/fileops.di +26 -0
- package/examples/lib/math.di +25 -0
- package/examples/lib/mongodb.di +96 -0
- package/examples/llm-agent.di +32 -0
- package/examples/llm-basic.di +12 -0
- package/examples/llm-command-no-exec.di +13 -0
- package/examples/llm-command.di +13 -0
- package/examples/llm-complex.di +141 -0
- package/examples/llm-recursive.di +31 -0
- package/examples/llm-reflection-test.di +19 -0
- package/examples/llm-subs.di +132 -0
- package/examples/llm-use-subs.di +6 -0
- package/examples/loop.di +12 -0
- package/examples/math-test.di +22 -0
- package/examples/mongodb-count-events.di +8 -0
- package/examples/mongodb-import-demo.di +25 -0
- package/examples/mongodb-simple-test.di +18 -0
- package/examples/nl-agent.di +47 -0
- package/examples/parameters-demo.di +68 -0
- package/examples/params-test.di +10 -0
- package/examples/recipe-chain.di +38 -0
- package/examples/recursive-llm.di +44 -0
- package/examples/sample-library/README.md +152 -0
- package/examples/sample-library/examples/demo.di +34 -0
- package/examples/sample-library/lib/index.di +65 -0
- package/examples/sample-library/package.json +31 -0
- package/examples/seamless.di +45 -0
- package/examples/shell-test.bk +10 -0
- package/examples/simple-import.di +13 -0
- package/examples/simple-recursive.di +26 -0
- package/examples/story-builder.di +45 -0
- package/examples/subroutine.di +23 -0
- package/examples/system-llm.di +21 -0
- package/examples/system-simple.di +3 -0
- package/examples/system-test.di +13 -0
- package/examples/task-assistant.di +27 -0
- package/examples/test-parameters.di +50 -0
- package/examples/two-styles.di +28 -0
- package/examples/var-debug.di +6 -0
- package/examples/var-inline.di +4 -0
- package/examples/var-test2.di +6 -0
- package/examples/variable-simple.di +16 -0
- package/examples/variable-test.di +22 -0
- package/filePath +1 -0
- package/greeting.txt +1 -0
- package/package.json +41 -0
- package/src/cli.ts +118 -0
- package/src/index.ts +33 -0
- package/src/llm/ollama.ts +58 -0
- package/src/runtime/braket-parser.ts +234 -0
- package/src/runtime/interpreter.ts +135 -0
- package/src/runtime/parser.ts +151 -0
- package/src/runtime/session.ts +228 -0
- package/src/tags/assign.ts +37 -0
- package/src/tags/call.ts +156 -0
- package/src/tags/defvar.ts +56 -0
- package/src/tags/eval.ts +68 -0
- package/src/tags/execute.ts +52 -0
- package/src/tags/expr.ts +128 -0
- package/src/tags/if.ts +58 -0
- package/src/tags/import.ts +66 -0
- package/src/tags/index.ts +37 -0
- package/src/tags/llm.ts +207 -0
- package/src/tags/loop.ts +43 -0
- package/src/tags/mongodb.ts +70 -0
- package/src/tags/output.ts +23 -0
- package/src/tags/parameters.ts +79 -0
- package/src/tags/require_module.ts +19 -0
- package/src/tags/subroutine.ts +52 -0
- package/src/tags/system.ts +70 -0
- package/src/tags/variable.ts +25 -0
- package/src/types/index.ts +101 -0
- package/src/utils/llm-adapter.ts +113 -0
- package/tools/create-library.sh +175 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,1071 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cleanToBoundary,
|
|
3
|
+
createSession,
|
|
4
|
+
emit,
|
|
5
|
+
getAvailableSubroutines,
|
|
6
|
+
getCurrentParameters,
|
|
7
|
+
getOutput,
|
|
8
|
+
getSubroutine,
|
|
9
|
+
getVariable,
|
|
10
|
+
popParameters,
|
|
11
|
+
pushParameters,
|
|
12
|
+
registerSubroutine,
|
|
13
|
+
setBoundary,
|
|
14
|
+
setVariable,
|
|
15
|
+
substituteVariables
|
|
16
|
+
} from "./chunk-NDIRTD3D.js";
|
|
17
|
+
|
|
18
|
+
// src/runtime/parser.ts
|
|
19
|
+
import { XMLParser } from "fast-xml-parser";
|
|
20
|
+
var DiracParser = class {
|
|
21
|
+
parser;
|
|
22
|
+
constructor() {
|
|
23
|
+
this.parser = new XMLParser({
|
|
24
|
+
ignoreAttributes: false,
|
|
25
|
+
attributeNamePrefix: "@_",
|
|
26
|
+
trimValues: true,
|
|
27
|
+
parseAttributeValue: false,
|
|
28
|
+
parseTagValue: false,
|
|
29
|
+
textNodeName: "#text",
|
|
30
|
+
cdataPropName: "#cdata",
|
|
31
|
+
preserveOrder: true,
|
|
32
|
+
// Preserve element order!
|
|
33
|
+
commentPropName: "#comment"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
parse(source) {
|
|
37
|
+
if (source.startsWith("#!")) {
|
|
38
|
+
source = source.replace(/^#!.*\n/, "");
|
|
39
|
+
}
|
|
40
|
+
const result = this.parser.parse(source);
|
|
41
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
42
|
+
throw new Error("Empty or invalid XML");
|
|
43
|
+
}
|
|
44
|
+
for (const item of result) {
|
|
45
|
+
if (!item["#comment"]) {
|
|
46
|
+
return this.convertOrderedToElement(item);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
throw new Error("No root element found");
|
|
50
|
+
}
|
|
51
|
+
convertOrderedToElement(obj) {
|
|
52
|
+
const tagName = Object.keys(obj).find((k) => k !== ":@" && k !== "#comment");
|
|
53
|
+
if (!tagName) {
|
|
54
|
+
throw new Error("Invalid element structure");
|
|
55
|
+
}
|
|
56
|
+
const element = {
|
|
57
|
+
tag: tagName,
|
|
58
|
+
attributes: {},
|
|
59
|
+
children: []
|
|
60
|
+
};
|
|
61
|
+
if (obj[":@"]) {
|
|
62
|
+
for (const [key, value] of Object.entries(obj[":@"])) {
|
|
63
|
+
if (key.startsWith("@_")) {
|
|
64
|
+
element.attributes[key.slice(2)] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const children = obj[tagName];
|
|
69
|
+
if (Array.isArray(children)) {
|
|
70
|
+
for (const child of children) {
|
|
71
|
+
if (child["#text"]) {
|
|
72
|
+
element.children.push({
|
|
73
|
+
tag: "",
|
|
74
|
+
text: child["#text"],
|
|
75
|
+
attributes: {},
|
|
76
|
+
children: []
|
|
77
|
+
});
|
|
78
|
+
if (!element.text) {
|
|
79
|
+
element.text = child["#text"];
|
|
80
|
+
} else {
|
|
81
|
+
element.text += child["#text"];
|
|
82
|
+
}
|
|
83
|
+
} else if (child["#comment"]) {
|
|
84
|
+
continue;
|
|
85
|
+
} else {
|
|
86
|
+
element.children.push(this.convertOrderedToElement(child));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return element;
|
|
91
|
+
}
|
|
92
|
+
// Old method - no longer used
|
|
93
|
+
convertToElement(obj, tagName) {
|
|
94
|
+
if (!tagName) {
|
|
95
|
+
const keys = Object.keys(obj);
|
|
96
|
+
if (keys.length === 0) {
|
|
97
|
+
throw new Error("Empty XML");
|
|
98
|
+
}
|
|
99
|
+
tagName = keys[0];
|
|
100
|
+
obj = obj[tagName];
|
|
101
|
+
}
|
|
102
|
+
const element = {
|
|
103
|
+
tag: tagName,
|
|
104
|
+
attributes: {},
|
|
105
|
+
children: []
|
|
106
|
+
};
|
|
107
|
+
if (typeof obj === "string") {
|
|
108
|
+
element.text = obj;
|
|
109
|
+
return element;
|
|
110
|
+
}
|
|
111
|
+
if (!obj) {
|
|
112
|
+
return element;
|
|
113
|
+
}
|
|
114
|
+
for (const key of Object.keys(obj)) {
|
|
115
|
+
const value = obj[key];
|
|
116
|
+
if (key === "#text") {
|
|
117
|
+
element.text = value;
|
|
118
|
+
} else if (key.startsWith("@_")) {
|
|
119
|
+
element.attributes[key.slice(2)] = value;
|
|
120
|
+
} else {
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
for (const item of value) {
|
|
123
|
+
element.children.push(this.convertToElement(item, key));
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
element.children.push(this.convertToElement(value, key));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return element;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/tags/parameters.ts
|
|
135
|
+
async function executeParameters(session, element) {
|
|
136
|
+
const select = element.attributes.select;
|
|
137
|
+
if (!select) {
|
|
138
|
+
throw new Error("<parameters> requires select attribute");
|
|
139
|
+
}
|
|
140
|
+
const params = getCurrentParameters(session);
|
|
141
|
+
if (!params || params.length === 0) {
|
|
142
|
+
if (session.debug) {
|
|
143
|
+
console.error(`[PARAMETERS] No parameters available`);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const caller = params[0];
|
|
148
|
+
if (select === "*") {
|
|
149
|
+
if (session.debug) {
|
|
150
|
+
console.error(`[PARAMETERS] Selecting all children (${caller.children.length} elements)`);
|
|
151
|
+
}
|
|
152
|
+
const prevOutput = session.output;
|
|
153
|
+
session.output = [];
|
|
154
|
+
for (const child of caller.children) {
|
|
155
|
+
await integrate(session, child);
|
|
156
|
+
}
|
|
157
|
+
const captured = session.output.join("");
|
|
158
|
+
session.output = prevOutput;
|
|
159
|
+
return captured;
|
|
160
|
+
} else if (select.startsWith("@")) {
|
|
161
|
+
const attrName = select.slice(1);
|
|
162
|
+
if (attrName === "*") {
|
|
163
|
+
if (session.debug) {
|
|
164
|
+
console.error(`[PARAMETERS] Selecting all attributes`);
|
|
165
|
+
}
|
|
166
|
+
const attrs = Object.entries(caller.attributes).map(([key, val]) => `${key}="${val}"`).join(" ");
|
|
167
|
+
emit(session, attrs);
|
|
168
|
+
} else {
|
|
169
|
+
const value = caller.attributes[attrName];
|
|
170
|
+
if (session.debug) {
|
|
171
|
+
console.error(`[PARAMETERS] Setting variable '${attrName}' = '${value}'`);
|
|
172
|
+
}
|
|
173
|
+
if (value !== void 0) {
|
|
174
|
+
setVariable(session, attrName, value, false);
|
|
175
|
+
console.error(`[PARAMETERS] Variable stack after setting '${attrName}':`, JSON.stringify(session.variables));
|
|
176
|
+
}
|
|
177
|
+
for (const child of element.children) {
|
|
178
|
+
await integrate(session, child);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
throw new Error(`<parameters> invalid select: ${select}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/tags/defvar.ts
|
|
187
|
+
async function executeDefvar(session, element) {
|
|
188
|
+
const name = element.attributes.name;
|
|
189
|
+
const valueAttr = element.attributes.value;
|
|
190
|
+
const visibleAttr = element.attributes.visible || "false";
|
|
191
|
+
const literal = "literal" in element.attributes;
|
|
192
|
+
if (!name) {
|
|
193
|
+
throw new Error("<defvar> requires name attribute");
|
|
194
|
+
}
|
|
195
|
+
const visible = visibleAttr === "true" || visibleAttr === "variable" || visibleAttr === "both";
|
|
196
|
+
let value;
|
|
197
|
+
if (valueAttr !== void 0) {
|
|
198
|
+
value = substituteVariables(session, valueAttr);
|
|
199
|
+
} else if (literal) {
|
|
200
|
+
if (element.text) {
|
|
201
|
+
value = substituteVariables(session, element.text);
|
|
202
|
+
} else {
|
|
203
|
+
value = "";
|
|
204
|
+
}
|
|
205
|
+
} else if (element.children && element.children.length > 0) {
|
|
206
|
+
if (element.children.length === 1 && element.children[0].tag && element.children[0].tag.toLowerCase() === "parameters") {
|
|
207
|
+
value = await executeParameters(session, element.children[0]);
|
|
208
|
+
} else {
|
|
209
|
+
const prevOutput = session.output;
|
|
210
|
+
session.output = [];
|
|
211
|
+
for (const child of element.children) {
|
|
212
|
+
await integrate(session, child);
|
|
213
|
+
}
|
|
214
|
+
value = session.output.join("");
|
|
215
|
+
session.output = prevOutput;
|
|
216
|
+
}
|
|
217
|
+
} else if (element.text) {
|
|
218
|
+
value = substituteVariables(session, element.text);
|
|
219
|
+
} else {
|
|
220
|
+
value = "";
|
|
221
|
+
}
|
|
222
|
+
setVariable(session, name, value, visible);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/tags/variable.ts
|
|
226
|
+
function executeVariable(session, element) {
|
|
227
|
+
const name = element.attributes.name;
|
|
228
|
+
if (!name) {
|
|
229
|
+
console.error("[VariableTagError] <variable> tag missing name attribute:", JSON.stringify(element));
|
|
230
|
+
throw new Error("<variable> requires name attribute");
|
|
231
|
+
}
|
|
232
|
+
const value = getVariable(session, name);
|
|
233
|
+
if (value === void 0) {
|
|
234
|
+
if (session.debug) {
|
|
235
|
+
console.error(`[Warning] Variable '${name}' is undefined`);
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
emit(session, String(value));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/tags/assign.ts
|
|
243
|
+
function executeAssign(session, element) {
|
|
244
|
+
const name = element.attributes.name;
|
|
245
|
+
const valueAttr = element.attributes.value;
|
|
246
|
+
if (!name) {
|
|
247
|
+
throw new Error("<assign> requires name attribute");
|
|
248
|
+
}
|
|
249
|
+
let value;
|
|
250
|
+
if (valueAttr !== void 0) {
|
|
251
|
+
value = substituteVariables(session, valueAttr);
|
|
252
|
+
} else if (element.text) {
|
|
253
|
+
value = substituteVariables(session, element.text);
|
|
254
|
+
} else {
|
|
255
|
+
value = "";
|
|
256
|
+
}
|
|
257
|
+
for (let i = session.variables.length - 1; i >= 0; i--) {
|
|
258
|
+
if (session.variables[i].name === name) {
|
|
259
|
+
session.variables[i].value = value;
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
setVariable(session, name, value, false);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/tags/output.ts
|
|
267
|
+
async function executeOutput(session, element) {
|
|
268
|
+
if (element.children && element.children.length > 0) {
|
|
269
|
+
await integrateChildren(session, element);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (element.text) {
|
|
273
|
+
const content = substituteVariables(session, element.text);
|
|
274
|
+
emit(session, content);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/tags/subroutine.ts
|
|
280
|
+
function executeSubroutine(session, element) {
|
|
281
|
+
const name = element.attributes.name;
|
|
282
|
+
if (!name) {
|
|
283
|
+
throw new Error("<subroutine> requires name attribute");
|
|
284
|
+
}
|
|
285
|
+
const description = element.attributes.description;
|
|
286
|
+
const parameters = [];
|
|
287
|
+
for (const [attrName, attrValue] of Object.entries(element.attributes)) {
|
|
288
|
+
if (attrName.startsWith("param-")) {
|
|
289
|
+
const paramName = attrName.substring(6);
|
|
290
|
+
const parts = attrValue.split(":");
|
|
291
|
+
const paramMeta = {
|
|
292
|
+
name: paramName,
|
|
293
|
+
type: parts[0] || "string",
|
|
294
|
+
required: parts[1] === "required",
|
|
295
|
+
description: parts[2] || void 0
|
|
296
|
+
};
|
|
297
|
+
if (parts[3]) {
|
|
298
|
+
paramMeta.enum = parts[3].split("|");
|
|
299
|
+
}
|
|
300
|
+
parameters.push(paramMeta);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const subroutine = {
|
|
304
|
+
tag: "subroutine",
|
|
305
|
+
attributes: { ...element.attributes },
|
|
306
|
+
children: element.children
|
|
307
|
+
};
|
|
308
|
+
registerSubroutine(session, name, subroutine, description, parameters.length > 0 ? parameters : void 0);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/tags/call.ts
|
|
312
|
+
async function executeCall(session, element) {
|
|
313
|
+
let name;
|
|
314
|
+
if (element.tag === "call") {
|
|
315
|
+
name = element.attributes.name || element.attributes.subroutine || "";
|
|
316
|
+
} else {
|
|
317
|
+
name = element.tag;
|
|
318
|
+
}
|
|
319
|
+
if (!name) {
|
|
320
|
+
throw new Error("<call> requires name or subroutine attribute");
|
|
321
|
+
}
|
|
322
|
+
const subroutine = getSubroutine(session, name);
|
|
323
|
+
if (!subroutine) {
|
|
324
|
+
throw new Error(`Subroutine '${name}' not found`);
|
|
325
|
+
}
|
|
326
|
+
const extendsName = subroutine.attributes.extends;
|
|
327
|
+
if (extendsName) {
|
|
328
|
+
const parent = getSubroutine(session, extendsName);
|
|
329
|
+
if (parent) {
|
|
330
|
+
await executeCallInternal(session, parent, element);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
await executeCallInternal(session, subroutine, element);
|
|
334
|
+
}
|
|
335
|
+
async function executeCallInternal(session, subroutine, callElement) {
|
|
336
|
+
const oldBoundary = setBoundary(session);
|
|
337
|
+
const wasReturn = session.isReturn;
|
|
338
|
+
session.isReturn = false;
|
|
339
|
+
const substitutedElement = {
|
|
340
|
+
tag: callElement.tag,
|
|
341
|
+
attributes: {},
|
|
342
|
+
children: callElement.children
|
|
343
|
+
};
|
|
344
|
+
for (const [key, value] of Object.entries(callElement.attributes)) {
|
|
345
|
+
if (typeof value === "string") {
|
|
346
|
+
substitutedElement.attributes[key] = substituteVariables(session, value);
|
|
347
|
+
} else {
|
|
348
|
+
substitutedElement.attributes[key] = value;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
pushParameters(session, [substitutedElement]);
|
|
352
|
+
try {
|
|
353
|
+
const paramElements = callElement.children.filter((c) => c.tag === "parameters");
|
|
354
|
+
if (paramElements.length > 0) {
|
|
355
|
+
await bindParameters(session, subroutine, paramElements[0]);
|
|
356
|
+
}
|
|
357
|
+
await integrateChildren(session, subroutine);
|
|
358
|
+
} finally {
|
|
359
|
+
popParameters(session);
|
|
360
|
+
session.varBoundary = oldBoundary;
|
|
361
|
+
cleanToBoundary(session);
|
|
362
|
+
session.isReturn = wasReturn;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
async function bindParameters(session, subroutine, callParams) {
|
|
366
|
+
const paramDef = subroutine.children.find((c) => c.tag === "parameters");
|
|
367
|
+
if (!paramDef) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const paramVars = paramDef.children.filter((c) => c.tag === "variable");
|
|
371
|
+
const callVars = callParams.children.filter((c) => c.tag === "variable");
|
|
372
|
+
for (let i = 0; i < paramVars.length; i++) {
|
|
373
|
+
const paramVar = paramVars[i];
|
|
374
|
+
const callVar = callVars[i];
|
|
375
|
+
const paramName = paramVar.attributes.name;
|
|
376
|
+
const passby = paramVar.attributes.passby || "value";
|
|
377
|
+
if (!paramName) continue;
|
|
378
|
+
let value;
|
|
379
|
+
if (callVar) {
|
|
380
|
+
const callValue = callVar.attributes.value;
|
|
381
|
+
if (callValue) {
|
|
382
|
+
if (passby === "ref") {
|
|
383
|
+
setVariable(session, paramName, getVariable(session, callValue), false);
|
|
384
|
+
session.variables[session.variables.length - 1].passby = "ref";
|
|
385
|
+
session.variables[session.variables.length - 1].refName = callValue;
|
|
386
|
+
} else {
|
|
387
|
+
value = substituteVariables(session, callValue);
|
|
388
|
+
setVariable(session, paramName, value, false);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
const defaultValue = paramVar.attributes.default || "";
|
|
393
|
+
value = substituteVariables(session, defaultValue);
|
|
394
|
+
setVariable(session, paramName, value, false);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/tags/loop.ts
|
|
400
|
+
async function executeLoop(session, element) {
|
|
401
|
+
const countAttr = element.attributes.count;
|
|
402
|
+
const varName = element.attributes.var || "i";
|
|
403
|
+
if (!countAttr) {
|
|
404
|
+
throw new Error("<loop> requires count attribute");
|
|
405
|
+
}
|
|
406
|
+
const count = parseInt(substituteVariables(session, countAttr), 10);
|
|
407
|
+
if (isNaN(count) || count < 0) {
|
|
408
|
+
throw new Error(`Invalid loop count: ${countAttr}`);
|
|
409
|
+
}
|
|
410
|
+
const wasBreak = session.isBreak;
|
|
411
|
+
session.isBreak = false;
|
|
412
|
+
for (let i = 0; i < count; i++) {
|
|
413
|
+
setVariable(session, varName, i, false);
|
|
414
|
+
await integrateChildren(session, element);
|
|
415
|
+
if (session.isBreak) {
|
|
416
|
+
session.isBreak = false;
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
if (session.isReturn) {
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
session.isBreak = wasBreak;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/tags/if.ts
|
|
427
|
+
async function executeIf(session, element) {
|
|
428
|
+
const test = element.attributes.test;
|
|
429
|
+
if (!test) {
|
|
430
|
+
throw new Error("<if> requires test attribute");
|
|
431
|
+
}
|
|
432
|
+
const condition = evaluateCondition(session, test);
|
|
433
|
+
if (condition) {
|
|
434
|
+
await integrateChildren(session, element);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function evaluateCondition(session, test) {
|
|
438
|
+
const substituted = substituteVariables(session, test);
|
|
439
|
+
const operators = ["==", "!=", "<=", ">=", "<", ">"];
|
|
440
|
+
for (const op of operators) {
|
|
441
|
+
const parts = substituted.split(op);
|
|
442
|
+
if (parts.length === 2) {
|
|
443
|
+
const left = parts[0].trim();
|
|
444
|
+
const right = parts[1].trim();
|
|
445
|
+
switch (op) {
|
|
446
|
+
case "==":
|
|
447
|
+
return left === right;
|
|
448
|
+
case "!=":
|
|
449
|
+
return left !== right;
|
|
450
|
+
case "<":
|
|
451
|
+
return parseFloat(left) < parseFloat(right);
|
|
452
|
+
case ">":
|
|
453
|
+
return parseFloat(left) > parseFloat(right);
|
|
454
|
+
case "<=":
|
|
455
|
+
return parseFloat(left) <= parseFloat(right);
|
|
456
|
+
case ">=":
|
|
457
|
+
return parseFloat(left) >= parseFloat(right);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return substituted.trim() !== "" && substituted.trim() !== "0" && substituted.trim() !== "false";
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/tags/llm.ts
|
|
465
|
+
async function executeLLM(session, element) {
|
|
466
|
+
if (!session.llmClient) {
|
|
467
|
+
throw new Error("<LLM> requires API key (set OPENAI_API_KEY, ANTHROPIC_API_KEY, or LLM_PROVIDER=ollama in .env file)");
|
|
468
|
+
}
|
|
469
|
+
if (session.limits.currentLLMCalls >= session.limits.maxLLMCalls) {
|
|
470
|
+
throw new Error("Maximum LLM calls exceeded");
|
|
471
|
+
}
|
|
472
|
+
session.limits.currentLLMCalls++;
|
|
473
|
+
const providerName = session.llmClient.constructor.name;
|
|
474
|
+
const isOpenAI = providerName === "OpenAI";
|
|
475
|
+
const isOllama = providerName === "OllamaProvider";
|
|
476
|
+
const defaultModel = isOpenAI ? "gpt-4.1-2025-04-14" : isOllama ? "llama2" : "claude-sonnet-4-20250514";
|
|
477
|
+
console.log("LLM Provider:", providerName);
|
|
478
|
+
const model = element.attributes.model || process.env.DEFAULT_MODEL || defaultModel;
|
|
479
|
+
console.log("LLM Model:", model);
|
|
480
|
+
const outputVar = element.attributes.output;
|
|
481
|
+
const contextVar = element.attributes.context;
|
|
482
|
+
const executeMode = element.attributes.execute === "true";
|
|
483
|
+
const temperature = parseFloat(element.attributes.temperature || "1.0");
|
|
484
|
+
const maxTokens = parseInt(element.attributes.maxTokens || "4096", 10);
|
|
485
|
+
let userPrompt = "";
|
|
486
|
+
if (element.children.length > 0) {
|
|
487
|
+
const beforeOutput = session.output.length;
|
|
488
|
+
for (const child of element.children) {
|
|
489
|
+
await integrate(session, child);
|
|
490
|
+
}
|
|
491
|
+
const childOutput = session.output.slice(beforeOutput);
|
|
492
|
+
userPrompt = childOutput.join("");
|
|
493
|
+
session.output = session.output.slice(0, beforeOutput);
|
|
494
|
+
} else if (element.text) {
|
|
495
|
+
userPrompt = substituteVariables(session, element.text);
|
|
496
|
+
} else {
|
|
497
|
+
throw new Error("<LLM> requires prompt content");
|
|
498
|
+
}
|
|
499
|
+
const noExtra = element.attributes.noextra === "true";
|
|
500
|
+
let prompt;
|
|
501
|
+
if (noExtra) {
|
|
502
|
+
prompt = userPrompt;
|
|
503
|
+
if (session.debug || process.env.DIRAC_LOG_PROMPT === "1") {
|
|
504
|
+
console.error("[LLM] Full prompt sent to LLM (noextra):\n" + prompt + "\n");
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
const { getAvailableSubroutines: getAvailableSubroutines2 } = await import("./session-4QG7OERD.js");
|
|
508
|
+
const subroutines = getAvailableSubroutines2(session);
|
|
509
|
+
if (session.debug) {
|
|
510
|
+
console.error(
|
|
511
|
+
"[LLM] Subroutines available at prompt composition:",
|
|
512
|
+
subroutines.map((s) => ({ name: s.name, description: s.description, parameters: s.parameters }))
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
let systemPrompt = `Dirac is a XML based language, you define the subroutine like
|
|
516
|
+
\`\`\`xml
|
|
517
|
+
<subroutine name=background >
|
|
518
|
+
<parameters select="@color" />
|
|
519
|
+
<paint_the_color_somewhere />
|
|
520
|
+
</subroutine>
|
|
521
|
+
\`\`\`
|
|
522
|
+
then you call it like
|
|
523
|
+
\`\`\`xml
|
|
524
|
+
<background color="blue" />
|
|
525
|
+
\`\`\`
|
|
526
|
+
`;
|
|
527
|
+
systemPrompt += "Now, You are an expert Dirac XML code generator.\nAllowed Dirac XML tags (use ONLY these tags):";
|
|
528
|
+
for (const sub of subroutines) {
|
|
529
|
+
systemPrompt += `
|
|
530
|
+
- <${sub.name} />: ${sub.description || ""}`;
|
|
531
|
+
if (sub.parameters && sub.parameters.length > 0) {
|
|
532
|
+
systemPrompt += " Parameters: " + sub.parameters.map((p) => `${p.name} (${p.type || "string"})`).join(", ");
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
systemPrompt += "\nDo NOT invent or use any tags not listed above. For example, do NOT use <changeBackground> or <set-background>. Only use the allowed tags.\nInstructions: Output only valid Dirac XML tags from the list above. Do not include explanations or extra text.";
|
|
536
|
+
systemPrompt += "\nAfter generating your answer, check the command/tag list again and ensure every tag you use is in the list above. If any tag is not in the list, do not output it\u2014regenerate your answer using only allowed tags.";
|
|
537
|
+
prompt = systemPrompt + "\nUser: " + userPrompt + "\nOutput:";
|
|
538
|
+
if (session.debug || process.env.DIRAC_LOG_PROMPT === "1") {
|
|
539
|
+
console.error("[LLM] Full prompt sent to LLM:\n" + prompt + "\n");
|
|
540
|
+
}
|
|
541
|
+
if (contextVar) {
|
|
542
|
+
const contextValue = getVariable(session, contextVar);
|
|
543
|
+
if (contextValue) {
|
|
544
|
+
prompt = `Context: ${contextValue}
|
|
545
|
+
|
|
546
|
+
${prompt}`;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (session.debug) {
|
|
551
|
+
console.error(`[LLM] Calling ${model} with prompt length: ${prompt.length}`);
|
|
552
|
+
}
|
|
553
|
+
try {
|
|
554
|
+
let result;
|
|
555
|
+
if (isOpenAI) {
|
|
556
|
+
const response = await session.llmClient.chat.completions.create({
|
|
557
|
+
model,
|
|
558
|
+
max_tokens: maxTokens,
|
|
559
|
+
temperature,
|
|
560
|
+
messages: [
|
|
561
|
+
{
|
|
562
|
+
role: "user",
|
|
563
|
+
content: prompt
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
});
|
|
567
|
+
result = response.choices[0]?.message?.content || "";
|
|
568
|
+
} else if (isOllama) {
|
|
569
|
+
result = await session.llmClient.complete(prompt, {
|
|
570
|
+
model,
|
|
571
|
+
temperature,
|
|
572
|
+
max_tokens: maxTokens
|
|
573
|
+
});
|
|
574
|
+
} else {
|
|
575
|
+
const response = await session.llmClient.messages.create({
|
|
576
|
+
model,
|
|
577
|
+
max_tokens: maxTokens,
|
|
578
|
+
temperature,
|
|
579
|
+
messages: [
|
|
580
|
+
{
|
|
581
|
+
role: "user",
|
|
582
|
+
content: prompt
|
|
583
|
+
}
|
|
584
|
+
]
|
|
585
|
+
});
|
|
586
|
+
const content = response.content[0];
|
|
587
|
+
result = content.type === "text" ? content.text : "";
|
|
588
|
+
}
|
|
589
|
+
if (session.debug) {
|
|
590
|
+
console.error(`[LLM] Response length: ${result.length}`);
|
|
591
|
+
}
|
|
592
|
+
if (outputVar) {
|
|
593
|
+
setVariable(session, outputVar, result, false);
|
|
594
|
+
} else if (executeMode) {
|
|
595
|
+
if (session.debug) {
|
|
596
|
+
console.error(`[LLM] Executing response as Dirac code:
|
|
597
|
+
${result}
|
|
598
|
+
`);
|
|
599
|
+
}
|
|
600
|
+
const replaceTick = element.attributes["replace-tick"] === "true";
|
|
601
|
+
let diracCode = result.trim();
|
|
602
|
+
if (replaceTick && diracCode.startsWith("```")) {
|
|
603
|
+
const match = diracCode.match(/^```(\w+)?\n?/m);
|
|
604
|
+
if (match && match[1] === "bash") {
|
|
605
|
+
const endIdx = diracCode.indexOf("```", 3);
|
|
606
|
+
let bashContent = diracCode.slice(match[0].length, endIdx).trim();
|
|
607
|
+
diracCode = `<system>${bashContent}</system>`;
|
|
608
|
+
} else {
|
|
609
|
+
diracCode = diracCode.replace(/^```(?:xml|html|dirac)?\n?/m, "").replace(/\n?```$/m, "").trim();
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
try {
|
|
613
|
+
const parser = new DiracParser();
|
|
614
|
+
const dynamicAST = parser.parse(diracCode);
|
|
615
|
+
await integrate(session, dynamicAST);
|
|
616
|
+
} catch (parseError) {
|
|
617
|
+
if (session.debug) {
|
|
618
|
+
console.error(`[LLM] Failed to parse as Dirac, treating as text: ${parseError}`);
|
|
619
|
+
}
|
|
620
|
+
emit(session, result);
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
emit(session, result);
|
|
624
|
+
}
|
|
625
|
+
} catch (error) {
|
|
626
|
+
throw new Error(`LLM error: ${error instanceof Error ? error.message : String(error)}`);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/tags/eval.ts
|
|
631
|
+
var AsyncFunction = Object.getPrototypeOf(async function() {
|
|
632
|
+
}).constructor;
|
|
633
|
+
async function executeEval(session, element) {
|
|
634
|
+
const name = element.attributes.name;
|
|
635
|
+
const exprAttr = element.attributes.expr;
|
|
636
|
+
let expr;
|
|
637
|
+
if (exprAttr) {
|
|
638
|
+
expr = exprAttr.replace(/\$\{(\w+)\}/g, "$1");
|
|
639
|
+
} else if (element.text) {
|
|
640
|
+
expr = element.text.replace(/\$\{(\w+)\}/g, "$1");
|
|
641
|
+
} else {
|
|
642
|
+
throw new Error("<eval> requires expr attribute or text content");
|
|
643
|
+
}
|
|
644
|
+
if (session.debug) {
|
|
645
|
+
console.error(`[EVAL] Code after substitution:
|
|
646
|
+
${expr}
|
|
647
|
+
`);
|
|
648
|
+
}
|
|
649
|
+
try {
|
|
650
|
+
const context = {};
|
|
651
|
+
for (const v of session.variables) {
|
|
652
|
+
context[v.name] = v.value;
|
|
653
|
+
}
|
|
654
|
+
const { default: fs } = await import("fs");
|
|
655
|
+
const { default: path } = await import("path");
|
|
656
|
+
const { fileURLToPath } = await import("url");
|
|
657
|
+
context.fs = fs;
|
|
658
|
+
context.path = path;
|
|
659
|
+
context.__dirname = process.cwd();
|
|
660
|
+
context.getParams = () => {
|
|
661
|
+
const params = session.parameterStack[session.parameterStack.length - 1];
|
|
662
|
+
return params && params[0] ? params[0] : null;
|
|
663
|
+
};
|
|
664
|
+
let result;
|
|
665
|
+
const func = new AsyncFunction(...Object.keys(context), expr);
|
|
666
|
+
result = await func(...Object.values(context));
|
|
667
|
+
if (session.debug) {
|
|
668
|
+
console.error(`[EVAL] Result: ${JSON.stringify(result)}`);
|
|
669
|
+
}
|
|
670
|
+
if (name) {
|
|
671
|
+
setVariable(session, name, result, false);
|
|
672
|
+
}
|
|
673
|
+
} catch (error) {
|
|
674
|
+
throw new Error(`Eval error: ${error instanceof Error ? error.message : String(error)}`);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// src/tags/execute.ts
|
|
679
|
+
async function executeExecute(session, element) {
|
|
680
|
+
const sourceAttr = element.attributes.source;
|
|
681
|
+
let diracCode;
|
|
682
|
+
if (sourceAttr) {
|
|
683
|
+
diracCode = getVariable(session, sourceAttr);
|
|
684
|
+
if (!diracCode) {
|
|
685
|
+
throw new Error(`<execute> source variable '${sourceAttr}' not found`);
|
|
686
|
+
}
|
|
687
|
+
} else if (element.text) {
|
|
688
|
+
diracCode = substituteVariables(session, element.text);
|
|
689
|
+
} else {
|
|
690
|
+
throw new Error("<execute> requires source attribute or text content");
|
|
691
|
+
}
|
|
692
|
+
if (session.debug) {
|
|
693
|
+
console.error(`[EXECUTE] Interpreting dynamic code:
|
|
694
|
+
${diracCode}
|
|
695
|
+
`);
|
|
696
|
+
}
|
|
697
|
+
diracCode = diracCode.trim();
|
|
698
|
+
if (diracCode.startsWith("```")) {
|
|
699
|
+
diracCode = diracCode.replace(/^```(?:xml|html)?\n?/m, "").replace(/\n?```$/m, "").trim();
|
|
700
|
+
}
|
|
701
|
+
try {
|
|
702
|
+
const parser = new DiracParser();
|
|
703
|
+
const dynamicAST = parser.parse(diracCode);
|
|
704
|
+
await integrate(session, dynamicAST);
|
|
705
|
+
} catch (error) {
|
|
706
|
+
throw new Error(`Execute error: ${error instanceof Error ? error.message : String(error)}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/tags/import.ts
|
|
711
|
+
import { readFileSync } from "fs";
|
|
712
|
+
import { resolve, dirname } from "path";
|
|
713
|
+
async function executeImport(session, element) {
|
|
714
|
+
const src = element.attributes.src;
|
|
715
|
+
if (!src) {
|
|
716
|
+
throw new Error("<import> requires src attribute");
|
|
717
|
+
}
|
|
718
|
+
const currentDir = session.currentFile ? dirname(session.currentFile) : process.cwd();
|
|
719
|
+
const importPath = resolve(currentDir, src);
|
|
720
|
+
if (session.debug) {
|
|
721
|
+
console.error(`[IMPORT] Loading: ${importPath}`);
|
|
722
|
+
}
|
|
723
|
+
if (!session.importedFiles) {
|
|
724
|
+
session.importedFiles = /* @__PURE__ */ new Set();
|
|
725
|
+
}
|
|
726
|
+
if (session.importedFiles.has(importPath)) {
|
|
727
|
+
if (session.debug) {
|
|
728
|
+
console.error(`[IMPORT] Already imported: ${importPath}`);
|
|
729
|
+
}
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
session.importedFiles.add(importPath);
|
|
733
|
+
try {
|
|
734
|
+
const source = readFileSync(importPath, "utf-8");
|
|
735
|
+
const parser = new DiracParser();
|
|
736
|
+
const ast = parser.parse(source);
|
|
737
|
+
const previousFile = session.currentFile;
|
|
738
|
+
session.currentFile = importPath;
|
|
739
|
+
await integrate(session, ast);
|
|
740
|
+
session.currentFile = previousFile;
|
|
741
|
+
if (session.debug) {
|
|
742
|
+
console.error(`[IMPORT] Loaded: ${importPath}`);
|
|
743
|
+
}
|
|
744
|
+
} catch (error) {
|
|
745
|
+
throw new Error(`Import error: ${error instanceof Error ? error.message : String(error)}`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/tags/expr.ts
|
|
750
|
+
async function executeExpr(session, element) {
|
|
751
|
+
const op = element.attributes.eval || element.attributes.op;
|
|
752
|
+
if (!op) {
|
|
753
|
+
throw new Error("<expr> requires eval or op attribute");
|
|
754
|
+
}
|
|
755
|
+
const args = [];
|
|
756
|
+
const stringArgs = [];
|
|
757
|
+
for (const child of element.children) {
|
|
758
|
+
if (child.tag === "arg") {
|
|
759
|
+
let argValue = "";
|
|
760
|
+
if (child.text) {
|
|
761
|
+
argValue = substituteVariables(session, child.text);
|
|
762
|
+
} else {
|
|
763
|
+
const oldOutput = session.output;
|
|
764
|
+
session.output = [];
|
|
765
|
+
for (const argChild of child.children) {
|
|
766
|
+
await integrate(session, argChild);
|
|
767
|
+
}
|
|
768
|
+
argValue = session.output.join("");
|
|
769
|
+
session.output = oldOutput;
|
|
770
|
+
}
|
|
771
|
+
stringArgs.push(argValue);
|
|
772
|
+
const numValue = parseFloat(argValue);
|
|
773
|
+
args.push(isNaN(numValue) ? 0 : numValue);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
let result = 0;
|
|
777
|
+
switch (op.toLowerCase()) {
|
|
778
|
+
case "plus":
|
|
779
|
+
case "add":
|
|
780
|
+
result = args.reduce((a, b) => a + b, 0);
|
|
781
|
+
break;
|
|
782
|
+
case "minus":
|
|
783
|
+
case "subtract":
|
|
784
|
+
result = args.length > 0 ? args[0] - args.slice(1).reduce((a, b) => a + b, 0) : 0;
|
|
785
|
+
break;
|
|
786
|
+
case "times":
|
|
787
|
+
case "multiply":
|
|
788
|
+
case "mul":
|
|
789
|
+
result = args.reduce((a, b) => a * b, 1);
|
|
790
|
+
break;
|
|
791
|
+
case "divide":
|
|
792
|
+
case "div":
|
|
793
|
+
if (args.length >= 2 && args[1] !== 0) {
|
|
794
|
+
result = args[0] / args[1];
|
|
795
|
+
} else {
|
|
796
|
+
result = 0;
|
|
797
|
+
}
|
|
798
|
+
break;
|
|
799
|
+
case "mod":
|
|
800
|
+
case "modulo":
|
|
801
|
+
if (args.length >= 2 && args[1] !== 0) {
|
|
802
|
+
result = args[0] % args[1];
|
|
803
|
+
} else {
|
|
804
|
+
result = 0;
|
|
805
|
+
}
|
|
806
|
+
break;
|
|
807
|
+
case "lt":
|
|
808
|
+
case "less":
|
|
809
|
+
result = args.length >= 2 ? args[0] < args[1] : false;
|
|
810
|
+
break;
|
|
811
|
+
case "gt":
|
|
812
|
+
case "greater":
|
|
813
|
+
result = args.length >= 2 ? args[0] > args[1] : false;
|
|
814
|
+
break;
|
|
815
|
+
case "eq":
|
|
816
|
+
case "equal":
|
|
817
|
+
result = args.length >= 2 ? args[0] === args[1] : false;
|
|
818
|
+
break;
|
|
819
|
+
case "and":
|
|
820
|
+
result = args.every((a) => a !== 0);
|
|
821
|
+
break;
|
|
822
|
+
case "or":
|
|
823
|
+
result = args.some((a) => a !== 0);
|
|
824
|
+
break;
|
|
825
|
+
case "not":
|
|
826
|
+
result = args.length > 0 ? args[0] === 0 : true;
|
|
827
|
+
break;
|
|
828
|
+
case "same":
|
|
829
|
+
case "strcmp":
|
|
830
|
+
result = stringArgs.length >= 2 ? stringArgs[0] === stringArgs[1] : false;
|
|
831
|
+
break;
|
|
832
|
+
default:
|
|
833
|
+
throw new Error(`<expr> unknown operation: ${op}`);
|
|
834
|
+
}
|
|
835
|
+
if (typeof result === "boolean") {
|
|
836
|
+
emit(session, result ? "1" : "0");
|
|
837
|
+
} else {
|
|
838
|
+
emit(session, String(result));
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// src/tags/system.ts
|
|
843
|
+
import { exec } from "child_process";
|
|
844
|
+
import { promisify } from "util";
|
|
845
|
+
var execAsync = promisify(exec);
|
|
846
|
+
async function executeSystem(session, element) {
|
|
847
|
+
let command;
|
|
848
|
+
const hasElementChildren = element.children.some((child) => child.tag !== "");
|
|
849
|
+
if (hasElementChildren) {
|
|
850
|
+
const beforeOutput = session.output.length;
|
|
851
|
+
for (const child of element.children) {
|
|
852
|
+
await integrate(session, child);
|
|
853
|
+
}
|
|
854
|
+
const childOutput = session.output.slice(beforeOutput);
|
|
855
|
+
command = childOutput.join("");
|
|
856
|
+
session.output = session.output.slice(0, beforeOutput);
|
|
857
|
+
} else if (element.text) {
|
|
858
|
+
command = substituteVariables(session, element.text);
|
|
859
|
+
} else {
|
|
860
|
+
throw new Error("<system> requires command content");
|
|
861
|
+
}
|
|
862
|
+
if (!command.trim()) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (session.debug) {
|
|
866
|
+
console.error(`[SYSTEM] Executing: ${command}`);
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
870
|
+
encoding: "utf-8",
|
|
871
|
+
maxBuffer: 10 * 1024 * 1024
|
|
872
|
+
// 10MB buffer
|
|
873
|
+
});
|
|
874
|
+
if (stdout) {
|
|
875
|
+
emit(session, stdout);
|
|
876
|
+
}
|
|
877
|
+
if (stderr && session.debug) {
|
|
878
|
+
console.error(`[SYSTEM STDERR] ${stderr}`);
|
|
879
|
+
}
|
|
880
|
+
} catch (error) {
|
|
881
|
+
const errorMsg = error.message || String(error);
|
|
882
|
+
throw new Error(`System command failed: ${errorMsg}`);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// src/tags/require_module.ts
|
|
887
|
+
async function executeRequireModule(session, element) {
|
|
888
|
+
const name = element.attributes.name;
|
|
889
|
+
const varName = element.attributes.var || name;
|
|
890
|
+
if (!name) throw new Error("<require_module> missing name attribute");
|
|
891
|
+
try {
|
|
892
|
+
const mod = await import(name);
|
|
893
|
+
setVariable(session, varName, mod, true);
|
|
894
|
+
} catch (err) {
|
|
895
|
+
throw new Error(`<require_module> failed to load module '${name}': ${err}`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// src/runtime/interpreter.ts
|
|
900
|
+
async function integrate(session, element) {
|
|
901
|
+
if (session.limits.currentDepth >= session.limits.maxDepth) {
|
|
902
|
+
throw new Error("Maximum execution depth exceeded");
|
|
903
|
+
}
|
|
904
|
+
session.limits.currentDepth++;
|
|
905
|
+
try {
|
|
906
|
+
if (element.text && !element.tag) {
|
|
907
|
+
const substituted = substituteVariables(session, element.text);
|
|
908
|
+
emit(session, substituted);
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
if (session.isReturn || session.isBreak) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
switch (element.tag.toLowerCase()) {
|
|
915
|
+
case "defvar":
|
|
916
|
+
await executeDefvar(session, element);
|
|
917
|
+
break;
|
|
918
|
+
case "variable":
|
|
919
|
+
await executeVariable(session, element);
|
|
920
|
+
break;
|
|
921
|
+
case "assign":
|
|
922
|
+
await executeAssign(session, element);
|
|
923
|
+
break;
|
|
924
|
+
case "output":
|
|
925
|
+
await executeOutput(session, element);
|
|
926
|
+
break;
|
|
927
|
+
case "subroutine":
|
|
928
|
+
await executeSubroutine(session, element);
|
|
929
|
+
break;
|
|
930
|
+
case "call":
|
|
931
|
+
await executeCall(session, element);
|
|
932
|
+
break;
|
|
933
|
+
case "loop":
|
|
934
|
+
await executeLoop(session, element);
|
|
935
|
+
break;
|
|
936
|
+
case "if":
|
|
937
|
+
await executeIf(session, element);
|
|
938
|
+
break;
|
|
939
|
+
case "llm":
|
|
940
|
+
await executeLLM(session, element);
|
|
941
|
+
break;
|
|
942
|
+
case "eval":
|
|
943
|
+
await executeEval(session, element);
|
|
944
|
+
break;
|
|
945
|
+
case "execute":
|
|
946
|
+
await executeExecute(session, element);
|
|
947
|
+
break;
|
|
948
|
+
case "import":
|
|
949
|
+
await executeImport(session, element);
|
|
950
|
+
break;
|
|
951
|
+
case "parameters":
|
|
952
|
+
await executeParameters(session, element);
|
|
953
|
+
break;
|
|
954
|
+
case "expr":
|
|
955
|
+
await executeExpr(session, element);
|
|
956
|
+
break;
|
|
957
|
+
case "system":
|
|
958
|
+
await executeSystem(session, element);
|
|
959
|
+
break;
|
|
960
|
+
case "require_module":
|
|
961
|
+
await executeRequireModule(session, element);
|
|
962
|
+
break;
|
|
963
|
+
default:
|
|
964
|
+
const subroutine = getSubroutine(session, element.tag);
|
|
965
|
+
if (subroutine) {
|
|
966
|
+
await executeCall(session, element);
|
|
967
|
+
} else {
|
|
968
|
+
for (const child of element.children) {
|
|
969
|
+
await integrate(session, child);
|
|
970
|
+
if (session.isReturn || session.isBreak) break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
} finally {
|
|
975
|
+
session.limits.currentDepth--;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async function integrateChildren(session, element) {
|
|
979
|
+
for (const child of element.children) {
|
|
980
|
+
await integrate(session, child);
|
|
981
|
+
if (session.isReturn || session.isBreak) break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/utils/llm-adapter.ts
|
|
986
|
+
function createLLMAdapter(session) {
|
|
987
|
+
const subroutines = getAvailableSubroutines(session);
|
|
988
|
+
const actions = subroutines.map((s) => `"${s.name}"`).join("|");
|
|
989
|
+
const examples = subroutines.slice(0, 3).map((sub) => {
|
|
990
|
+
if (!sub.parameters || sub.parameters.length === 0) {
|
|
991
|
+
return `"${sub.name}" \u2192 {"action":"${sub.name}","params":{}}`;
|
|
992
|
+
}
|
|
993
|
+
const firstParam = sub.parameters[0];
|
|
994
|
+
const exampleValue = firstParam.enum?.[0] || "value";
|
|
995
|
+
return `"call ${sub.name}" \u2192 {"action":"${sub.name}","params":{"${firstParam.name}":"${exampleValue}"}}`;
|
|
996
|
+
}).join("\n");
|
|
997
|
+
return {
|
|
998
|
+
generatePrompt(userInput) {
|
|
999
|
+
return `You are a command parser. Convert user input to JSON.
|
|
1000
|
+
Return ONLY valid JSON, no other text.
|
|
1001
|
+
|
|
1002
|
+
Format: {"action": ${actions}, "params": {}}
|
|
1003
|
+
|
|
1004
|
+
Examples:
|
|
1005
|
+
${examples}
|
|
1006
|
+
|
|
1007
|
+
User: ${userInput}
|
|
1008
|
+
JSON:`;
|
|
1009
|
+
},
|
|
1010
|
+
intentToXML(intent) {
|
|
1011
|
+
if (!intent || !intent.action) return null;
|
|
1012
|
+
const sub = subroutines.find((s) => s.name === intent.action);
|
|
1013
|
+
if (!sub) return null;
|
|
1014
|
+
const attrs = [`name="${sub.name}"`];
|
|
1015
|
+
if (sub.parameters) {
|
|
1016
|
+
for (const param of sub.parameters) {
|
|
1017
|
+
const value = intent.params?.[param.name];
|
|
1018
|
+
if (value != null) {
|
|
1019
|
+
if (param.enum && !param.enum.includes(value)) {
|
|
1020
|
+
return null;
|
|
1021
|
+
}
|
|
1022
|
+
attrs.push(`${param.name}="${value}"`);
|
|
1023
|
+
} else if (param.required) {
|
|
1024
|
+
return null;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
return `<call ${attrs.join(" ")}/>`;
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
async function executeUserCommand(session, userInput, llmExecuteFn) {
|
|
1033
|
+
try {
|
|
1034
|
+
const adapter = createLLMAdapter(session);
|
|
1035
|
+
const prompt = adapter.generatePrompt(userInput);
|
|
1036
|
+
const llmResponse = await llmExecuteFn(prompt);
|
|
1037
|
+
let jsonStr = llmResponse.trim();
|
|
1038
|
+
jsonStr = jsonStr.replace(/```json\s*/g, "").replace(/```\s*/g, "");
|
|
1039
|
+
const intent = JSON.parse(jsonStr);
|
|
1040
|
+
const xml = adapter.intentToXML(intent);
|
|
1041
|
+
if (!xml) {
|
|
1042
|
+
return { success: false, error: "Could not convert intent to valid command" };
|
|
1043
|
+
}
|
|
1044
|
+
return { success: true, xml };
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
return {
|
|
1047
|
+
success: false,
|
|
1048
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// src/index.ts
|
|
1054
|
+
async function execute(source, config = {}) {
|
|
1055
|
+
const parser = new DiracParser();
|
|
1056
|
+
const session = createSession(config);
|
|
1057
|
+
if (config.filePath) {
|
|
1058
|
+
session.currentFile = config.filePath;
|
|
1059
|
+
}
|
|
1060
|
+
const ast = parser.parse(source);
|
|
1061
|
+
await integrate(session, ast);
|
|
1062
|
+
return getOutput(session);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
export {
|
|
1066
|
+
DiracParser,
|
|
1067
|
+
integrate,
|
|
1068
|
+
createLLMAdapter,
|
|
1069
|
+
executeUserCommand,
|
|
1070
|
+
execute
|
|
1071
|
+
};
|