deepclause-sdk 0.0.88 → 0.1.0

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 (318) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -914
  3. package/dist/agent.d.ts +19 -2
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +221 -4
  6. package/dist/agent.js.map +1 -1
  7. package/dist/cli/config.d.ts +323 -176
  8. package/dist/cli/config.d.ts.map +1 -1
  9. package/dist/cli/config.js +146 -188
  10. package/dist/cli/config.js.map +1 -1
  11. package/dist/cli/index.d.ts +3 -2
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +61 -425
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/login.d.ts +29 -0
  16. package/dist/cli/login.d.ts.map +1 -0
  17. package/dist/cli/login.js +184 -0
  18. package/dist/cli/login.js.map +1 -0
  19. package/dist/cli/readline.d.ts +6 -0
  20. package/dist/cli/readline.d.ts.map +1 -0
  21. package/dist/cli/readline.js +15 -0
  22. package/dist/cli/readline.js.map +1 -0
  23. package/dist/cli/repl-bin.d.ts +9 -0
  24. package/dist/cli/repl-bin.d.ts.map +1 -0
  25. package/dist/cli/repl-bin.js +16 -0
  26. package/dist/cli/repl-bin.js.map +1 -0
  27. package/dist/cli/repl.d.ts +191 -0
  28. package/dist/cli/repl.d.ts.map +1 -0
  29. package/dist/cli/repl.js +1232 -0
  30. package/dist/cli/repl.js.map +1 -0
  31. package/dist/cli/run.d.ts +17 -18
  32. package/dist/cli/run.d.ts.map +1 -1
  33. package/dist/cli/run.js +196 -183
  34. package/dist/cli/run.js.map +1 -1
  35. package/dist/cli/set-backend.d.ts +53 -0
  36. package/dist/cli/set-backend.d.ts.map +1 -0
  37. package/dist/cli/set-backend.js +259 -0
  38. package/dist/cli/set-backend.js.map +1 -0
  39. package/dist/cli/visualize.d.ts +38 -0
  40. package/dist/cli/visualize.d.ts.map +1 -0
  41. package/dist/cli/visualize.js +125 -0
  42. package/dist/cli/visualize.js.map +1 -0
  43. package/dist/compiler.d.ts +5 -52
  44. package/dist/compiler.d.ts.map +1 -1
  45. package/dist/compiler.js +4 -768
  46. package/dist/compiler.js.map +1 -1
  47. package/dist/index.d.ts +29 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +20 -2
  50. package/dist/index.js.map +1 -1
  51. package/dist/judge/index.d.ts +9 -0
  52. package/dist/judge/index.d.ts.map +1 -0
  53. package/dist/judge/index.js +6 -0
  54. package/dist/judge/index.js.map +1 -0
  55. package/dist/judge/jev.d.ts +21 -0
  56. package/dist/judge/jev.d.ts.map +1 -0
  57. package/dist/judge/jev.js +218 -0
  58. package/dist/judge/jev.js.map +1 -0
  59. package/dist/judge/llm.d.ts +23 -0
  60. package/dist/judge/llm.d.ts.map +1 -0
  61. package/dist/judge/llm.js +120 -0
  62. package/dist/judge/llm.js.map +1 -0
  63. package/dist/judge/marshal.d.ts +26 -0
  64. package/dist/judge/marshal.d.ts.map +1 -0
  65. package/dist/judge/marshal.js +266 -0
  66. package/dist/judge/marshal.js.map +1 -0
  67. package/dist/judge/mock.d.ts +28 -0
  68. package/dist/judge/mock.d.ts.map +1 -0
  69. package/dist/judge/mock.js +98 -0
  70. package/dist/judge/mock.js.map +1 -0
  71. package/dist/judge/types.d.ts +95 -0
  72. package/dist/judge/types.d.ts.map +1 -0
  73. package/dist/judge/types.js +23 -0
  74. package/dist/judge/types.js.map +1 -0
  75. package/dist/prolog/bridge.d.ts +5 -1
  76. package/dist/prolog/bridge.d.ts.map +1 -1
  77. package/dist/prolog/bridge.js +29 -1
  78. package/dist/prolog/bridge.js.map +1 -1
  79. package/dist/prolog-src/deepclause_analysis.pl +10 -2
  80. package/dist/prolog-src/deepclause_mi.pl +2522 -118
  81. package/dist/repl/agent.d.ts +72 -0
  82. package/dist/repl/agent.d.ts.map +1 -0
  83. package/dist/repl/agent.js +366 -0
  84. package/dist/repl/agent.js.map +1 -0
  85. package/dist/repl/auth.d.ts +45 -0
  86. package/dist/repl/auth.d.ts.map +1 -0
  87. package/dist/repl/auth.js +116 -0
  88. package/dist/repl/auth.js.map +1 -0
  89. package/dist/repl/backend.d.ts +290 -0
  90. package/dist/repl/backend.d.ts.map +1 -0
  91. package/dist/repl/backend.js +370 -0
  92. package/dist/repl/backend.js.map +1 -0
  93. package/dist/repl/compaction.d.ts +122 -0
  94. package/dist/repl/compaction.d.ts.map +1 -0
  95. package/dist/repl/compaction.js +318 -0
  96. package/dist/repl/compaction.js.map +1 -0
  97. package/dist/repl/export.d.ts +30 -0
  98. package/dist/repl/export.d.ts.map +1 -0
  99. package/dist/repl/export.js +23 -0
  100. package/dist/repl/export.js.map +1 -0
  101. package/dist/repl/frames.d.ts +21 -0
  102. package/dist/repl/frames.d.ts.map +1 -0
  103. package/dist/repl/frames.js +79 -0
  104. package/dist/repl/frames.js.map +1 -0
  105. package/dist/repl/harness-tools.d.ts +74 -0
  106. package/dist/repl/harness-tools.d.ts.map +1 -0
  107. package/dist/repl/harness-tools.js +121 -0
  108. package/dist/repl/harness-tools.js.map +1 -0
  109. package/dist/repl/highlight.d.ts +30 -0
  110. package/dist/repl/highlight.d.ts.map +1 -0
  111. package/dist/repl/highlight.js +285 -0
  112. package/dist/repl/highlight.js.map +1 -0
  113. package/dist/repl/history.d.ts +234 -0
  114. package/dist/repl/history.d.ts.map +1 -0
  115. package/dist/repl/history.js +661 -0
  116. package/dist/repl/history.js.map +1 -0
  117. package/dist/repl/index.d.ts +120 -0
  118. package/dist/repl/index.d.ts.map +1 -0
  119. package/dist/repl/index.js +107 -0
  120. package/dist/repl/index.js.map +1 -0
  121. package/dist/repl/judge.d.ts +51 -0
  122. package/dist/repl/judge.d.ts.map +1 -0
  123. package/dist/repl/judge.js +58 -0
  124. package/dist/repl/judge.js.map +1 -0
  125. package/dist/repl/markdown.d.ts +25 -0
  126. package/dist/repl/markdown.d.ts.map +1 -0
  127. package/dist/repl/markdown.js +103 -0
  128. package/dist/repl/markdown.js.map +1 -0
  129. package/dist/repl/picker.d.ts +34 -0
  130. package/dist/repl/picker.d.ts.map +1 -0
  131. package/dist/repl/picker.js +81 -0
  132. package/dist/repl/picker.js.map +1 -0
  133. package/dist/repl/project-context.d.ts +16 -0
  134. package/dist/repl/project-context.d.ts.map +1 -0
  135. package/dist/repl/project-context.js +23 -0
  136. package/dist/repl/project-context.js.map +1 -0
  137. package/dist/repl/render.d.ts +160 -0
  138. package/dist/repl/render.d.ts.map +1 -0
  139. package/dist/repl/render.js +715 -0
  140. package/dist/repl/render.js.map +1 -0
  141. package/dist/repl/session.d.ts +356 -0
  142. package/dist/repl/session.d.ts.map +1 -0
  143. package/dist/repl/session.js +1275 -0
  144. package/dist/repl/session.js.map +1 -0
  145. package/dist/repl/status.d.ts +100 -0
  146. package/dist/repl/status.d.ts.map +1 -0
  147. package/dist/repl/status.js +218 -0
  148. package/dist/repl/status.js.map +1 -0
  149. package/dist/repl/tools.d.ts +53 -0
  150. package/dist/repl/tools.d.ts.map +1 -0
  151. package/dist/repl/tools.js +307 -0
  152. package/dist/repl/tools.js.map +1 -0
  153. package/dist/repl/toolset.d.ts +32 -0
  154. package/dist/repl/toolset.d.ts.map +1 -0
  155. package/dist/repl/toolset.js +82 -0
  156. package/dist/repl/toolset.js.map +1 -0
  157. package/dist/repl/tui/editor.d.ts +17 -0
  158. package/dist/repl/tui/editor.d.ts.map +1 -0
  159. package/dist/repl/tui/editor.js +39 -0
  160. package/dist/repl/tui/editor.js.map +1 -0
  161. package/dist/repl/tui/status-bar.d.ts +26 -0
  162. package/dist/repl/tui/status-bar.d.ts.map +1 -0
  163. package/dist/repl/tui/status-bar.js +47 -0
  164. package/dist/repl/tui/status-bar.js.map +1 -0
  165. package/dist/repl/tui/theme.d.ts +30 -0
  166. package/dist/repl/tui/theme.d.ts.map +1 -0
  167. package/dist/repl/tui/theme.js +81 -0
  168. package/dist/repl/tui/theme.js.map +1 -0
  169. package/dist/repl/tui/transcript.d.ts +39 -0
  170. package/dist/repl/tui/transcript.d.ts.map +1 -0
  171. package/dist/repl/tui/transcript.js +123 -0
  172. package/dist/repl/tui/transcript.js.map +1 -0
  173. package/dist/runner.d.ts +145 -13
  174. package/dist/runner.d.ts.map +1 -1
  175. package/dist/runner.js +600 -282
  176. package/dist/runner.js.map +1 -1
  177. package/dist/sdk.d.ts.map +1 -1
  178. package/dist/sdk.js +56 -32
  179. package/dist/sdk.js.map +1 -1
  180. package/dist/system/assets/docs/AGENT_PROMPT.md +1373 -0
  181. package/dist/system/assets/docs/DML_AUTHORING.md +195 -0
  182. package/dist/system/assets/docs/DML_REFERENCE.md +393 -72
  183. package/dist/system/assets/docs/HARNESS_EXAMPLES.md +172 -0
  184. package/dist/system/assets/docs/HARNESS_PATTERNS.md +562 -0
  185. package/dist/system/assets/docs/META_PROMPT.md +68 -0
  186. package/dist/system/assets/docs/PROLOG_SNIPPETS.md +117 -0
  187. package/dist/system/assets/index.d.ts +9 -17
  188. package/dist/system/assets/index.d.ts.map +1 -1
  189. package/dist/system/assets/index.js +26 -85
  190. package/dist/system/assets/index.js.map +1 -1
  191. package/dist/system/runtime/agentvm-manager.d.ts +9 -2
  192. package/dist/system/runtime/agentvm-manager.d.ts.map +1 -1
  193. package/dist/system/runtime/agentvm-manager.js +70 -44
  194. package/dist/system/runtime/agentvm-manager.js.map +1 -1
  195. package/dist/system/runtime/media.d.ts +23 -0
  196. package/dist/system/runtime/media.d.ts.map +1 -0
  197. package/dist/system/runtime/media.js +55 -0
  198. package/dist/system/runtime/media.js.map +1 -0
  199. package/dist/system/runtime/shell-limits.d.ts +21 -0
  200. package/dist/system/runtime/shell-limits.d.ts.map +1 -0
  201. package/dist/system/runtime/shell-limits.js +39 -0
  202. package/dist/system/runtime/shell-limits.js.map +1 -0
  203. package/dist/system/runtime/shell-manager.d.ts +8 -3
  204. package/dist/system/runtime/shell-manager.d.ts.map +1 -1
  205. package/dist/system/runtime/shell-manager.js +56 -39
  206. package/dist/system/runtime/shell-manager.js.map +1 -1
  207. package/dist/system/runtime/shell-tool-events.js +5 -0
  208. package/dist/system/runtime/shell-tool-events.js.map +1 -1
  209. package/dist/system/runtime/token-usage.d.ts +2 -0
  210. package/dist/system/runtime/token-usage.d.ts.map +1 -1
  211. package/dist/system/runtime/token-usage.js +7 -0
  212. package/dist/system/runtime/token-usage.js.map +1 -1
  213. package/dist/tools.d.ts +3 -21
  214. package/dist/tools.d.ts.map +1 -1
  215. package/dist/tools.js +14 -168
  216. package/dist/tools.js.map +1 -1
  217. package/dist/types.d.ts +149 -118
  218. package/dist/types.d.ts.map +1 -1
  219. package/dist/validate.d.ts +19 -0
  220. package/dist/validate.d.ts.map +1 -0
  221. package/dist/validate.js +338 -0
  222. package/dist/validate.js.map +1 -0
  223. package/dist/visualize/index.d.ts +52 -0
  224. package/dist/visualize/index.d.ts.map +1 -0
  225. package/dist/visualize/index.js +189 -0
  226. package/dist/visualize/index.js.map +1 -0
  227. package/package.json +17 -15
  228. package/src/prolog-src/deepclause_analysis.pl +10 -2
  229. package/src/prolog-src/deepclause_mi.pl +2522 -118
  230. package/dist/cli/commands.d.ts +0 -42
  231. package/dist/cli/commands.d.ts.map +0 -1
  232. package/dist/cli/commands.js +0 -246
  233. package/dist/cli/commands.js.map +0 -1
  234. package/dist/cli/compile.d.ts +0 -99
  235. package/dist/cli/compile.d.ts.map +0 -1
  236. package/dist/cli/compile.js +0 -363
  237. package/dist/cli/compile.js.map +0 -1
  238. package/dist/cli/default-skills.d.ts +0 -10
  239. package/dist/cli/default-skills.d.ts.map +0 -1
  240. package/dist/cli/default-skills.js +0 -206
  241. package/dist/cli/default-skills.js.map +0 -1
  242. package/dist/cli/interactive.d.ts +0 -2
  243. package/dist/cli/interactive.d.ts.map +0 -1
  244. package/dist/cli/interactive.js +0 -20
  245. package/dist/cli/interactive.js.map +0 -1
  246. package/dist/cli/mcp.d.ts +0 -56
  247. package/dist/cli/mcp.d.ts.map +0 -1
  248. package/dist/cli/mcp.js +0 -138
  249. package/dist/cli/mcp.js.map +0 -1
  250. package/dist/cli/prompt.d.ts +0 -2
  251. package/dist/cli/prompt.d.ts.map +0 -1
  252. package/dist/cli/prompt.js +0 -2
  253. package/dist/cli/prompt.js.map +0 -1
  254. package/dist/cli/search.d.ts +0 -19
  255. package/dist/cli/search.d.ts.map +0 -1
  256. package/dist/cli/search.js +0 -189
  257. package/dist/cli/search.js.map +0 -1
  258. package/dist/cli/tool-args.d.ts +0 -2
  259. package/dist/cli/tool-args.d.ts.map +0 -1
  260. package/dist/cli/tool-args.js +0 -39
  261. package/dist/cli/tool-args.js.map +0 -1
  262. package/dist/cli/tools.d.ts +0 -36
  263. package/dist/cli/tools.d.ts.map +0 -1
  264. package/dist/cli/tools.js +0 -229
  265. package/dist/cli/tools.js.map +0 -1
  266. package/dist/cli/tui/index.d.ts +0 -22
  267. package/dist/cli/tui/index.d.ts.map +0 -1
  268. package/dist/cli/tui/index.js +0 -29
  269. package/dist/cli/tui/index.js.map +0 -1
  270. package/dist/cli/tui.d.ts +0 -167
  271. package/dist/cli/tui.d.ts.map +0 -1
  272. package/dist/cli/tui.js +0 -5228
  273. package/dist/cli/tui.js.map +0 -1
  274. package/dist/compiler_prompt.d.ts +0 -20
  275. package/dist/compiler_prompt.d.ts.map +0 -1
  276. package/dist/compiler_prompt.js +0 -870
  277. package/dist/compiler_prompt.js.map +0 -1
  278. package/dist/deepclause-cli.skill +0 -0
  279. package/dist/prolog-src/deepclause_mi.pl.bak +0 -570
  280. package/dist/system/assets/compactors/default-memory-compactor.dml +0 -6
  281. package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +0 -105
  282. package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +0 -700
  283. package/dist/system/assets/docs/TUI.md +0 -150
  284. package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +0 -100
  285. package/dist/system/assets/skills/conductor.dml +0 -76
  286. package/dist/system/assets/skills/deep-planner.dml +0 -412
  287. package/dist/system/assets/skills/plan.dml +0 -429
  288. package/dist/system/assets/skills/security-planner.dml +0 -337
  289. package/dist/system/assets/skills/skill-creator.dml +0 -187
  290. package/dist/system/runtime/catalog-recipes.d.ts +0 -24
  291. package/dist/system/runtime/catalog-recipes.d.ts.map +0 -1
  292. package/dist/system/runtime/catalog-recipes.js +0 -273
  293. package/dist/system/runtime/catalog-recipes.js.map +0 -1
  294. package/dist/system/runtime/catalog-skills.d.ts +0 -50
  295. package/dist/system/runtime/catalog-skills.d.ts.map +0 -1
  296. package/dist/system/runtime/catalog-skills.js +0 -152
  297. package/dist/system/runtime/catalog-skills.js.map +0 -1
  298. package/dist/system/runtime/conductor.d.ts +0 -105
  299. package/dist/system/runtime/conductor.d.ts.map +0 -1
  300. package/dist/system/runtime/conductor.js +0 -732
  301. package/dist/system/runtime/conductor.js.map +0 -1
  302. package/dist/system/runtime/console-capture.d.ts +0 -9
  303. package/dist/system/runtime/console-capture.d.ts.map +0 -1
  304. package/dist/system/runtime/console-capture.js +0 -67
  305. package/dist/system/runtime/console-capture.js.map +0 -1
  306. package/dist/system/runtime/dml-executor.d.ts +0 -52
  307. package/dist/system/runtime/dml-executor.d.ts.map +0 -1
  308. package/dist/system/runtime/dml-executor.js +0 -203
  309. package/dist/system/runtime/dml-executor.js.map +0 -1
  310. package/dist/system/runtime/runtime-tools.d.ts +0 -31
  311. package/dist/system/runtime/runtime-tools.d.ts.map +0 -1
  312. package/dist/system/runtime/runtime-tools.js +0 -312
  313. package/dist/system/runtime/runtime-tools.js.map +0 -1
  314. package/dist/system/runtime/skill-creator.d.ts +0 -38
  315. package/dist/system/runtime/skill-creator.d.ts.map +0 -1
  316. package/dist/system/runtime/skill-creator.js +0 -763
  317. package/dist/system/runtime/skill-creator.js.map +0 -1
  318. package/src/prolog-src/deepclause_mi.pl.bak +0 -570
