dirac-lang 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/dist/cli.js +13 -1
  2. package/lib/index.di +9 -0
  3. package/{examples/lib → lib}/math.di +3 -3
  4. package/package.json +13 -1
  5. package/.env.example +0 -8
  6. package/COMMUNITY.md +0 -465
  7. package/CONDITIONAL-TAGS.md +0 -172
  8. package/EXCEPTION-HANDLING.md +0 -156
  9. package/LIBRARIES.md +0 -172
  10. package/LLM-VALIDATION.md +0 -128
  11. package/NAMESPACES.md +0 -366
  12. package/PROMOTION.md +0 -257
  13. package/QUICKSTART-LIBRARY.md +0 -93
  14. package/TEST-COVERAGE.md +0 -113
  15. package/TESTING.md +0 -162
  16. package/config.test.yml +0 -5
  17. package/dirac-http/examples/demo.di +0 -9
  18. package/dirac-http/lib/index.di +0 -12
  19. package/examples/add-demo.di +0 -74
  20. package/examples/add.bk +0 -11
  21. package/examples/advanced-math-demo.di +0 -53
  22. package/examples/calculator.di +0 -32
  23. package/examples/compact-test.di +0 -6
  24. package/examples/comprehensive.bk +0 -29
  25. package/examples/defvar-variable-demo.di +0 -18
  26. package/examples/direct-call.di +0 -17
  27. package/examples/disk-analysis.di +0 -16
  28. package/examples/exception-demo.di +0 -82
  29. package/examples/executable-hello.di +0 -7
  30. package/examples/execute-demo.di +0 -38
  31. package/examples/file-manager.di +0 -77
  32. package/examples/file-stats.di +0 -18
  33. package/examples/hello.bk +0 -1
  34. package/examples/hello.di +0 -5
  35. package/examples/if-comparison.di +0 -91
  36. package/examples/if-cstyle-test.di +0 -149
  37. package/examples/if-vs-testif.di +0 -56
  38. package/examples/import-demo.di +0 -31
  39. package/examples/inline-test.bk +0 -7
  40. package/examples/llm-agent.di +0 -32
  41. package/examples/llm-basic.di +0 -12
  42. package/examples/llm-command-more.di +0 -6
  43. package/examples/llm-command-no-exec.di +0 -13
  44. package/examples/llm-command.di +0 -6
  45. package/examples/llm-complex.di +0 -141
  46. package/examples/llm-feedback-debug.di +0 -30
  47. package/examples/llm-feedback-demo.di +0 -19
  48. package/examples/llm-feedback-math.di +0 -22
  49. package/examples/llm-feedback-simple.di +0 -16
  50. package/examples/llm-feedback-sub.di +0 -22
  51. package/examples/llm-no-feedback.di +0 -10
  52. package/examples/llm-recursive.di +0 -31
  53. package/examples/llm-reflection-test.di +0 -19
  54. package/examples/llm-simple-test.di +0 -12
  55. package/examples/llm-subs.di +0 -132
  56. package/examples/llm-use-subs.di +0 -6
  57. package/examples/llm-validate-test.di +0 -18
  58. package/examples/loop.di +0 -12
  59. package/examples/math-test.di +0 -22
  60. package/examples/minimal-test.di +0 -13
  61. package/examples/mongodb-context-test.di +0 -27
  62. package/examples/mongodb-count-events.di +0 -8
  63. package/examples/mongodb-import-demo.di +0 -25
  64. package/examples/mongodb-simple-test.di +0 -18
  65. package/examples/nl-agent.di +0 -47
  66. package/examples/parameters-demo.di +0 -68
  67. package/examples/params-meta-test.di +0 -17
  68. package/examples/params-test.di +0 -10
  69. package/examples/recipe-chain.di +0 -38
  70. package/examples/recursive-llm.di +0 -44
  71. package/examples/sample-library/README.md +0 -152
  72. package/examples/sample-library/examples/demo.di +0 -34
  73. package/examples/sample-library/lib/index.di +0 -65
  74. package/examples/sample-library/package.json +0 -31
  75. package/examples/scope-test-nested.di +0 -60
  76. package/examples/scope-test.di +0 -55
  77. package/examples/seamless.di +0 -45
  78. package/examples/shell-test.bk +0 -10
  79. package/examples/simple-import.di +0 -13
  80. package/examples/simple-recursive.di +0 -26
  81. package/examples/story-builder.di +0 -45
  82. package/examples/subroutine.di +0 -23
  83. package/examples/system-llm.di +0 -21
  84. package/examples/system-simple.di +0 -3
  85. package/examples/system-test.di +0 -8
  86. package/examples/tag-check-test.di +0 -139
  87. package/examples/task-assistant.di +0 -27
  88. package/examples/test-if-demo.di +0 -110
  89. package/examples/test-parameters.di +0 -50
  90. package/examples/try-catch-test.di +0 -118
  91. package/examples/two-styles.di +0 -28
  92. package/examples/var-debug.di +0 -6
  93. package/examples/var-inline.di +0 -4
  94. package/examples/var-test2.di +0 -6
  95. package/examples/variable-replace.di +0 -25
  96. package/examples/variable-simple.di +0 -16
  97. package/examples/variable-test.di +0 -22
  98. package/examples/whitespace-test.di +0 -24
  99. package/filePath +0 -1
  100. package/greeting.txt +0 -1
  101. package/src/cli.ts +0 -140
  102. package/src/index.ts +0 -33
  103. package/src/llm/ollama.ts +0 -58
  104. package/src/runtime/braket-parser.ts +0 -234
  105. package/src/runtime/interpreter.ts +0 -203
  106. package/src/runtime/parser.ts +0 -155
  107. package/src/runtime/session.ts +0 -325
  108. package/src/tags/assign.ts +0 -37
  109. package/src/tags/attr.ts +0 -64
  110. package/src/tags/available-subroutines.ts +0 -70
  111. package/src/tags/call.ts +0 -259
  112. package/src/tags/catch.ts +0 -24
  113. package/src/tags/defvar.ts +0 -115
  114. package/src/tags/environment.ts +0 -21
  115. package/src/tags/eval.ts +0 -71
  116. package/src/tags/exception.ts +0 -20
  117. package/src/tags/execute.ts +0 -52
  118. package/src/tags/expr.ts +0 -128
  119. package/src/tags/foreach.ts +0 -170
  120. package/src/tags/if.ts +0 -191
  121. package/src/tags/import.ts +0 -135
  122. package/src/tags/index.ts +0 -41
  123. package/src/tags/input.ts +0 -182
  124. package/src/tags/llm.ts +0 -415
  125. package/src/tags/loop.ts +0 -43
  126. package/src/tags/mongodb.ts +0 -70
  127. package/src/tags/output.ts +0 -53
  128. package/src/tags/parameters.ts +0 -81
  129. package/src/tags/require_module.ts +0 -19
  130. package/src/tags/subroutine.ts +0 -75
  131. package/src/tags/system.ts +0 -93
  132. package/src/tags/tag-check.ts +0 -176
  133. package/src/tags/test-if.ts +0 -112
  134. package/src/tags/throw.ts +0 -26
  135. package/src/tags/try.ts +0 -19
  136. package/src/tags/variable.ts +0 -25
  137. package/src/test-runner.ts +0 -300
  138. package/src/types/index.ts +0 -128
  139. package/src/utils/llm-adapter.ts +0 -113
  140. package/src/utils/tag-validator.ts +0 -231
  141. package/test-available-extends.di +0 -28
  142. package/test-available-simple.di +0 -12
  143. package/test-available-subroutines.di +0 -16
  144. package/test-call.di +0 -9
  145. package/test-extend-basic.di +0 -17
  146. package/test-extend-chain.di +0 -26
  147. package/test-extend-debug.di +0 -17
  148. package/test-extend-debug2.di +0 -15
  149. package/test-extend-person.di +0 -17
  150. package/test-extend-simple.di +0 -11
  151. package/test-extend-zhi.di +0 -23
  152. package/test-extend.di +0 -19
  153. package/test-extend2.di +0 -26
  154. package/test-extend3-fixed.di +0 -23
  155. package/test-extend3-trouble.di +0 -23
  156. package/test-extend3.di +0 -21
  157. package/test-factorial.di +0 -19
  158. package/test-input-debug.di +0 -19
  159. package/test-nested-debug.di +0 -7
  160. package/test-nested-debug2.di +0 -8
  161. package/test-no-extend.di +0 -16
  162. package/test-simple-call.di +0 -7
  163. package/test-simple.di +0 -6
  164. package/tests/README.md +0 -69
  165. package/tests/assign-basic.test.di +0 -7
  166. package/tests/assign-from-eval.test.di +0 -7
  167. package/tests/available-subroutines-foreach.test.di +0 -32
  168. package/tests/basic-output.test.di +0 -5
  169. package/tests/call-basic.test.di +0 -11
  170. package/tests/call-with-output.test.di +0 -10
  171. package/tests/comments-before-content.test.di +0 -6
  172. package/tests/defvar-multiple.test.di +0 -8
  173. package/tests/environment-basic.test.di +0 -22
  174. package/tests/environment-nonexistent.test.di +0 -5
  175. package/tests/environment-with-defvar.test.di +0 -15
  176. package/tests/eval-basic.test.di +0 -6
  177. package/tests/eval-with-variables.test.di +0 -8
  178. package/tests/exception-basic.test.di +0 -10
  179. package/tests/expr-basic.test.di +0 -11
  180. package/tests/extend-basic.test.di +0 -19
  181. package/tests/extend-inheritance-chain.test.di +0 -26
  182. package/tests/extend-multiple-nested.test.di +0 -24
  183. package/tests/extend-self.test.di +0 -19
  184. package/tests/extend-with-parameters.test.di +0 -14
  185. package/tests/generate-dirac.test.di +0 -22
  186. package/tests/if-conditional.test.di +0 -17
  187. package/tests/if-else.test.di +0 -11
  188. package/tests/if-with-variables.test.di +0 -8
  189. package/tests/import-basic.test.di +0 -6
  190. package/tests/input-file-all.test.di +0 -5
  191. package/tests/input-file-line.test.di +0 -15
  192. package/tests/input-file-loop.test.di +0 -12
  193. package/tests/input-stdin-all.test.di +0 -8
  194. package/tests/input-stdin-all.txt +0 -1
  195. package/tests/llm-validate.test.di +0 -17
  196. package/tests/loop-basic.test.di +0 -9
  197. package/tests/loop-nested.test.di +0 -10
  198. package/tests/loop-with-eval.test.di +0 -8
  199. package/tests/no-root-element.test.di +0 -6
  200. package/tests/output-file.test.di +0 -19
  201. package/tests/output-multiple.test.di +0 -9
  202. package/tests/parameters-basic.test.di +0 -6
  203. package/tests/require-module-basic.test.di +0 -7
  204. package/tests/subroutine-basic.test.di +0 -9
  205. package/tests/subroutine-multiple-params.test.di +0 -10
  206. package/tests/subroutine-nested-calls.test.di +0 -32
  207. package/tests/subroutine-sequential-calls.test.di +0 -36
  208. package/tests/system-background.test.di +0 -39
  209. package/tests/system-basic.test.di +0 -5
  210. package/tests/tag-check.test.di +0 -27
  211. package/tests/test-if-basic.test.di +0 -8
  212. package/tests/test-input.txt +0 -3
  213. package/tests/try-catch-basic.test.di +0 -10
  214. package/tests/try-catch-eval-error.test.di +0 -10
  215. package/tests/variable-basic.test.di +0 -6
  216. package/tests/variable-interpolation.test.di +0 -7
  217. package/tools/create-library.sh +0 -175
  218. package/tsconfig.json +0 -19
  219. /package/{examples/lib → lib}/advanced-math.di +0 -0
  220. /package/{examples/lib → lib}/fileops.di +0 -0
  221. /package/{examples/lib → lib}/mongodb.di +0 -0
package/src/tags/index.ts DELETED
@@ -1,41 +0,0 @@
1
- import * as system from './system';
2
- import * as execute from './execute';
3
- import * as llm from './llm';
4
- import * as variable from './variable';
5
- import * as subroutine from './subroutine';
6
- import * as assign from './assign';
7
- import * as parameters from './parameters';
8
- import * as loop from './loop';
9
- import * as evalTag from './eval';
10
- import * as call from './call';
11
- import * as defvar from './defvar';
12
- import * as output from './output';
13
- import * as expr from './expr';
14
- import * as ifTag from './if';
15
- import * as importTag from './import';
16
- import * as mongodb from './mongodb';
17
- import * as requireModule from './require_module';
18
- import * as environment from './environment';
19
- import * as input from './input';
20
-
21
- export default {
22
- ...system,
23
- ...execute,
24
- ...llm,
25
- ...variable,
26
- ...subroutine,
27
- ...assign,
28
- ...parameters,
29
- ...loop,
30
- ...evalTag,
31
- ...call,
32
- ...defvar,
33
- ...output,
34
- ...expr,
35
- ...ifTag,
36
- ...importTag,
37
- ...mongodb,
38
- ...requireModule,
39
- ...environment,
40
- ...input,
41
- };
package/src/tags/input.ts DELETED
@@ -1,182 +0,0 @@
1
- /**
2
- * <input> tag - read from stdin or file
3
- * Usage:
4
- * <input source="stdin" mode="all" />
5
- * <input source="stdin" mode="line" />
6
- * <input source="file" path="file.txt" mode="all" />
7
- * <input source="file" path="file.txt" mode="line" />
8
- */
9
-
10
- import type { DiracSession, DiracElement } from '../types/index.js';
11
- import { emit, substituteAttribute } from '../runtime/session.js';
12
- import * as fs from 'fs';
13
- import * as readline from 'readline';
14
-
15
- // Store file readers for line-by-line reading
16
- const fileReaders = new Map<string, readline.Interface>();
17
- const fileIterators = new Map<string, AsyncIterator<string>>();
18
-
19
- export async function executeInput(session: DiracSession, element: DiracElement): Promise<void> {
20
- const source = element.attributes.source;
21
- const mode = element.attributes.mode || 'all';
22
- const pathAttr = element.attributes.path;
23
-
24
- if (!source) {
25
- throw new Error('<input> requires source attribute (stdin or file)');
26
- }
27
-
28
- if (source === 'file' && !pathAttr) {
29
- throw new Error('<input source="file"> requires path attribute');
30
- }
31
-
32
- let value = '';
33
-
34
- if (source === 'stdin') {
35
- if (mode === 'all') {
36
- // Read all stdin at once
37
- value = await readAllStdin();
38
- } else if (mode === 'line') {
39
- // Read one line from stdin
40
- value = await readLineStdin();
41
- } else {
42
- throw new Error(`<input> invalid mode: ${mode}. Use 'all' or 'line'`);
43
- }
44
- } else if (source === 'file') {
45
- const path = substituteAttribute(session, pathAttr);
46
-
47
- if (mode === 'all') {
48
- // Read entire file
49
- value = fs.readFileSync(path, 'utf-8');
50
- } else if (mode === 'line') {
51
- // Read one line from file
52
- value = await readLineFromFile(path);
53
- } else {
54
- throw new Error(`<input> invalid mode: ${mode}. Use 'all' or 'line'`);
55
- }
56
- } else {
57
- throw new Error(`<input> invalid source: ${source}. Use 'stdin' or 'file'`);
58
- }
59
-
60
- // Emit the value to output
61
- emit(session, value);
62
- }
63
-
64
- /**
65
- * Read all stdin content at once
66
- */
67
- async function readAllStdin(): Promise<string> {
68
- // Remove any existing listeners to avoid conflicts
69
- process.stdin.removeAllListeners('data');
70
- process.stdin.removeAllListeners('end');
71
- process.stdin.removeAllListeners('error');
72
-
73
- return new Promise((resolve, reject) => {
74
- const chunks: Buffer[] = [];
75
-
76
- const onData = (chunk: Buffer) => {
77
- chunks.push(chunk);
78
- };
79
-
80
- const onEnd = () => {
81
- const result = Buffer.concat(chunks).toString('utf-8');
82
-
83
- // Clean up listeners
84
- process.stdin.removeListener('data', onData);
85
- process.stdin.removeListener('end', onEnd);
86
- process.stdin.removeListener('error', onError);
87
-
88
- resolve(result);
89
- };
90
-
91
- const onError = (err: Error) => {
92
- // Clean up listeners
93
- process.stdin.removeListener('data', onData);
94
- process.stdin.removeListener('end', onEnd);
95
- process.stdin.removeListener('error', onError);
96
-
97
- reject(err);
98
- };
99
-
100
- process.stdin.on('data', onData);
101
- process.stdin.on('end', onEnd);
102
- process.stdin.on('error', onError);
103
-
104
- process.stdin.resume();
105
- });
106
- }
107
-
108
- /**
109
- * Read one line from stdin
110
- */
111
- let stdinReader: readline.Interface | null = null;
112
- let stdinIterator: AsyncIterator<string> | null = null;
113
-
114
- async function readLineStdin(): Promise<string> {
115
- if (!stdinReader) {
116
- stdinReader = readline.createInterface({
117
- input: process.stdin,
118
- output: process.stdout,
119
- terminal: false
120
- });
121
- stdinIterator = stdinReader[Symbol.asyncIterator]();
122
- }
123
-
124
- const result = await stdinIterator!.next();
125
-
126
- if (result.done) {
127
- // EOF reached, close reader
128
- stdinReader.close();
129
- stdinReader = null;
130
- stdinIterator = null;
131
- return '';
132
- }
133
-
134
- return result.value;
135
- }
136
-
137
- /**
138
- * Read one line from a file
139
- */
140
- async function readLineFromFile(path: string): Promise<string> {
141
- // Create reader if it doesn't exist for this file
142
- if (!fileReaders.has(path)) {
143
- const fileStream = fs.createReadStream(path);
144
- const rl = readline.createInterface({
145
- input: fileStream,
146
- crlfDelay: Infinity
147
- });
148
- fileReaders.set(path, rl);
149
- fileIterators.set(path, rl[Symbol.asyncIterator]());
150
- }
151
-
152
- const iterator = fileIterators.get(path)!;
153
- const result = await iterator.next();
154
-
155
- if (result.done) {
156
- // EOF reached, close and cleanup
157
- const reader = fileReaders.get(path)!;
158
- reader.close();
159
- fileReaders.delete(path);
160
- fileIterators.delete(path);
161
- return '';
162
- }
163
-
164
- return result.value;
165
- }
166
-
167
- /**
168
- * Clean up all open file readers (can be called at end of session)
169
- */
170
- export function cleanupInputReaders(): void {
171
- if (stdinReader) {
172
- stdinReader.close();
173
- stdinReader = null;
174
- stdinIterator = null;
175
- }
176
-
177
- for (const reader of fileReaders.values()) {
178
- reader.close();
179
- }
180
- fileReaders.clear();
181
- fileIterators.clear();
182
- }
package/src/tags/llm.ts DELETED
@@ -1,415 +0,0 @@
1
- /**
2
- * <LLM> tag - THE INNOVATION
3
- * Execute LLM operation with recursive Dirac execution capability
4
- */
5
-
6
- import type { DiracSession, DiracElement } from '../types/index.js';
7
- import { setVariable, substituteVariables, emit, getVariable } from '../runtime/session.js';
8
- import { integrate } from '../runtime/interpreter.js';
9
- import { DiracParser } from '../runtime/parser.js';
10
-
11
-
12
- export async function executeLLM(session: DiracSession, element: DiracElement): Promise<void> {
13
- if (!session.llmClient) {
14
- throw new Error('<LLM> requires API key (set OPENAI_API_KEY, ANTHROPIC_API_KEY, or LLM_PROVIDER=ollama in .env file)');
15
- }
16
-
17
- // Check limits
18
- if (session.limits.currentLLMCalls >= session.limits.maxLLMCalls) {
19
- throw new Error('Maximum LLM calls exceeded');
20
- }
21
-
22
- session.limits.currentLLMCalls++;
23
-
24
- // Detect provider from client type
25
- const providerName = session.llmClient.constructor.name;
26
- const isOpenAI = providerName === 'OpenAI';
27
- const isOllama = providerName === 'OllamaProvider';
28
- const defaultModel = isOpenAI
29
- ? 'gpt-4.1-2025-04-14'
30
- : isOllama
31
- ? 'llama2'
32
- : 'claude-sonnet-4-20250514';
33
-
34
-
35
- const model = element.attributes.model || process.env.DEFAULT_MODEL || defaultModel;
36
-
37
- const outputVar = element.attributes.output;
38
- const contextVar = element.attributes.context;
39
- const executeMode = element.attributes.execute === 'true'; // NEW: seamless execution mode
40
- const temperature = parseFloat(element.attributes.temperature || '1.0');
41
- const maxTokens = parseInt(element.attributes.maxTokens || '4096', 10);
42
-
43
- // Build prompt from children or text
44
- let userPrompt = '';
45
- if (element.children.length > 0) {
46
- // Execute children to build prompt
47
- const beforeOutput = session.output.length;
48
- for (const child of element.children) {
49
- await integrate(session, child);
50
- }
51
- // Collect output from children
52
- const childOutput = session.output.slice(beforeOutput);
53
- userPrompt = childOutput.join('').trim();
54
- // Remove child output from main output
55
- session.output = session.output.slice(0, beforeOutput);
56
- } else if (element.text) {
57
- userPrompt = substituteVariables(session, element.text).trim();
58
- } else {
59
- throw new Error('<LLM> requires prompt content');
60
- }
61
-
62
- // FIFO dialog history support
63
- let dialogHistory = [];
64
- if (contextVar) {
65
- const existing = getVariable(session, contextVar);
66
- if (Array.isArray(existing)) {
67
- dialogHistory = [...existing];
68
- } else if (existing) {
69
- // If context is a string, treat as system message
70
- dialogHistory = [{ role: 'system', content: String(existing) }];
71
- }
72
- }
73
-
74
- const noExtra = element.attributes.noextra === 'true';
75
- let prompt: string;
76
- let systemPrompt = '';
77
- if (noExtra) {
78
- prompt = userPrompt;
79
- if (session.debug || process.env.DIRAC_LOG_PROMPT === '1') {
80
- console.error('[LLM] Full prompt sent to LLM (noextra):\n' + prompt + '\n');
81
- }
82
- } else {
83
- // Reflect subroutines for system prompt
84
- const { getAvailableSubroutines } = await import('../runtime/session.js');
85
- const subroutines = getAvailableSubroutines(session);
86
- if (session.debug) {
87
- console.error('[LLM] Subroutines available at prompt composition:',
88
- subroutines.map(s => ({ name: s.name, description: s.description, parameters: s.parameters })));
89
- }
90
- systemPrompt = `Dirac is a XML based language, you define the subroutine like
91
- \`\`\`xml
92
- <subroutine name=background param-color="string">
93
- <paint_the_color_somewhere />
94
- </subroutine>
95
- \`\`\`
96
- then you call it like
97
- \`\`\`xml
98
- <background color="blue" />
99
- \`\`\`
100
- `;
101
- systemPrompt += 'Now, You are an expert Dirac XML code generator.\nAllowed Dirac XML tags (use ONLY these tags):';
102
- for (const sub of subroutines) {
103
- systemPrompt += `\n- ${sub.name} : ${sub.description || ''}`;
104
- systemPrompt += `\n\tEx: <${sub.name}`;
105
- if (sub.parameters && sub.parameters.length > 0) {
106
- for (const p of sub.parameters) {
107
- systemPrompt += ` ${p.name}="${p.example || 'string'}"`;
108
- }
109
- }
110
- let example = sub.meta?.body?.example || '';
111
- example = example.replace(/&quot;/g, '"').replace(/&#58;/g, ':');
112
- systemPrompt += '>'+example+'</' + sub.name + '>';
113
- }
114
- systemPrompt += '\n\nIMPORTANT INSTRUCTIONS:';
115
- systemPrompt += '\n1. Output ONLY valid XML tags from the list above';
116
- systemPrompt += '\n2. Do NOT include any explanations, descriptions, or extra text';
117
- systemPrompt += '\n3. Do NOT use bullet points or formatting - just pure XML';
118
- systemPrompt += '\n4. Do NOT invent tags - only use tags from the list above';
119
- systemPrompt += '\n5. Start your response directly with the XML tag (e.g., <add ...>)';
120
- systemPrompt += '\n\nDouble-check: Does your response contain ONLY XML tags? If not, remove all non-XML text.';
121
-
122
- prompt = systemPrompt + '\nUser: ' + userPrompt + '\nOutput:';
123
- if (session.debug || process.env.DIRAC_LOG_PROMPT === '1') {
124
- console.error('[LLM] Full prompt sent to LLM:\n' + prompt + '\n');
125
- }
126
- }
127
-
128
- // Add the full prompt as a user message to dialogHistory
129
- dialogHistory.push({ role: 'user', content: noExtra ? userPrompt : prompt });
130
-
131
- if (session.debug) {
132
- console.error(`[LLM] Calling ${model} with prompt length: ${prompt.length}`);
133
- console.error(`[LLM] Dialog history length: ${dialogHistory.length} messages`);
134
- }
135
-
136
- try {
137
- let result: string;
138
- if (isOpenAI) {
139
- // Call OpenAI API with full dialog history
140
- const response = await session.llmClient.chat.completions.create({
141
- model,
142
- max_tokens: maxTokens,
143
- temperature,
144
- messages: dialogHistory,
145
- });
146
- result = response.choices[0]?.message?.content || '';
147
- } else if (isOllama) {
148
- // Call OllamaProvider with dialog history as joined string
149
- const ollamaPrompt = dialogHistory.map(m => `${m.role.charAt(0).toUpperCase() + m.role.slice(1)}: ${m.content}`).join('\n');
150
- result = await session.llmClient.complete(ollamaPrompt, {
151
- model,
152
- temperature,
153
- max_tokens: maxTokens,
154
- });
155
- } else {
156
- // Call Anthropic API with full dialog history
157
- const response = await session.llmClient.messages.create({
158
- model,
159
- max_tokens: maxTokens,
160
- temperature,
161
- messages: dialogHistory,
162
- });
163
- const content = response.content[0];
164
- result = content.type === 'text' ? content.text : '';
165
- }
166
-
167
- if (session.debug) {
168
- console.error(`[LLM] Response length: ${result.length}`);
169
- }
170
-
171
- // After LLM call, append assistant response to dialogHistory and update context variable
172
- if (contextVar) {
173
- dialogHistory.push({ role: 'assistant', content: result });
174
- setVariable(session, contextVar, dialogHistory, true);
175
- }
176
-
177
- // Store in variable if requested
178
- if (outputVar) {
179
- setVariable(session, outputVar, result, false);
180
- } else if (executeMode) {
181
- // NEW: Execute mode - parse and interpret LLM response as Dirac code
182
- const validateTags = element.attributes['validate'] === 'true';
183
- const autocorrect = element.attributes['autocorrect'] === 'true';
184
- const maxRetries = parseInt(element.attributes['max-retries'] || '0', 10);
185
- const feedbackMode = element.attributes['feedback'] === 'true';
186
- const maxIterations = parseInt(element.attributes['max-iterations'] || '3', 10);
187
- const replaceTick = element.attributes['replace-tick'] === 'true';
188
-
189
- if (session.debug) {
190
- console.error(`[LLM] Executing response as Dirac code:\n${result}\n`);
191
- if (validateTags) {
192
- console.error(`[LLM] Tag validation enabled (autocorrect: ${autocorrect}, max-retries: ${maxRetries})`);
193
- }
194
- if (feedbackMode) {
195
- console.error(`[LLM] Feedback mode enabled (max iterations: ${maxIterations})`);
196
- }
197
- }
198
-
199
- // Feedback loop: execute, capture output, send back to LLM, repeat
200
- let iteration = 0;
201
-
202
- while (iteration < maxIterations && (iteration === 0 || feedbackMode)) {
203
- iteration++;
204
- if (session.debug && feedbackMode) {
205
- console.error(`[LLM] Feedback iteration ${iteration}/${maxIterations}`);
206
- }
207
-
208
- // Only replace triple backtick code blocks if replace-tick="true" is set
209
- let diracCode = result.trim();
210
- if (replaceTick && diracCode.startsWith('```')) {
211
- // Check for bash, xml, html, dirac, or no language
212
- const match = diracCode.match(/^```(\w+)?\n?/m);
213
- if (match && match[1] === 'bash') {
214
- // Find closing triple backticks
215
- const endIdx = diracCode.indexOf('```', 3);
216
- let bashContent = diracCode.slice(match[0].length, endIdx).trim();
217
- diracCode = `<system>${bashContent}</system>`;
218
- } else {
219
- // Remove opening and closing backticks for xml/html/dirac/none
220
- diracCode = diracCode.replace(/^```(?:xml|html|dirac)?\n?/m, '').replace(/\n?```$/m, '').trim();
221
- }
222
- }
223
-
224
- // Capture output before execution (for feedback)
225
- const outputBefore = feedbackMode ? session.output.slice() : [];
226
-
227
- try {
228
- // Parse the LLM's output as Dirac code
229
- const parser = new DiracParser();
230
- let dynamicAST = parser.parse(diracCode);
231
-
232
- // Validate tags if requested
233
- if (validateTags) {
234
- const { validateDiracCode, applyCorrectedTags } = await import('../utils/tag-validator.js');
235
- let validation = await validateDiracCode(session, dynamicAST, { autocorrect });
236
- let retryCount = 0;
237
-
238
- while (!validation.valid && retryCount < maxRetries) {
239
- retryCount++;
240
- if (session.debug) {
241
- console.error(`[LLM] Validation failed (attempt ${retryCount}/${maxRetries}):`, validation.errorMessages);
242
- }
243
-
244
- // Build error feedback for LLM
245
- const errorFeedback = validation.errorMessages.join('\n');
246
- const retryPrompt = `Your previous response had the following errors:\n${errorFeedback}\n\nPlease fix these errors and generate valid Dirac XML again. Remember to only use the allowed tags.`;
247
-
248
- // Add error feedback to dialog history
249
- dialogHistory.push({ role: 'user', content: retryPrompt });
250
-
251
- // Retry LLM call
252
- if (isOpenAI) {
253
- const response = await session.llmClient.chat.completions.create({
254
- model,
255
- max_tokens: maxTokens,
256
- temperature,
257
- messages: dialogHistory,
258
- });
259
- result = response.choices[0]?.message?.content || '';
260
- } else if (isOllama) {
261
- const ollamaPrompt = dialogHistory.map(m => `${m.role.charAt(0).toUpperCase() + m.role.slice(1)}: ${m.content}`).join('\n');
262
- result = await session.llmClient.complete(ollamaPrompt, {
263
- model,
264
- temperature,
265
- max_tokens: maxTokens,
266
- });
267
- } else {
268
- const response = await session.llmClient.messages.create({
269
- model,
270
- max_tokens: maxTokens,
271
- temperature,
272
- messages: dialogHistory,
273
- });
274
- const content = response.content[0];
275
- result = content.type === 'text' ? content.text : '';
276
- }
277
-
278
- // Add new response to dialog history
279
- dialogHistory.push({ role: 'assistant', content: result });
280
-
281
- // Update context variable if present
282
- if (contextVar) {
283
- setVariable(session, contextVar, dialogHistory, true);
284
- }
285
-
286
- if (session.debug) {
287
- console.error(`[LLM] Retry ${retryCount} response:\n${result}\n`);
288
- }
289
-
290
- // Clean up and parse the new response
291
- diracCode = result.trim();
292
- if (replaceTick && diracCode.startsWith('```')) {
293
- const match = diracCode.match(/^```(\w+)?\n?/m);
294
- if (match && match[1] === 'bash') {
295
- const endIdx = diracCode.indexOf('```', 3);
296
- let bashContent = diracCode.slice(match[0].length, endIdx).trim();
297
- diracCode = `<system>${bashContent}</system>`;
298
- } else {
299
- diracCode = diracCode.replace(/^```(?:xml|html|dirac)?\n?/m, '').replace(/\n?```$/m, '').trim();
300
- }
301
- }
302
-
303
- dynamicAST = parser.parse(diracCode);
304
- validation = await validateDiracCode(session, dynamicAST, { autocorrect });
305
- }
306
-
307
- if (!validation.valid) {
308
- throw new Error(`Tag validation failed after ${maxRetries} retries:\n${validation.errorMessages.join('\n')}`);
309
- }
310
-
311
- // Apply auto-corrections if enabled
312
- if (autocorrect) {
313
- dynamicAST = applyCorrectedTags(dynamicAST, validation.results);
314
- if (session.debug) {
315
- console.error('[LLM] Applied auto-corrections to tags');
316
- }
317
- }
318
- }
319
-
320
- // Execute the validated (and possibly corrected) code
321
- await integrate(session, dynamicAST);
322
-
323
- // If feedback mode, capture execution output and send back to LLM
324
- if (feedbackMode) {
325
- const outputAfter = session.output.slice();
326
- const executionOutput = outputAfter.slice(outputBefore.length).join('');
327
-
328
- if (session.debug) {
329
- console.error(`[LLM] Execution output (${executionOutput.length} chars):\n${executionOutput}\n`);
330
- }
331
-
332
- // Build feedback prompt
333
- const feedbackPrompt = `The code executed successfully. Here is the output:\n\`\`\`\n${executionOutput}\n\`\`\`\n\nPlease review the output carefully. If the output is correct and complete, respond with ONLY the word "DONE" and nothing else. If the output is incorrect or incomplete, generate corrected Dirac XML code.`;
334
-
335
- if (session.debug) {
336
- console.error(`[LLM] Feedback prompt:\n${feedbackPrompt}\n`);
337
- }
338
-
339
- // Add feedback to dialog history
340
- dialogHistory.push({ role: 'user', content: feedbackPrompt });
341
-
342
- // Get LLM's assessment
343
- if (isOpenAI) {
344
- const response = await session.llmClient.chat.completions.create({
345
- model,
346
- max_tokens: maxTokens,
347
- temperature,
348
- messages: dialogHistory,
349
- });
350
- result = response.choices[0]?.message?.content || '';
351
- } else if (isOllama) {
352
- const ollamaPrompt = dialogHistory.map(m => `${m.role.charAt(0).toUpperCase() + m.role.slice(1)}: ${m.content}`).join('\n');
353
- result = await session.llmClient.complete(ollamaPrompt, {
354
- model,
355
- temperature,
356
- max_tokens: maxTokens,
357
- });
358
- } else {
359
- const response = await session.llmClient.messages.create({
360
- model,
361
- max_tokens: maxTokens,
362
- temperature,
363
- messages: dialogHistory,
364
- });
365
- const content = response.content[0];
366
- result = content.type === 'text' ? content.text : '';
367
- }
368
-
369
- // Add response to dialog history
370
- dialogHistory.push({ role: 'assistant', content: result });
371
-
372
- // Update context variable if present
373
- if (contextVar) {
374
- setVariable(session, contextVar, dialogHistory, true);
375
- }
376
-
377
- if (session.debug) {
378
- console.error(`[LLM] Feedback response:\n${result}\n`);
379
- }
380
-
381
- // Check if LLM says we're done (check at start of response)
382
- const responseStart = result.trim().substring(0, 100).toUpperCase();
383
- if (responseStart.startsWith('DONE') || result.trim().toLowerCase().includes('looks correct') || result.trim().toLowerCase().includes('looks good')) {
384
- if (session.debug) {
385
- console.error(`[LLM] Feedback loop terminating - LLM indicated completion\n`);
386
- }
387
- break;
388
- }
389
-
390
- // Otherwise, continue to next iteration with new LLM response
391
- } else {
392
- // No feedback mode, exit after first execution
393
- break;
394
- }
395
-
396
- } catch (parseError) {
397
- // If parsing fails, treat as plain text
398
- if (session.debug) {
399
- console.error(`[LLM] Failed to parse as Dirac, treating as text: ${parseError}`);
400
- }
401
- emit(session, result);
402
- break; // Exit feedback loop on parse error
403
- }
404
- } // end while loop
405
- } else {
406
- // Otherwise emit to output as text
407
- emit(session, result);
408
- }
409
-
410
- } catch (error) {
411
- throw new Error(`LLM error: ${error instanceof Error ? error.message : String(error)}`);
412
- }
413
- }
414
-
415
-
package/src/tags/loop.ts DELETED
@@ -1,43 +0,0 @@
1
- /**
2
- * <loop> tag - iteration
3
- * Maps to mask_tag_loop in MASK
4
- */
5
-
6
- import type { DiracSession, DiracElement } from '../types/index.js';
7
- import { setVariable, substituteVariables, getVariable } from '../runtime/session.js';
8
- import { integrateChildren } from '../runtime/interpreter.js';
9
-
10
- export async function executeLoop(session: DiracSession, element: DiracElement): Promise<void> {
11
- const countAttr = element.attributes.count;
12
- const varName = element.attributes.var || 'i';
13
-
14
- if (!countAttr) {
15
- throw new Error('<loop> requires count attribute');
16
- }
17
-
18
- const count = parseInt(substituteVariables(session, countAttr), 10);
19
-
20
- if (isNaN(count) || count < 0) {
21
- throw new Error(`Invalid loop count: ${countAttr}`);
22
- }
23
-
24
- const wasBreak = session.isBreak;
25
- session.isBreak = false;
26
-
27
- for (let i = 0; i < count; i++) {
28
- setVariable(session, varName, i, false);
29
-
30
- await integrateChildren(session, element);
31
-
32
- if (session.isBreak) {
33
- session.isBreak = false;
34
- break;
35
- }
36
-
37
- if (session.isReturn) {
38
- break;
39
- }
40
- }
41
-
42
- session.isBreak = wasBreak;
43
- }