package/dist/compiler.js CHANGED
@@ -1,771 +1,7 @@
1
1
  /**
2
- * DeepClause SDK - Compilation Module
3
- *
4
- * Compiles Markdown task descriptions to DML programs using an agentic loop
5
- * with LLM generation and Prolog validation.
2
+ * @deprecated The Markdown->DML compiler was removed in the SDK cleanup. This
3
+ * module is a compatibility alias re-exporting `validateWithProlog` from
4
+ * `deepclause-sdk/validate`. Import from `deepclause-sdk/validate` instead.
6
5
  */
7
- import { generateText } from 'ai';
8
- import { openai, createOpenAI } from '@ai-sdk/openai';
9
- import { anthropic } from '@ai-sdk/anthropic';
10
- import { google } from '@ai-sdk/google';
11
- import { buildCompilationPrompt, buildUserMessage } from './compiler_prompt.js';
12
- import { loadProlog } from './prolog/loader.js';
13
- import { recordTokenUsage } from './system/runtime/token-usage.js';
14
- // =============================================================================
15
- // Prolog Validation
16
- // =============================================================================
17
- let prologInstance = null;
18
- /**
19
- * Get or initialize Prolog instance for validation
20
- */
21
- async function getProlog() {
22
- if (!prologInstance) {
23
- prologInstance = await loadProlog();
24
- }
25
- return prologInstance;
26
- }
27
- /**
28
- * Validate DML code using the actual Prolog parser
29
- */
30
- export async function validateWithProlog(dml) {
31
- const errors = [];
32
- const warnings = [];
33
- try {
34
- const swipl = await getProlog();
35
- // Write code to temp file
36
- const tempPath = `/tmp/validate_${Date.now()}_${Math.random().toString(36).substring(7)}.pl`;
37
- swipl.FS.writeFile(tempPath, dml);
38
- // Try to parse the file using read_term which will catch syntax errors
39
- try {
40
- swipl.prolog.query(`catch(
41
- (
42
- open('${tempPath}', read, Stream, []),
43
- call_cleanup(
44
- read_all_terms(Stream),
45
- close(Stream)
46
- )
47
- ),
48
- Error,
49
- (
50
- Error = error(syntax_error(Message), _) ->
51
- true
52
- ;
53
- (term_to_atom(Error, Message), true)
54
- )
55
- ),
56
- read_all_terms(S) :-
57
- repeat,
58
- read_term(S, T, [syntax_errors(error)]),
59
- (T == end_of_file -> ! ; fail)`);
60
- // Simple approach: try to consult the file
61
- try {
62
- swipl.prolog.call(`consult('${tempPath}')`);
63
- }
64
- catch (consultError) {
65
- const errMsg = consultError instanceof Error ? consultError.message : String(consultError);
66
- if (errMsg.includes('syntax') || errMsg.includes('error')) {
67
- // Extract meaningful error message
68
- const match = errMsg.match(/(?:syntax_error|error)\s*\(\s*['"]?([^'")\]]+)/i);
69
- if (match) {
70
- errors.push(`Syntax error: ${match[1]}`);
71
- }
72
- else {
73
- errors.push(`Parse error: ${errMsg.substring(0, 200)}`);
74
- }
75
- }
76
- }
77
- }
78
- catch (e) {
79
- const errMsg = e instanceof Error ? e.message : String(e);
80
- if (errMsg.includes('syntax') || errMsg.includes('error')) {
81
- errors.push(errMsg.substring(0, 200));
82
- }
83
- }
84
- // Check for required elements
85
- if (!dml.includes('agent_main')) {
86
- errors.push('Missing agent_main predicate - every DML program must define agent_main');
87
- }
88
- // Check for balanced delimiters
89
- const delimiterCheck = checkBalancedDelimiters(dml);
90
- errors.push(...delimiterCheck.errors);
91
- // Check for common mistakes
92
- const lintResult = lintDML(dml);
93
- errors.push(...lintResult.errors);
94
- warnings.push(...lintResult.warnings);
95
- // Cleanup temp file
96
- try {
97
- swipl.FS.unlink(tempPath);
98
- }
99
- catch {
100
- // Ignore cleanup errors
101
- }
102
- }
103
- catch (error) {
104
- // If Prolog itself fails, fall back to basic validation
105
- return validateDMLSyntaxBasic(dml);
106
- }
107
- return {
108
- valid: errors.length === 0,
109
- errors,
110
- warnings: warnings.length > 0 ? warnings : undefined
111
- };
112
- }
113
- /**
114
- * Check balanced delimiters
115
- */
116
- function checkBalancedDelimiters(dml) {
117
- const errors = [];
118
- // Remove strings and comments for delimiter checking
119
- const stripped = dml
120
- .replace(/"(?:[^"\\]|\\.)*"/g, '""') // Remove string contents
121
- .replace(/%.*$/gm, '') // Remove line comments
122
- .replace(/\/\*[\s\S]*?\*\//g, ''); // Remove block comments
123
- let parenCount = 0;
124
- let bracketCount = 0;
125
- let braceCount = 0;
126
- for (const char of stripped) {
127
- if (char === '(')
128
- parenCount++;
129
- if (char === ')')
130
- parenCount--;
131
- if (char === '[')
132
- bracketCount++;
133
- if (char === ']')
134
- bracketCount--;
135
- if (char === '{')
136
- braceCount++;
137
- if (char === '}')
138
- braceCount--;
139
- if (parenCount < 0) {
140
- errors.push('Unbalanced parentheses: extra closing )');
141
- break;
142
- }
143
- if (bracketCount < 0) {
144
- errors.push('Unbalanced brackets: extra closing ]');
145
- break;
146
- }
147
- if (braceCount < 0) {
148
- errors.push('Unbalanced braces: extra closing }');
149
- break;
150
- }
151
- }
152
- if (parenCount > 0)
153
- errors.push(`Unbalanced parentheses: ${parenCount} unclosed (`);
154
- if (bracketCount > 0)
155
- errors.push(`Unbalanced brackets: ${bracketCount} unclosed [`);
156
- if (braceCount > 0)
157
- errors.push(`Unbalanced braces: ${braceCount} unclosed {`);
158
- return { errors };
159
- }
160
- /**
161
- * Extract all string literals from DML code (both single and double quoted)
162
- */
163
- function extractStringLiterals(dml) {
164
- const doubleQuoted = [];
165
- const singleQuoted = [];
166
- // Double-quoted strings
167
- for (const m of dml.matchAll(/"((?:[^"\\]|\\.)*)"/g)) {
168
- doubleQuoted.push(m[1]);
169
- }
170
- // Single-quoted atoms
171
- for (const m of dml.matchAll(/'((?:[^'\\]|\\.)*)'/g)) {
172
- singleQuoted.push(m[1]);
173
- }
174
- return { doubleQuoted, singleQuoted };
175
- }
176
- /**
177
- * Strip comments and string contents for structural analysis
178
- */
179
- function stripForAnalysis(dml) {
180
- return dml
181
- .replace(/%.*$/gm, '') // line comments
182
- .replace(/\/\*[\s\S]*?\*\//g, '') // block comments
183
- .replace(/"(?:[^"\\]|\\.)*"/g, '""') // double-quoted string contents
184
- .replace(/'(?:[^'\\]|\\.)*'/g, "''"); // single-quoted atom contents
185
- }
186
- /**
187
- * Lint DML for common issues — focused on string handling and structural errors.
188
- * Returns errors (will crash at runtime) and warnings (likely wrong).
189
- */
190
- function lintDML(dml) {
191
- const errors = [];
192
- const warnings = [];
193
- const stripped = stripForAnalysis(dml);
194
- const { doubleQuoted, singleQuoted } = extractStringLiterals(dml);
195
- const allStrings = [...doubleQuoted, ...singleQuoted];
196
- // ═══════════════════════════════════════════════════════════════════════════
197
- // STRING HANDLING ERRORS — these WILL crash or produce wrong output
198
- // ═══════════════════════════════════════════════════════════════════════════
199
- // E1: format() passed directly to output() or answer()
200
- // format/3 binds its first arg, it does NOT return a value.
201
- // output(format("...", [...])) is always wrong.
202
- if (/output\s*\(\s*format\s*\(/.test(dml)) {
203
- errors.push('ERROR: format/3 does not return a value. `output(format(...))` will crash. Fix: format(string(S), "...", [...]), output(S).');
204
- }
205
- if (/answer\s*\(\s*format\s*\(/.test(dml)) {
206
- errors.push('ERROR: format/3 does not return a value. `answer(format(...))` will crash. Fix: format(string(S), "...", [...]), answer(S).');
207
- }
208
- // E2: ~Variable in task/prompt description strings (only ~w, ~d, ~a, ~s work with format)
209
- // task("Analyze ~Topic", R) does NOT interpolate. Use {Topic}.
210
- for (const s of doubleQuoted) {
211
- if (/~[A-Z][a-zA-Z0-9_]*/.test(s)) {
212
- errors.push(`ERROR: ~Variable interpolation does not work in DML. Found in: "...${s.substring(0, 60)}...". Use {Variable} syntax instead (e.g. {Topic} not ~Topic).`);
213
- break;
214
- }
215
- }
216
- // E3: {Variable} inside format/3 template string
217
- // format(string(S), "Hello {Name}", []) — the {Name} won't be interpolated by format.
218
- // This is a style-mixing bug.
219
- const formatCalls = dml.matchAll(/format\s*\(\s*(?:string|atom)\s*\([^)]*\)\s*,\s*"([^"]*)"/g);
220
- for (const m of formatCalls) {
221
- const tmpl = m[1];
222
- if (/\{[A-Z][a-zA-Z0-9_]*\}/.test(tmpl)) {
223
- errors.push(`ERROR: {Variable} inside format() template does nothing — format uses ~w placeholders. Found: "${tmpl.substring(0, 60)}". Use EITHER {Variable} in task() strings OR ~w in format() strings, never both in the same string.`);
224
- break;
225
- }
226
- }
227
- // E4: String concatenation with + operator
228
- // "hello" + "world" or Var + Var — Prolog's + is arithmetic only.
229
- if (/"\s*\+\s*"/.test(dml) || /"\s*\+\s*[A-Z]/.test(dml) || /[A-Z][a-zA-Z_0-9]*\s*\+\s*"/.test(dml)) {
230
- errors.push('ERROR: The + operator is arithmetic only in Prolog, not string concatenation. Use {Variable} interpolation in task() strings, or atom_concat/3, or format/3 for building strings.');
231
- }
232
- // E5: task() with non-string first arg — task(llm(...)) or task(prompt(...))
233
- if (/task\s*\(\s*(?:llm|prompt)\s*\(/.test(stripped)) {
234
- errors.push('ERROR: task() takes a plain string as first argument. task(llm(...)) and task(prompt(...)) are wrong. Use: task("description string", Var).');
235
- }
236
- // E6: Hallucinated predicates — these do NOT exist in DML runtime
237
- // But skip if user defines the predicate themselves (pred(...) :- ...).
238
- const hallucinated = [
239
- ['json_parse', 'json_parse/2 does not exist. Use task() to extract data from JSON via LLM.'],
240
- ['http_get', 'http_get does not exist. Use exec(url_fetch(url: URL), R).'],
241
- ['string_format', 'string_format does not exist. Use format(string(R), FormatStr, Args).'],
242
- ['get_field', 'get_field does not exist. Use get_dict(Key, Dict, Value) — note: Key comes first.'],
243
- ['string_join', 'string_join does not exist. Use atomic_list_concat(List, Sep, Atom).'],
244
- ['string_lower', 'string_lower does not exist. Use downcase_atom(Atom, Lower).'],
245
- ['string_trim', 'string_trim does not exist. Use normalize_space(string(Out), In).'],
246
- ['contains', 'contains/2 does not exist. Use sub_atom/5 or sub_string/5.'],
247
- ];
248
- for (const [name, msg] of hallucinated) {
249
- const usePattern = new RegExp(`(?<!\\w)${name}\\s*\\(`, 'g');
250
- if (usePattern.test(stripped)) {
251
- // Check if user defines this predicate (name(...) :- or name(...) .)
252
- const defPattern = new RegExp(`^${name}\\s*\\([^)]*\\)\\s*(?::-|\\.)`, 'm');
253
- if (!defPattern.test(stripped)) {
254
- errors.push(`ERROR: ${msg}`);
255
- }
256
- }
257
- }
258
- // E7: url_fetch used as a bare predicate (not wrapped in exec)
259
- // url_fetch("url", R) is wrong. Must be exec(url_fetch(url: "..."), R).
260
- if (/(?<!exec\s*\(\s*)url_fetch\s*\(\s*"/.test(stripped)) {
261
- errors.push('ERROR: url_fetch is not a predicate. Must use exec/2 wrapper: exec(url_fetch(url: URL), R).');
262
- }
263
- // E8: curl/wget in bash command strings
264
- for (const s of allStrings) {
265
- if (/\b(?:curl|wget)\s/.test(s)) {
266
- errors.push('ERROR: curl and wget are banned — the VM has no direct internet. Use exec(url_fetch(url: URL), R) to fetch web content.');
267
- break;
268
- }
269
- }
270
- // E9: writeln() used for user output — not a DML predicate
271
- if (/(?<!\w)writeln\s*\(/.test(stripped)) {
272
- // Check it's not inside an open/close file I/O block (write to stream is OK)
273
- // Simple heuristic: if there's no open() call, writeln is definitely wrong
274
- if (!/\bopen\s*\(/.test(stripped) || /writeln\s*\(\s*['"]/.test(dml)) {
275
- errors.push('ERROR: writeln() is not a DML output predicate. Use output() for progress messages and answer() for final results.');
276
- }
277
- }
278
- // ═══════════════════════════════════════════════════════════════════════════
279
- // STRING HANDLING WARNINGS — likely wrong, should fix
280
- // ═══════════════════════════════════════════════════════════════════════════
281
- // W1: Mixing {Variable} interpolation and format/3 in the same clause
282
- // Not always wrong (different strings), but a code smell with small models
283
- const hasInterpolation = /\{[A-Z][a-zA-Z0-9_]*\}/.test(dml);
284
- const hasFormat = /format\s*\(/.test(stripped);
285
- if (hasInterpolation && hasFormat) {
286
- warnings.push('WARNING: Code mixes {Variable} interpolation and format/3. This is allowed but can confuse the runtime if mixed in the same string. Ensure {Variable} is only in task()/output()/answer() strings and ~w is only in format() strings.');
287
- }
288
- // W2: No tool definitions — model probably wrote pure Prolog
289
- if (!/\btool\s*\(/.test(dml)) {
290
- warnings.push('WARNING: No tool() definitions found. This is fine for pure Prolog or direct exec()-only skills, but LLM-driven skills usually need tool()/3 wrappers for task() calls.');
291
- }
292
- // W3: No task() call — model probably wrote pure Prolog logic
293
- if (!/\btask\s*\(/.test(stripped)) {
294
- warnings.push('WARNING: No task() call found. This is fine for deterministic or simple skills. Skills that need open-ended reasoning, summarization, extraction, or classification should usually use task().');
295
- }
296
- // W4: No system() call — LLM has no instructions
297
- if (!/\bsystem\s*\(/.test(stripped)) {
298
- warnings.push('WARNING: No system() call found. Add system() when the skill uses task()/prompt() and the LLM needs instructions on how to use tools.');
299
- }
300
- // W5: No answer() call — skill completes silently
301
- if (!/\banswer\s*\(/.test(stripped)) {
302
- warnings.push('WARNING: No answer() call found. The skill will complete without returning a result to the user.');
303
- }
304
- // W6: No output() before task/exec — skill appears frozen
305
- if (/\btask\s*\(/.test(stripped) && !/\boutput\s*\(/.test(stripped)) {
306
- warnings.push('WARNING: No output() calls found. Add output() before long-running task() or exec() calls so the skill doesn\'t appear frozen.');
307
- }
308
- // W7: Single agent_main clause — no fallback
309
- const mainMatches = stripped.match(/agent_main\s*[\(\.]/g);
310
- if (mainMatches && mainMatches.length === 1) {
311
- warnings.push('WARNING: Only one agent_main clause. Add a fallback clause with a static error message (no LLM calls) as required by Rule 7.');
312
- }
313
- // W8: Dict dot notation — Result.field etc.
314
- // Only check outside strings — match Var.key pattern in code
315
- if (/[A-Z][a-zA-Z_0-9]*\.[a-z][a-z_]+(?!\s*\()/.test(stripped)) {
316
- warnings.push('WARNING: Possible dict dot notation (e.g. Result.stdout). This may not work — use get_dict(Key, Dict, Value) instead.');
317
- }
318
- return { errors, warnings };
319
- }
320
- /**
321
- * Basic syntax validation (fallback when Prolog fails)
322
- */
323
- function validateDMLSyntaxBasic(dml) {
324
- const errors = [];
325
- if (!dml.includes('agent_main')) {
326
- errors.push('Missing agent_main predicate');
327
- }
328
- const delimiterCheck = checkBalancedDelimiters(dml);
329
- errors.push(...delimiterCheck.errors);
330
- // Check for unclosed strings
331
- const stringPattern = /"(?:[^"\\]|\\.)*"/g;
332
- const cleanedDml = dml.replace(stringPattern, '""');
333
- if ((cleanedDml.match(/"/g) || []).length % 2 !== 0) {
334
- errors.push('Unclosed string literal');
335
- }
336
- return {
337
- valid: errors.length === 0,
338
- errors: [...new Set(errors)]
339
- };
340
- }
341
- // =============================================================================
342
- // Analysis & Auditing
343
- // =============================================================================
344
- /**
345
- * Run static analysis on the DML code
346
- */
347
- export async function analyzeDML(dml) {
348
- const swipl = await getProlog();
349
- const tempPath = `/tmp/analysis_${Date.now()}_${Math.random().toString(36).substring(7)}.dml`;
350
- try {
351
- swipl.FS.writeFile(tempPath, dml);
352
- // Query Prolog to read file and analyze
353
- const query = `
354
- read_file_to_string('${tempPath}', Code, []),
355
- deepclause_analysis:analyze_source(Code, Result).
356
- `;
357
- const result = await swipl.prolog.query(query).once();
358
- // @ts-ignore
359
- const rawAnalysis = result.Result;
360
- // Convert Prolog result to AnalysisResult
361
- // Prolog dicts come back as objects with keys
362
- const warnings = [];
363
- if (rawAnalysis.warnings && Array.isArray(rawAnalysis.warnings)) {
364
- for (const w of rawAnalysis.warnings) {
365
- let level = 'low';
366
- let message = 'Unknown warning';
367
- // Handle swipl-wasm compound term structure: { functor: 'name', name: [[args]] }
368
- let args = [];
369
- if (w.args) {
370
- args = w.args;
371
- }
372
- else if (w.functor && w[w.functor] && Array.isArray(w[w.functor])) {
373
- // It seems arguments are wrapped in a nested array: [ [Arg1, Arg2] ]
374
- const inner = w[w.functor];
375
- args = Array.isArray(inner[0]) ? inner[0] : inner;
376
- }
377
- if (args.length >= 2) {
378
- level = args[0];
379
- const msgObj = args[1];
380
- // Handle PrologString object { v: "text" }
381
- message = (typeof msgObj === 'object' && msgObj && 'v' in msgObj) ? msgObj.v : String(msgObj);
382
- }
383
- warnings.push({
384
- level: level,
385
- message
386
- });
387
- }
388
- }
389
- const capabilities = [];
390
- if (rawAnalysis.capabilities && Array.isArray(rawAnalysis.capabilities)) {
391
- for (const cap of rawAnalysis.capabilities) {
392
- if (typeof cap === 'string') {
393
- capabilities.push(cap);
394
- }
395
- else if (typeof cap === 'object' && cap) {
396
- // Handle compound terms like tool_use(name)
397
- const functor = cap.functor;
398
- if (functor) {
399
- let args = [];
400
- const inner = cap[functor];
401
- if (Array.isArray(inner) && Array.isArray(inner[0])) {
402
- args = inner[0];
403
- }
404
- if (functor === 'tool_use' && args.length > 0) {
405
- capabilities.push(`tool_use(${args[0]})`);
406
- }
407
- else {
408
- capabilities.push(`${functor}(${args.join(', ')})`);
409
- }
410
- }
411
- else {
412
- capabilities.push(String(cap));
413
- }
414
- }
415
- }
416
- }
417
- return {
418
- valid: rawAnalysis.valid === true || rawAnalysis.valid === 'true',
419
- warnings,
420
- capabilities,
421
- auditorReport: undefined,
422
- error: rawAnalysis.error ? String(rawAnalysis.error) : undefined
423
- };
424
- }
425
- catch (e) {
426
- console.warn('Analysis failed:', e);
427
- return {
428
- valid: false, // Fail if analysis throws (e.g. timeout or prolog error)
429
- warnings: [{ level: 'low', message: `Analysis failed: ${e}` }],
430
- capabilities: [],
431
- error: String(e)
432
- };
433
- }
434
- finally {
435
- try {
436
- swipl.FS.unlink(tempPath);
437
- }
438
- catch { }
439
- }
440
- }
441
- /**
442
- * Run LLM-based security audit
443
- */
444
- export async function runLLMSecurityAudit(dml, staticAnalysis, model, provider, baseUrl, usageByModel) {
445
- const llm = getLanguageModel(provider, model, baseUrl);
446
- const prompt = `
447
- You are a senior security engineer auditing a DeepClause agent (DML).
448
- DML is a Prolog dialect for controlling LLMs.
449
-
450
- RUNTIME CONSTRAINTS:
451
- - Only recommend mitigations that are actually supported by the current DeepClause runtime or standard SWI-Prolog predicates used here.
452
- - Do NOT recommend nonexistent helpers or framework features such as sanitize_for_prompt/2, structured message envelopes for task()/prompt(), or built-in ask_user rate limiting.
453
- - task()/prompt() take a plain string as their first argument. If you suggest prompt-injection mitigations, prefer prompt() for fresh context, narrower prompt text, explicit quoting/fencing of untrusted data, and minimizing tainted interpolation into system()/user().
454
- - Positional agent_main arguments arrive as runtime strings by default. If you suggest type checks, prefer must_be(string, Arg) first, then explicit parsing/conversion.
455
- - Safe concrete suggestions in this codebase include must_be/2, simple string/atom guards, explicit empty-input checks, output-shape checks written in Prolog, atom_json_dict/3, get_dict/3, prompt(), and using gas limits or explicit counters for retry loops.
456
- - If an idea would require adding a new runtime helper or framework feature, label it clearly as "not currently built in" instead of presenting it as already available.
457
- - Do not invent warnings or remediation steps when the static findings do not support them.
458
-
459
- CODE:
460
- \`\`\`prolog
461
- ${dml}
462
- \`\`\`
463
-
464
- STATIC ANALYSIS FINDINGS:
465
- ${staticAnalysis.warnings.map(w => `- [${w.level.toUpperCase()}] ${w.message}`).join('\n')}
466
-
467
- DETECTED CAPABILITIES:
468
- ${staticAnalysis.capabilities.join(', ')}
469
-
470
- TASK:
471
- Review the code for logic flaws, security risks, and bad practices.
472
- Focus on:
473
- 1. Prompt Injection: Is user input properly isolated?
474
- 2. Command Injection: Are tool arguments validated?
475
- 3. Logic: Does the flow make sense?
476
- 4. Tool Misuse: Are dangerous tools used appropriately?
477
-
478
- OUTPUT:
479
- Provide a concise Markdown report with:
480
- - Critical Issues (if any)
481
- - Warnings
482
- - Suggestions for improvement
483
-
484
- Each suggestion must be either:
485
- - A supported mitigation that exists in this runtime, or
486
- - Explicitly labeled as requiring new runtime support.
487
- `;
488
- try {
489
- const result = await generateText({
490
- model: llm,
491
- prompt,
492
- temperature: 0.1
493
- });
494
- if (result.usage && usageByModel) {
495
- recordTokenUsage(usageByModel, model, {
496
- inputTokens: result.usage.inputTokens ?? 0,
497
- outputTokens: result.usage.outputTokens ?? 0,
498
- totalTokens: result.usage.totalTokens ?? 0,
499
- });
500
- }
501
- return result.text;
502
- }
503
- catch (e) {
504
- return `Audit failed: ${e}`;
505
- }
506
- }
507
- export async function analyzeAndAuditDML(dml, options) {
508
- const analysis = await analyzeDML(dml);
509
- if (options.audit) {
510
- analysis.auditorReport = await runLLMSecurityAudit(dml, analysis, options.model, options.provider, options.baseUrl, options.usageByModel);
511
- }
512
- return analysis;
513
- }
514
- // =============================================================================
515
- // Main Compilation Function
516
- // =============================================================================
517
- /**
518
- * Compile a natural language prompt or markdown directly to DML
519
- */
520
- export async function compileToDML(source, options) {
521
- const model = options.model || 'gpt-4o';
522
- const provider = options.provider || 'openai';
523
- const maxAttempts = options.maxAttempts ?? 3;
524
- const temperature = options.temperature ?? 0.3;
525
- const tools = options.tools || [];
526
- const baseUrl = options.baseUrl;
527
- // Build the compilation prompt
528
- const systemPrompt = buildCompilationPrompt(tools);
529
- const userMessage = buildUserMessage(source);
530
- const attempts = [];
531
- let lastDml = "";
532
- let lastValidation = { valid: false, errors: [] };
533
- const usageByModel = {};
534
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
535
- try {
536
- const dml = await generateDML(systemPrompt, userMessage, attempts, model, provider, temperature, baseUrl, usageByModel);
537
- lastDml = dml;
538
- const validation = await validateWithProlog(dml);
539
- lastValidation = validation;
540
- attempts.push({ dml, validation });
541
- if (validation.valid) {
542
- // Run Static Analysis
543
- const analysis = await analyzeAndAuditDML(dml, {
544
- audit: options.audit,
545
- model,
546
- provider,
547
- baseUrl,
548
- usageByModel,
549
- });
550
- // Generate explanation
551
- const explanation = await generateExplanation(dml, model, provider, baseUrl, usageByModel);
552
- return {
553
- dml,
554
- tools: extractToolDependencies(dml),
555
- explanation,
556
- attempts: attempt,
557
- valid: true,
558
- analysis,
559
- usageByModel: Object.keys(usageByModel).length > 0 ? usageByModel : undefined,
560
- };
561
- }
562
- }
563
- catch (error) {
564
- const message = error instanceof Error ? error.message : String(error);
565
- attempts.push({
566
- dml: lastDml,
567
- validation: { valid: false, errors: [message] }
568
- });
569
- }
570
- }
571
- const allErrors = new Set(lastValidation.errors);
572
- for (const attempt of attempts) {
573
- for (const err of attempt.validation.errors) {
574
- allErrors.add(err);
575
- }
576
- }
577
- return {
578
- dml: lastDml,
579
- tools: extractToolDependencies(lastDml),
580
- valid: false,
581
- errors: Array.from(allErrors),
582
- attempts: maxAttempts,
583
- usageByModel: Object.keys(usageByModel).length > 0 ? usageByModel : undefined,
584
- };
585
- }
586
- // =============================================================================
587
- // LLM Integration
588
- // =============================================================================
589
- /**
590
- * Generate DML using LLM (non-streaming)
591
- */
592
- async function generateDML(systemPrompt, userMessage, previousAttempts, model, provider, temperature, baseUrl, usageByModel) {
593
- const llm = getLanguageModel(provider, model, baseUrl);
594
- // Build messages including previous attempts for self-correction
595
- const messages = buildMessages(systemPrompt, userMessage, previousAttempts);
596
- const result = await generateText({
597
- model: llm,
598
- messages,
599
- temperature: temperature ?? 0.3,
600
- maxOutputTokens: 8192
601
- });
602
- if (result.usage && usageByModel) {
603
- recordTokenUsage(usageByModel, model, {
604
- inputTokens: result.usage.inputTokens ?? 0,
605
- outputTokens: result.usage.outputTokens ?? 0,
606
- totalTokens: result.usage.totalTokens ?? 0,
607
- });
608
- }
609
- return cleanDMLResponse(result.text);
610
- }
611
- /**
612
- * Build messages for the compilation, including error feedback from previous attempts
613
- */
614
- function buildMessages(systemPrompt, userMessage, previousAttempts) {
615
- const messages = [
616
- { role: 'system', content: systemPrompt },
617
- { role: 'user', content: userMessage }
618
- ];
619
- // Add previous attempts and their errors for self-correction
620
- for (const attempt of previousAttempts) {
621
- messages.push({
622
- role: 'assistant',
623
- content: attempt.dml
624
- });
625
- const errorFeedback = [
626
- 'The code above has the following validation errors:',
627
- ...attempt.validation.errors.map(e => `- ${e}`),
628
- '',
629
- 'Please fix these errors and generate corrected DML code.'
630
- ].join('\n');
631
- messages.push({
632
- role: 'user',
633
- content: errorFeedback
634
- });
635
- }
636
- return messages;
637
- }
638
- /**
639
- * Generate a brief explanation of the compiled DML
640
- */
641
- async function generateExplanation(dml, model, provider, baseUrl, usageByModel) {
642
- const llm = getLanguageModel(provider, model, baseUrl);
643
- try {
644
- const result = await generateText({
645
- model: llm,
646
- system: 'You are a technical writer. Explain code briefly and clearly.',
647
- prompt: `Briefly explain what this DML program does (2-3 sentences max):\n\n\`\`\`prolog\n${dml}\n\`\`\`\n\nFocus on: what it does, what tools it uses, and how it handles input. Be concise.`,
648
- temperature: 0.3,
649
- maxOutputTokens: 256
650
- });
651
- if (result.usage && usageByModel) {
652
- recordTokenUsage(usageByModel, model, {
653
- inputTokens: result.usage.inputTokens ?? 0,
654
- outputTokens: result.usage.outputTokens ?? 0,
655
- totalTokens: result.usage.totalTokens ?? 0,
656
- });
657
- }
658
- return result.text.trim();
659
- }
660
- catch {
661
- // If explanation generation fails, return a generic message
662
- return 'DML program compiled successfully.';
663
- }
664
- }
665
- /**
666
- * Clean up LLM response - remove markdown code fences
667
- */
668
- function cleanDMLResponse(text) {
669
- let dml = text.trim();
670
- // Remove markdown code fences
671
- if (dml.startsWith('```prolog') || dml.startsWith('```')) {
672
- dml = dml.replace(/^```(?:prolog)?\n?/, '').replace(/\n?```$/, '');
673
- }
674
- return dml.trim();
675
- }
676
- /**
677
- * Get the appropriate language model instance
678
- */
679
- function getLanguageModel(provider, model, baseUrl) {
680
- // If a custom baseUrl is provided (e.g. a proxy), route all providers through it
681
- if (baseUrl) {
682
- const proxy = createOpenAI({
683
- baseURL: baseUrl,
684
- apiKey: process.env.OPENAI_API_KEY || process.env.OPENROUTER_API_KEY || 'proxy',
685
- });
686
- return proxy.chat(model);
687
- }
688
- switch (provider) {
689
- case 'openai':
690
- if (!process.env.OPENAI_API_KEY) {
691
- throw new Error('Missing OPENAI_API_KEY environment variable');
692
- }
693
- return openai(model);
694
- case 'anthropic':
695
- if (!process.env.ANTHROPIC_API_KEY) {
696
- throw new Error('Missing ANTHROPIC_API_KEY environment variable');
697
- }
698
- return anthropic(model);
699
- case 'google':
700
- if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
701
- throw new Error('Missing GOOGLE_GENERATIVE_AI_API_KEY environment variable');
702
- }
703
- return google(model);
704
- case 'openrouter': {
705
- if (!process.env.OPENROUTER_API_KEY) {
706
- throw new Error('Missing OPENROUTER_API_KEY environment variable');
707
- }
708
- const openrouter = createOpenAI({
709
- baseURL: 'https://openrouter.ai/api/v1',
710
- apiKey: process.env.OPENROUTER_API_KEY
711
- });
712
- return openrouter(model);
713
- }
714
- default:
715
- throw new Error(`Unsupported provider: ${provider}`);
716
- }
717
- }
718
- // =============================================================================
719
- // DML Analysis
720
- // =============================================================================
721
- /**
722
- * Extract tool dependencies from DML code
723
- */
724
- export function extractToolDependencies(dml) {
725
- const execPattern = /exec\s*\(\s*([a-z_][a-z0-9_]*)\s*\(/gi;
726
- const tools = new Set();
727
- let match;
728
- while ((match = execPattern.exec(dml)) !== null) {
729
- tools.add(match[1]);
730
- }
731
- return Array.from(tools).sort();
732
- }
733
- /**
734
- * Extract parameters from agent_main signature
735
- */
736
- export function extractParameters(dml) {
737
- const mainPattern = /agent_main\s*\(([^)]*)\)\s*:-/;
738
- const match = mainPattern.exec(dml);
739
- if (!match || !match[1].trim()) {
740
- return [];
741
- }
742
- const args = match[1]
743
- .split(',')
744
- .map(arg => arg.trim())
745
- .filter(arg => arg.length > 0);
746
- return args
747
- .map((arg, index) => ({
748
- name: arg.replace(/([A-Z])/g, (_m, c, i) => (i > 0 ? '_' : '') + c.toLowerCase()).replace(/^_/, ''),
749
- position: index,
750
- required: true
751
- }));
752
- }
753
- /**
754
- * Extract description from markdown
755
- */
756
- export function extractDescription(markdown) {
757
- const lines = markdown.split('\n');
758
- for (const line of lines) {
759
- if (line.startsWith('# ')) {
760
- return line.substring(2).trim();
761
- }
762
- }
763
- for (const line of lines) {
764
- const trimmed = line.trim();
765
- if (trimmed && !trimmed.startsWith('#')) {
766
- return trimmed.substring(0, 100);
767
- }
768
- }
769
- return 'No description';
770
- }
6
+ export { validateWithProlog } from './validate.js';
771
7
  //# sourceMappingURL=compiler.js.map