deepclause-sdk 0.0.89 → 0.1.1

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 (329) hide show
  1. package/README.md +481 -941
  2. package/dist/agent.d.ts +19 -2
  3. package/dist/agent.d.ts.map +1 -1
  4. package/dist/agent.js +75 -21
  5. package/dist/agent.js.map +1 -1
  6. package/dist/cli/config.d.ts +385 -178
  7. package/dist/cli/config.d.ts.map +1 -1
  8. package/dist/cli/config.js +161 -188
  9. package/dist/cli/config.js.map +1 -1
  10. package/dist/cli/index.d.ts +3 -2
  11. package/dist/cli/index.d.ts.map +1 -1
  12. package/dist/cli/index.js +85 -411
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cli/login.d.ts +29 -0
  15. package/dist/cli/login.d.ts.map +1 -0
  16. package/dist/cli/login.js +184 -0
  17. package/dist/cli/login.js.map +1 -0
  18. package/dist/cli/readline.d.ts +6 -0
  19. package/dist/cli/readline.d.ts.map +1 -0
  20. package/dist/cli/readline.js +15 -0
  21. package/dist/cli/readline.js.map +1 -0
  22. package/dist/cli/repl-bin.d.ts +9 -0
  23. package/dist/cli/repl-bin.d.ts.map +1 -0
  24. package/dist/cli/repl-bin.js +16 -0
  25. package/dist/cli/repl-bin.js.map +1 -0
  26. package/dist/cli/repl.d.ts +216 -0
  27. package/dist/cli/repl.d.ts.map +1 -0
  28. package/dist/cli/repl.js +1392 -0
  29. package/dist/cli/repl.js.map +1 -0
  30. package/dist/cli/run.d.ts +17 -18
  31. package/dist/cli/run.d.ts.map +1 -1
  32. package/dist/cli/run.js +202 -183
  33. package/dist/cli/run.js.map +1 -1
  34. package/dist/cli/set-backend.d.ts +53 -0
  35. package/dist/cli/set-backend.d.ts.map +1 -0
  36. package/dist/cli/set-backend.js +259 -0
  37. package/dist/cli/set-backend.js.map +1 -0
  38. package/dist/cli/visualize.d.ts +42 -0
  39. package/dist/cli/visualize.d.ts.map +1 -0
  40. package/dist/cli/visualize.js +150 -0
  41. package/dist/cli/visualize.js.map +1 -0
  42. package/dist/compiler.d.ts +5 -52
  43. package/dist/compiler.d.ts.map +1 -1
  44. package/dist/compiler.js +4 -768
  45. package/dist/compiler.js.map +1 -1
  46. package/dist/index.d.ts +27 -2
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +18 -2
  49. package/dist/index.js.map +1 -1
  50. package/dist/prolog/bridge.d.ts +5 -1
  51. package/dist/prolog/bridge.d.ts.map +1 -1
  52. package/dist/prolog/bridge.js +10 -1
  53. package/dist/prolog/bridge.js.map +1 -1
  54. package/dist/prolog-src/deepclause_analysis.pl +10 -2
  55. package/dist/prolog-src/deepclause_mi.pl +2440 -49
  56. package/dist/repl/agent.d.ts +90 -0
  57. package/dist/repl/agent.d.ts.map +1 -0
  58. package/dist/repl/agent.js +410 -0
  59. package/dist/repl/agent.js.map +1 -0
  60. package/dist/repl/auth.d.ts +45 -0
  61. package/dist/repl/auth.d.ts.map +1 -0
  62. package/dist/repl/auth.js +116 -0
  63. package/dist/repl/auth.js.map +1 -0
  64. package/dist/repl/backend.d.ts +321 -0
  65. package/dist/repl/backend.d.ts.map +1 -0
  66. package/dist/repl/backend.js +415 -0
  67. package/dist/repl/backend.js.map +1 -0
  68. package/dist/repl/compaction.d.ts +122 -0
  69. package/dist/repl/compaction.d.ts.map +1 -0
  70. package/dist/repl/compaction.js +318 -0
  71. package/dist/repl/compaction.js.map +1 -0
  72. package/dist/repl/export.d.ts +30 -0
  73. package/dist/repl/export.d.ts.map +1 -0
  74. package/dist/repl/export.js +23 -0
  75. package/dist/repl/export.js.map +1 -0
  76. package/dist/repl/frames.d.ts +21 -0
  77. package/dist/repl/frames.d.ts.map +1 -0
  78. package/dist/repl/frames.js +79 -0
  79. package/dist/repl/frames.js.map +1 -0
  80. package/dist/repl/harness-tools.d.ts +99 -0
  81. package/dist/repl/harness-tools.d.ts.map +1 -0
  82. package/dist/repl/harness-tools.js +192 -0
  83. package/dist/repl/harness-tools.js.map +1 -0
  84. package/dist/repl/highlight.d.ts +30 -0
  85. package/dist/repl/highlight.d.ts.map +1 -0
  86. package/dist/repl/highlight.js +285 -0
  87. package/dist/repl/highlight.js.map +1 -0
  88. package/dist/repl/history.d.ts +234 -0
  89. package/dist/repl/history.d.ts.map +1 -0
  90. package/dist/repl/history.js +661 -0
  91. package/dist/repl/history.js.map +1 -0
  92. package/dist/repl/imagegen.d.ts +29 -0
  93. package/dist/repl/imagegen.d.ts.map +1 -0
  94. package/dist/repl/imagegen.js +84 -0
  95. package/dist/repl/imagegen.js.map +1 -0
  96. package/dist/repl/index.d.ts +130 -0
  97. package/dist/repl/index.d.ts.map +1 -0
  98. package/dist/repl/index.js +112 -0
  99. package/dist/repl/index.js.map +1 -0
  100. package/dist/repl/judge.d.ts +51 -0
  101. package/dist/repl/judge.d.ts.map +1 -0
  102. package/dist/repl/judge.js +58 -0
  103. package/dist/repl/judge.js.map +1 -0
  104. package/dist/repl/markdown.d.ts +25 -0
  105. package/dist/repl/markdown.d.ts.map +1 -0
  106. package/dist/repl/markdown.js +103 -0
  107. package/dist/repl/markdown.js.map +1 -0
  108. package/dist/repl/model-resolver.d.ts +59 -0
  109. package/dist/repl/model-resolver.d.ts.map +1 -0
  110. package/dist/repl/model-resolver.js +156 -0
  111. package/dist/repl/model-resolver.js.map +1 -0
  112. package/dist/repl/picker.d.ts +34 -0
  113. package/dist/repl/picker.d.ts.map +1 -0
  114. package/dist/repl/picker.js +81 -0
  115. package/dist/repl/picker.js.map +1 -0
  116. package/dist/repl/project-context.d.ts +16 -0
  117. package/dist/repl/project-context.d.ts.map +1 -0
  118. package/dist/repl/project-context.js +23 -0
  119. package/dist/repl/project-context.js.map +1 -0
  120. package/dist/repl/render.d.ts +187 -0
  121. package/dist/repl/render.d.ts.map +1 -0
  122. package/dist/repl/render.js +808 -0
  123. package/dist/repl/render.js.map +1 -0
  124. package/dist/repl/session.d.ts +424 -0
  125. package/dist/repl/session.d.ts.map +1 -0
  126. package/dist/repl/session.js +1473 -0
  127. package/dist/repl/session.js.map +1 -0
  128. package/dist/repl/status.d.ts +100 -0
  129. package/dist/repl/status.d.ts.map +1 -0
  130. package/dist/repl/status.js +218 -0
  131. package/dist/repl/status.js.map +1 -0
  132. package/dist/repl/tools.d.ts +53 -0
  133. package/dist/repl/tools.d.ts.map +1 -0
  134. package/dist/repl/tools.js +307 -0
  135. package/dist/repl/tools.js.map +1 -0
  136. package/dist/repl/toolset.d.ts +32 -0
  137. package/dist/repl/toolset.d.ts.map +1 -0
  138. package/dist/repl/toolset.js +82 -0
  139. package/dist/repl/toolset.js.map +1 -0
  140. package/dist/repl/tui/editor.d.ts +17 -0
  141. package/dist/repl/tui/editor.d.ts.map +1 -0
  142. package/dist/repl/tui/editor.js +39 -0
  143. package/dist/repl/tui/editor.js.map +1 -0
  144. package/dist/repl/tui/status-bar.d.ts +26 -0
  145. package/dist/repl/tui/status-bar.d.ts.map +1 -0
  146. package/dist/repl/tui/status-bar.js +47 -0
  147. package/dist/repl/tui/status-bar.js.map +1 -0
  148. package/dist/repl/tui/theme.d.ts +30 -0
  149. package/dist/repl/tui/theme.d.ts.map +1 -0
  150. package/dist/repl/tui/theme.js +81 -0
  151. package/dist/repl/tui/theme.js.map +1 -0
  152. package/dist/repl/tui/transcript.d.ts +41 -0
  153. package/dist/repl/tui/transcript.d.ts.map +1 -0
  154. package/dist/repl/tui/transcript.js +139 -0
  155. package/dist/repl/tui/transcript.js.map +1 -0
  156. package/dist/runner.d.ts +143 -13
  157. package/dist/runner.d.ts.map +1 -1
  158. package/dist/runner.js +532 -290
  159. package/dist/runner.js.map +1 -1
  160. package/dist/sdk.d.ts.map +1 -1
  161. package/dist/sdk.js +0 -32
  162. package/dist/sdk.js.map +1 -1
  163. package/dist/system/assets/docs/AGENT_PROMPT.md +1447 -0
  164. package/dist/system/assets/docs/DML_AUTHORING.md +195 -0
  165. package/dist/system/assets/docs/DML_REFERENCE.md +344 -72
  166. package/dist/system/assets/docs/HARNESS_EXAMPLES.md +172 -0
  167. package/dist/system/assets/docs/HARNESS_PATTERNS.md +562 -0
  168. package/dist/system/assets/docs/META_PROMPT.md +68 -0
  169. package/dist/system/assets/docs/PROLOG_SNIPPETS.md +117 -0
  170. package/dist/system/assets/index.d.ts +9 -17
  171. package/dist/system/assets/index.d.ts.map +1 -1
  172. package/dist/system/assets/index.js +26 -85
  173. package/dist/system/assets/index.js.map +1 -1
  174. package/dist/system/runtime/agentvm-manager.d.ts +9 -2
  175. package/dist/system/runtime/agentvm-manager.d.ts.map +1 -1
  176. package/dist/system/runtime/agentvm-manager.js +70 -44
  177. package/dist/system/runtime/agentvm-manager.js.map +1 -1
  178. package/dist/system/runtime/media.d.ts +23 -0
  179. package/dist/system/runtime/media.d.ts.map +1 -0
  180. package/dist/system/runtime/media.js +55 -0
  181. package/dist/system/runtime/media.js.map +1 -0
  182. package/dist/system/runtime/shell-limits.d.ts +21 -0
  183. package/dist/system/runtime/shell-limits.d.ts.map +1 -0
  184. package/dist/system/runtime/shell-limits.js +39 -0
  185. package/dist/system/runtime/shell-limits.js.map +1 -0
  186. package/dist/system/runtime/shell-manager.d.ts +8 -3
  187. package/dist/system/runtime/shell-manager.d.ts.map +1 -1
  188. package/dist/system/runtime/shell-manager.js +56 -39
  189. package/dist/system/runtime/shell-manager.js.map +1 -1
  190. package/dist/system/runtime/shell-tool-events.js +5 -0
  191. package/dist/system/runtime/shell-tool-events.js.map +1 -1
  192. package/dist/system/runtime/token-usage.d.ts +2 -0
  193. package/dist/system/runtime/token-usage.d.ts.map +1 -1
  194. package/dist/system/runtime/token-usage.js +7 -0
  195. package/dist/system/runtime/token-usage.js.map +1 -1
  196. package/dist/tools.d.ts +3 -21
  197. package/dist/tools.d.ts.map +1 -1
  198. package/dist/tools.js +14 -168
  199. package/dist/tools.js.map +1 -1
  200. package/dist/types.d.ts +136 -119
  201. package/dist/types.d.ts.map +1 -1
  202. package/dist/validate.d.ts +19 -0
  203. package/dist/validate.d.ts.map +1 -0
  204. package/dist/validate.js +338 -0
  205. package/dist/validate.js.map +1 -0
  206. package/dist/visualize/ascii.d.ts +55 -0
  207. package/dist/visualize/ascii.d.ts.map +1 -0
  208. package/dist/visualize/ascii.js +242 -0
  209. package/dist/visualize/ascii.js.map +1 -0
  210. package/dist/visualize/display.d.ts +24 -0
  211. package/dist/visualize/display.d.ts.map +1 -0
  212. package/dist/visualize/display.js +29 -0
  213. package/dist/visualize/display.js.map +1 -0
  214. package/dist/visualize/graphics.d.ts +35 -0
  215. package/dist/visualize/graphics.d.ts.map +1 -0
  216. package/dist/visualize/graphics.js +96 -0
  217. package/dist/visualize/graphics.js.map +1 -0
  218. package/dist/visualize/image.d.ts +38 -0
  219. package/dist/visualize/image.d.ts.map +1 -0
  220. package/dist/visualize/image.js +95 -0
  221. package/dist/visualize/image.js.map +1 -0
  222. package/dist/visualize/index.d.ts +59 -0
  223. package/dist/visualize/index.d.ts.map +1 -0
  224. package/dist/visualize/index.js +198 -0
  225. package/dist/visualize/index.js.map +1 -0
  226. package/dist/visualize/raster.d.ts +23 -0
  227. package/dist/visualize/raster.d.ts.map +1 -0
  228. package/dist/visualize/raster.js +47 -0
  229. package/dist/visualize/raster.js.map +1 -0
  230. package/dist/visualize/svg.d.ts +39 -0
  231. package/dist/visualize/svg.d.ts.map +1 -0
  232. package/dist/visualize/svg.js +148 -0
  233. package/dist/visualize/svg.js.map +1 -0
  234. package/dist/visualize/transcode.d.ts +13 -0
  235. package/dist/visualize/transcode.d.ts.map +1 -0
  236. package/dist/visualize/transcode.js +40 -0
  237. package/dist/visualize/transcode.js.map +1 -0
  238. package/docs/images/repl.png +0 -0
  239. package/package.json +19 -15
  240. package/src/prolog-src/deepclause_analysis.pl +10 -2
  241. package/src/prolog-src/deepclause_mi.pl +2440 -49
  242. package/dist/cli/commands.d.ts +0 -42
  243. package/dist/cli/commands.d.ts.map +0 -1
  244. package/dist/cli/commands.js +0 -246
  245. package/dist/cli/commands.js.map +0 -1
  246. package/dist/cli/compile.d.ts +0 -99
  247. package/dist/cli/compile.d.ts.map +0 -1
  248. package/dist/cli/compile.js +0 -363
  249. package/dist/cli/compile.js.map +0 -1
  250. package/dist/cli/default-skills.d.ts +0 -10
  251. package/dist/cli/default-skills.d.ts.map +0 -1
  252. package/dist/cli/default-skills.js +0 -206
  253. package/dist/cli/default-skills.js.map +0 -1
  254. package/dist/cli/interactive.d.ts +0 -2
  255. package/dist/cli/interactive.d.ts.map +0 -1
  256. package/dist/cli/interactive.js +0 -20
  257. package/dist/cli/interactive.js.map +0 -1
  258. package/dist/cli/mcp.d.ts +0 -56
  259. package/dist/cli/mcp.d.ts.map +0 -1
  260. package/dist/cli/mcp.js +0 -138
  261. package/dist/cli/mcp.js.map +0 -1
  262. package/dist/cli/prompt.d.ts +0 -2
  263. package/dist/cli/prompt.d.ts.map +0 -1
  264. package/dist/cli/prompt.js +0 -2
  265. package/dist/cli/prompt.js.map +0 -1
  266. package/dist/cli/search.d.ts +0 -19
  267. package/dist/cli/search.d.ts.map +0 -1
  268. package/dist/cli/search.js +0 -189
  269. package/dist/cli/search.js.map +0 -1
  270. package/dist/cli/tool-args.d.ts +0 -2
  271. package/dist/cli/tool-args.d.ts.map +0 -1
  272. package/dist/cli/tool-args.js +0 -39
  273. package/dist/cli/tool-args.js.map +0 -1
  274. package/dist/cli/tools.d.ts +0 -36
  275. package/dist/cli/tools.d.ts.map +0 -1
  276. package/dist/cli/tools.js +0 -229
  277. package/dist/cli/tools.js.map +0 -1
  278. package/dist/cli/tui/index.d.ts +0 -22
  279. package/dist/cli/tui/index.d.ts.map +0 -1
  280. package/dist/cli/tui/index.js +0 -29
  281. package/dist/cli/tui/index.js.map +0 -1
  282. package/dist/cli/tui.d.ts +0 -167
  283. package/dist/cli/tui.d.ts.map +0 -1
  284. package/dist/cli/tui.js +0 -5228
  285. package/dist/cli/tui.js.map +0 -1
  286. package/dist/compiler_prompt.d.ts +0 -20
  287. package/dist/compiler_prompt.d.ts.map +0 -1
  288. package/dist/compiler_prompt.js +0 -870
  289. package/dist/compiler_prompt.js.map +0 -1
  290. package/dist/deepclause-cli.skill +0 -0
  291. package/dist/prolog-src/deepclause_mi.pl.bak +0 -570
  292. package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +0 -105
  293. package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +0 -700
  294. package/dist/system/assets/docs/TUI.md +0 -150
  295. package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +0 -100
  296. package/dist/system/assets/skills/conductor.dml +0 -76
  297. package/dist/system/assets/skills/deep-planner.dml +0 -412
  298. package/dist/system/assets/skills/plan.dml +0 -429
  299. package/dist/system/assets/skills/security-planner.dml +0 -337
  300. package/dist/system/assets/skills/skill-creator.dml +0 -187
  301. package/dist/system/runtime/catalog-recipes.d.ts +0 -24
  302. package/dist/system/runtime/catalog-recipes.d.ts.map +0 -1
  303. package/dist/system/runtime/catalog-recipes.js +0 -273
  304. package/dist/system/runtime/catalog-recipes.js.map +0 -1
  305. package/dist/system/runtime/catalog-skills.d.ts +0 -50
  306. package/dist/system/runtime/catalog-skills.d.ts.map +0 -1
  307. package/dist/system/runtime/catalog-skills.js +0 -152
  308. package/dist/system/runtime/catalog-skills.js.map +0 -1
  309. package/dist/system/runtime/conductor.d.ts +0 -105
  310. package/dist/system/runtime/conductor.d.ts.map +0 -1
  311. package/dist/system/runtime/conductor.js +0 -732
  312. package/dist/system/runtime/conductor.js.map +0 -1
  313. package/dist/system/runtime/console-capture.d.ts +0 -9
  314. package/dist/system/runtime/console-capture.d.ts.map +0 -1
  315. package/dist/system/runtime/console-capture.js +0 -67
  316. package/dist/system/runtime/console-capture.js.map +0 -1
  317. package/dist/system/runtime/dml-executor.d.ts +0 -52
  318. package/dist/system/runtime/dml-executor.d.ts.map +0 -1
  319. package/dist/system/runtime/dml-executor.js +0 -203
  320. package/dist/system/runtime/dml-executor.js.map +0 -1
  321. package/dist/system/runtime/runtime-tools.d.ts +0 -31
  322. package/dist/system/runtime/runtime-tools.d.ts.map +0 -1
  323. package/dist/system/runtime/runtime-tools.js +0 -312
  324. package/dist/system/runtime/runtime-tools.js.map +0 -1
  325. package/dist/system/runtime/skill-creator.d.ts +0 -38
  326. package/dist/system/runtime/skill-creator.d.ts.map +0 -1
  327. package/dist/system/runtime/skill-creator.js +0 -763
  328. package/dist/system/runtime/skill-creator.js.map +0 -1
  329. package/src/prolog-src/deepclause_mi.pl.bak +0 -570
@@ -11,10 +11,10 @@
11
11
  - [exec/2](#exec2)
12
12
  - [Tool Definitions](#tool-definitions)
13
13
  - [Tool Scoping](#tool-scoping)
14
+ - [Model Selection](#model-selection)
14
15
  - [system/1, user/1](#memory-predicates)
15
16
  - [output/1, yield/1, log/1](#output-predicates)
16
17
  - [answer/1](#answer1)
17
- - [param/3](#param3)
18
18
  - [Control Flow](#control-flow)
19
19
  - [String Interpolation](#string-interpolation)
20
20
  - [Backtracking](#backtracking)
@@ -58,7 +58,7 @@ agent_main :-
58
58
  ```
59
59
 
60
60
  ### agent_main/1
61
- Receives the first parameter:
61
+ Receives the first argument:
62
62
  ```prolog
63
63
  agent_main(Name) :-
64
64
  format(string(Msg), "Hello, ~w!", [Name]),
@@ -66,7 +66,7 @@ agent_main(Name) :-
66
66
  ```
67
67
 
68
68
  ### agent_main/2
69
- Receives first two parameters:
69
+ Receives the first two arguments:
70
70
  ```prolog
71
71
  agent_main(Name, Task) :-
72
72
  system("You are a helpful assistant."),
@@ -142,6 +142,23 @@ agent_main :-
142
142
 
143
143
  Bind up to three variables.
144
144
 
145
+ > **Note — `task/N` is load-time sugar.** `task/1,2,3,4` and `prompt/2,3,4` are
146
+ > rewritten by the DML loader into `task_named/3` / `prompt_named/3` with typed
147
+ > output variables. The rewrite runs whenever code is loaded (`deepclause run`,
148
+ > the REPL `-l` and commit paths, `consult`, and the REPL `assert`/`assert_many`
149
+ > tools). The untransformed form has no runtime handler,
150
+ > so code that somehow reaches the runtime without the rewrite raises
151
+ > `domain_error(unrewritten_task_form, Goal)` instead of failing silently.
152
+ > `task/1`/`prompt/1` are handled directly and are unaffected.
153
+
154
+ > **Internal note.** At load time `task/N`/`prompt/N` are rewritten to
155
+ > `task_named/3`/`prompt_named/3` (which carry the output-variable names) and
156
+ > `{Var}` descriptions are hoisted into a `format/3`. That is why a description
157
+ > like `task("Answer: {Question}", Answer)` sometimes *appears* as
158
+ > `format(string(C), "Answer: ~w", [Question]), task_named(C, [Answer], ...)`.
159
+ > `listing` and `export` reverse this, so you always read/write `task/N` and
160
+ > `prompt/N` — never author `task_named/3` yourself.
161
+
145
162
  ### Type-Safe Output Variables
146
163
 
147
164
  You can wrap output variables with type specifiers to enforce strict validation on the LLM's output. The runtime will ensure the value matches the specified type.
@@ -200,38 +217,66 @@ Or positional if the tool supports it:
200
217
  exec(get_time, CurrentTime)
201
218
  ```
202
219
 
220
+ The `bash` tool accepts an optional wall-clock `timeoutMs` and always returns the
221
+ wall-clock duration as `timeMs`:
222
+
223
+ ```prolog
224
+ exec(bash(command: "sleep 30", timeoutMs: 5000), R),
225
+ get_dict(timeMs, R, Took),
226
+ ( get_dict(exitCode, R, 124)
227
+ -> format(string(Msg), "timed out after ~w ms", [Took])
228
+ ; format(string(Msg), "finished in ~w ms", [Took])
229
+ ).
230
+ ```
231
+
232
+ A command is also killed when it produces no output for `DC_HOST_SHELL_IDLE_TIMEOUT_MS`
233
+ (default 180 000 ms); `DC_HOST_SHELL_TIMEOUT_MS` sets a default wall-clock cap
234
+ (0 = disabled). Exit code `124` means a timeout.
235
+
203
236
  ---
204
237
 
205
238
  ### Tool Definitions
206
239
 
207
- Define tools in DML that the LLM can call during `task()`. Tools use the `tool/2` predicate with a description:
240
+ `tool/2` is an **annotation**, not an implementation. It exposes an existing
241
+ harness predicate to the nested agent that runs inside `task/N`. Define the
242
+ predicate normally, then add a `tool/2` clause that delegates to it:
208
243
 
209
244
  ```prolog
210
- % Define a tool - makes it available to the LLM with description
211
- tool(calculate(Expression, Result), "Calculate a mathematical expression") :-
212
- exec(calculator(expression: Expression), Result).
245
+ % 1. The capability: a normal predicate, callable from `execute` and `/goal`.
246
+ count_words(File, Count) :-
247
+ script_file(count_words, Script),
248
+ format(atom(Cmd), "python3 '~w' '~w'", [Script, File]),
249
+ exec(bash(command: Cmd), Result),
250
+ get_dict(stdout, Result, Count).
213
251
 
214
- agent_main :-
215
- system("You have a calculate tool."),
216
- task("What is the square root of 144?"),
217
- answer("Done").
252
+ % 2. The annotation: exposes it to the nested agent. Thin body only.
253
+ tool(count_words(File, Count), "Count words in a workspace file.") :-
254
+ count_words(File, Count).
218
255
  ```
219
256
 
220
- Tool definitions have the form:
257
+ A predicate defined *only* inside a `tool/2` clause is invisible to
258
+ `execute` / `/goal` — the loader asserts it as `tool(Head)`, never as `Head`. Split
259
+ the two so one implementation is reachable from both surfaces:
260
+
221
261
  ```prolog
222
- tool(name(Arg1, Arg2, ..., Result), "Description") :- Body.
262
+ /goal count_words("report.txt", C). % authoring agent
263
+ task("Count the words in report.txt.", N). % nested agent calls the tool
223
264
  ```
224
265
 
225
- The last argument is typically the output. The description is shown to the LLM.
226
- ```
266
+ The tool head's **last argument is the output**; the description is shown to the
267
+ nested agent. Keep the `tool/2` body a single delegation — put no logic in it.
268
+
269
+ Logic lives in the predicate, not the annotation:
227
270
 
228
- You can add Prolog logic in tool implementations:
229
271
  ```prolog
230
- tool(safe_divide(A, B, Result), "Safely divide two numbers") :-
272
+ safe_divide(A, B, Result) :-
231
273
  ( B =:= 0
232
274
  -> Result = error("Division by zero")
233
- ; exec(calculator(expression: A/B), Result)
275
+ ; Result is A / B
234
276
  ).
277
+
278
+ tool(safe_divide(A, B, Result), "Safely divide two numbers.") :-
279
+ safe_divide(A, B, Result).
235
280
  ```
236
281
 
237
282
  #### Using `task()` Inside Tools
@@ -239,20 +284,22 @@ tool(safe_divide(A, B, Result), "Safely divide two numbers") :-
239
284
  Tools can use `task()` and `prompt()` internally to combine Prolog logic with LLM reasoning:
240
285
 
241
286
  ```prolog
242
- % A tool that computes then explains
243
- :- tool(explain_calculation(A, B), "Calculate and explain the result").
244
-
245
- tool(explain_calculation(A, B, Explanation)) :-
287
+ % A predicate that computes then explains.
288
+ explain_calculation(A, B, Explanation) :-
246
289
  Sum is A + B, % Prolog computation
247
290
  format(string(Desc), "Explain ~w + ~w = ~w to a child", [A, B, Sum]),
248
291
  task(Desc, Explanation). % LLM explanation
249
292
 
250
- % A tool that uses LLM for formatting
251
- :- tool(format_data(Data), "Format data nicely using LLM").
293
+ tool(explain_calculation(A, B, Explanation), "Calculate and explain the result.") :-
294
+ explain_calculation(A, B, Explanation).
252
295
 
253
- tool(format_data(Data, FormattedOutput)) :-
296
+ % A predicate that uses the LLM for formatting.
297
+ format_data(Data, FormattedOutput) :-
254
298
  format(string(Desc), "Format this data nicely: ~w", [Data]),
255
299
  task(Desc, FormattedOutput).
300
+
301
+ tool(format_data(Data, FormattedOutput), "Format data nicely using LLM.") :-
302
+ format_data(Data, FormattedOutput).
256
303
  ```
257
304
 
258
305
  **Memory Isolation:** When `task()` or `prompt()` runs inside a tool, the nested agent starts with **fresh memory**. It does NOT inherit the parent's accumulated memory from `system()`, `user()`, or previous `task()` calls. If you need context in a nested task, pass it explicitly as a tool argument or add it with `system()` inside the tool body.
@@ -260,12 +307,16 @@ tool(format_data(Data, FormattedOutput)) :-
260
307
  **Tool Access:** The nested agent has access to all DML tools **except** the tool that is currently executing (automatic call stack exclusion to prevent infinite recursion). You can further control tool access using `with_tools/2` and `without_tools/2`.
261
308
 
262
309
  ```prolog
263
- % Example: Passing context explicitly
264
- tool(smart_search(Context, Query, Summary), "Search with context") :-
265
- system(Context), % Add context to nested task's memory
266
- exec(web_search(query: Query), Results),
267
- format(string(Desc), "Summarize: ~w", [Results]),
310
+ % Example: passing context explicitly.
311
+ smart_grep(BuildContext, Pattern, Summary) :-
312
+ system(BuildContext), % add context to the nested task's memory
313
+ format(atom(Cmd), "grep -rn '~w' .", [Pattern]),
314
+ exec(bash(command: Cmd), Results),
315
+ format(string(Desc), "Summarize these matches: ~w", [Results]),
268
316
  task(Desc, Summary).
317
+
318
+ tool(smart_grep(BuildContext, Pattern, Summary), "Grep with context.") :-
319
+ smart_grep(BuildContext, Pattern, Summary).
269
320
  ```
270
321
 
271
322
  ---
@@ -309,7 +360,7 @@ agent_main :-
309
360
  system("You are a safe assistant."),
310
361
 
311
362
  % Run task with only safe tools
312
- with_tools([read_file, list_files], (
363
+ with_tools([search, fetch_page], (
313
364
  task("Analyze the files in the workspace.", Analysis)
314
365
  )),
315
366
 
@@ -321,6 +372,37 @@ agent_main :-
321
372
 
322
373
  ---
323
374
 
375
+ ### Model Selection
376
+
377
+ #### `with_model(+Spec, +Goal)`
378
+
379
+ Run `Goal` with a different model — and optionally a reasoning level — for every
380
+ `task/N`, `prompt/N` and `sample_token/N` call inside it. Judgments
381
+ (`choose/rate/verify/probability`) are not affected.
382
+
383
+ ```prolog
384
+ % a cheap model for classification
385
+ with_model("openai:gpt-4o-mini",
386
+ prompt("Classify as billing/orders/account: {Message}", Team)).
387
+
388
+ % a strong model with high reasoning, only for the hard step
389
+ with_model("anthropic:claude-sonnet-4#high",
390
+ task("Review this diff and list defects:\n{Diff}", Notes)).
391
+
392
+ % full control with a dict
393
+ with_model(model{provider: "google", id: "gemini-2.5-pro",
394
+ temperature: 0.2, maxTokens: 8192}, Goal).
395
+ ```
396
+
397
+ `Spec` is a string — `"provider:model"`, `"provider/model"`, `"model"`, each with
398
+ an optional `#reasoning` suffix (`off|minimal|low|medium|high|xhigh|max`) — or a
399
+ `model{provider, id, temperature, maxTokens, reasoning}` dict. The innermost
400
+ `with_model` wins, and a nested `with_reasoning/2` overrides the spec's reasoning.
401
+ The default is the session's active model. An unknown or unsigned-in model fails
402
+ with a clear error.
403
+
404
+ ---
405
+
324
406
  ### Memory Predicates
325
407
 
326
408
  Memory predicates build the conversation context sent to the LLM.
@@ -351,6 +433,68 @@ agent_main :-
351
433
 
352
434
  ---
353
435
 
436
+ ### Media Predicates
437
+
438
+ Images are **workspace files**; DML carries only a reference. See
439
+ `docs/DML_MEDIA.md`.
440
+
441
+ #### `read_media(+Path, -Media)`
442
+
443
+ Bind `Media = media(Path, Mime)` for a workspace-relative image (PNG, JPEG, GIF,
444
+ WebP). The bytes are not read into Prolog.
445
+
446
+ #### `attach_media(+Media)`
447
+
448
+ Append the image to conversation memory (reference only), so the next `task/N`
449
+ call sends it to the model as an image block:
450
+
451
+ ```prolog
452
+ agent_main :-
453
+ read_media("photos/fox.png", Img),
454
+ attach_media(Img),
455
+ task("Describe the image in one sentence.", Description),
456
+ answer(Description).
457
+ ```
458
+
459
+ Memory stores `media{path, mime}` — never the image bytes. Judgments
460
+ (`choose`/`rate`/`verify`/`probability`) stay text-only.
461
+
462
+ ---
463
+
464
+ ### File I/O and paths — prefer the shell
465
+
466
+ **Prefer `exec(bash(...))` for file operations.**
467
+ Reading, writing, copying, or converting files is usually clearer and more
468
+ robust as a shell command; reach for the DML predicates below only when the
469
+ content must be bound and reasoned over inside Prolog. Pulling a file into DML
470
+ just to hand it back to the shell is a smell (`DML_AUTHORING.md` §2).
471
+
472
+ If you do use them: every path in DML is **workspace-relative** and confined to
473
+ the workspace. The
474
+ engine mounts the workspace at `/workspace`, but you must not write
475
+ `/workspace/...` in DML — passing an absolute path is rejected, as is `..`. File
476
+ predicates all take a relative path:
477
+
478
+ ```prolog
479
+ read_file("images/a.png", Bytes),
480
+ write_file("out/report.txt", Text),
481
+ make_directory_path("out/nested"), % create a directory (and parents)
482
+ append_file("out/log.txt", Line),
483
+ delete_file("out/report.txt"),
484
+ directory_files("images", Names), % bare entry names: ["a.png", ...]
485
+ exists_file("images/a.png"),
486
+ size_file("images/a.png", Size),
487
+ time_file("images/a.png", Modified).
488
+ ```
489
+
490
+ `write_file/2` does **not** create parent directories — call
491
+ `make_directory_path/1` first. `directory_files/2` returns bare entry names (no
492
+ directory), so build a path with `atom_concat('images/', Name, Path)` when you
493
+ need one. `bash` runs with a wider view of the sandbox than DML has; convert
494
+ anything from the shell to a workspace-relative path before handing it to DML.
495
+
496
+ ---
497
+
354
498
  ### Output Predicates
355
499
 
356
500
  #### `output(+Text)`
@@ -397,25 +541,6 @@ agent_main :-
397
541
 
398
542
  ---
399
543
 
400
- ### `param(+Key, +Description, -Value)`
401
-
402
- Access parameters passed from the caller:
403
-
404
- ```prolog
405
- agent_main :-
406
- param(name, "User's name", Name),
407
- param(age, "User's age", Age),
408
- format(string(Msg), "Hello ~w, you are ~w years old!", [Name, Age]),
409
- answer(Msg).
410
- ```
411
-
412
- Called from TypeScript:
413
- ```typescript
414
- dc.runDML(code, { params: { name: 'Alice', age: 30 } });
415
- ```
416
-
417
- ---
418
-
419
544
  ## Control Flow
420
545
 
421
546
  DML supports standard Prolog control flow:
@@ -460,14 +585,13 @@ throw(Error)
460
585
 
461
586
  ## String Interpolation
462
587
 
463
- Text arguments support `{variable}` interpolation with parameters:
588
+ Text arguments support `{variable}` interpolation with bound variables:
464
589
 
465
590
  ```prolog
466
- agent_main :-
467
- param(topic, "Research topic", Topic),
591
+ agent_main(Topic) :-
468
592
  system("You are a research assistant."),
469
- task("Research the topic: {topic}"), % Topic is interpolated
470
- answer("Research on {topic} complete!").
593
+ task("Research the topic: {Topic}"), % Topic is interpolated
594
+ answer("Research on {Topic} complete!").
471
595
  ```
472
596
 
473
597
  ---
@@ -524,7 +648,12 @@ agent_main :-
524
648
 
525
649
  ## Full Prolog Support
526
650
 
527
- DML is built on SWI-Prolog, so you have access to the full Prolog language:
651
+ DML is built on SWI-Prolog, so you have access to the full Prolog language — and
652
+ to the constraint libraries (`clpfd`, `clpq`, `clpr`). Many questions are best
653
+ answered by a plain Prolog or CLP goal run with `execute`, with no model call at
654
+ all: arithmetic, counting, ordering, membership, `findall/3`, `aggregate_all/3`,
655
+ list/set operations, and constraint or optimisation problems. Reach for `task/N`
656
+ only when the step genuinely needs language understanding.
528
657
 
529
658
  ### Lists
530
659
  ```prolog
@@ -568,6 +697,44 @@ agent_main :-
568
697
  answer(Msg).
569
698
  ```
570
699
 
700
+ ### Bounding a goal (inference limit)
701
+
702
+ The interpreter has **no wall-clock timeout for a single builtin call** — the
703
+ session `gas` budget counts meta-interpreter steps, and a runaway `findall/3`,
704
+ `aggregate_all/3`, or `label/1` runs inside one step. Wrap such a call in
705
+ `call_with_inference_limit/3` (core SWI-Prolog; available in this runtime, which
706
+ has no threads) to bound it by inference count:
707
+
708
+ ```prolog
709
+ bounded_findall(Goal, Xs) :-
710
+ call_with_inference_limit(findall(X, call(Goal, X), Xs), 1000000, Result),
711
+ ( Result == inference_limit_exceeded
712
+ -> throw(error(inference_limit_exceeded, context(bounded_findall/2, Goal)))
713
+ ; true
714
+ ).
715
+ ```
716
+
717
+ `Result` is `inference_limit_exceeded` when the limit is hit (otherwise the
718
+ normal call result). Use it for `findall/3`, `aggregate_all/3`, and CLP
719
+ `label/1` over a large or under-specified domain:
720
+
721
+ ```prolog
722
+ sudoku_solve(Puzzle, Solution) :-
723
+ ...
724
+ call_with_inference_limit(label(Solution), 500000, Result),
725
+ ( Result == inference_limit_exceeded
726
+ -> throw(error(inference_limit_exceeded, context(sudoku_solve/2, label)))
727
+ ; true
728
+ ).
729
+ ```
730
+
731
+ System libraries imported with `:- use_module(library(...)).` (e.g. `clpfd`) are
732
+ also visible inside meta-calls, so `label/1`, `all_distinct/1`, and `ins/2` work
733
+ unqualified through the wrapper. If a library predicate is somehow not found
734
+ inside a wrapper (`existence_error`), qualify it: `clpfd:label(Xs)`.
735
+
736
+ For shell commands, pass `exec(bash(command: Cmd, timeoutMs: N), R)` instead.
737
+
571
738
  ### Assert/Retract (within session)
572
739
  ```prolog
573
740
  agent_main :-
@@ -577,24 +744,97 @@ agent_main :-
577
744
  answer(Msg).
578
745
  ```
579
746
 
580
- ### Constraint Logic Programming (CLP)
747
+ ### Constraint Logic Programming (CLP) — advanced, use sparingly
748
+
749
+ Use CLP only for a **genuine constraint problem** (scheduling, assignment,
750
+ puzzles, exact search). It is the wrong tool for ordinary arithmetic and
751
+ transformations — prefer a `task/N`/`prompt/N` step when the numbers or the
752
+ operation are open-ended (`DML_AUTHORING.md` §0). CLP also regresses easily: an
753
+ under-specified model, or one that is simply **unsatisfiable**, can search
754
+ essentially forever, so a buggy skill hangs the turn instead of failing fast.
755
+ If you use it:
581
756
 
582
- DML supports Prolog's CLP libraries for solving optimization and logic problems without needing Python:
757
+ - **Bound every domain first.** For one variable use `X in 0..100`; for a list use
758
+ `[X,Y,Z] ins 0..100`. (`X ins 0..100` on a bare variable is an
759
+ `instantiation_error` — use `in` for a single variable.)
760
+ - `all_distinct/1` / `all_different/1` over the list constrains it pairwise.
761
+ - Call `label/1` (or `labeling/2` with options such as `ff`) only when you need
762
+ concrete values; wrap it in `once/1` when a single witness is enough.
763
+ - To bound a search that can run away, wrap it in `call_with_inference_limit/3`
764
+ (see *Bounding a goal* above):
765
+ `call_with_inference_limit(label(Xs), 500000, R)` — `R == inference_limit_exceeded`
766
+ when it gave up. This works for CLP(FD) predicates in this runtime.
767
+ - Keep the model small; a big model is a sign the step belongs in a `task/N`.
583
768
 
584
- - **CLP(FD)**: Finite domains (integers). Use `:- use_module(library(clpfd)).`
585
- - **CLP(Q)**: Rational numbers. Use `:- use_module(library(clpq)).`
586
- - **CLP(R)**: Real numbers. Use `:- use_module(library(clpr)).`
769
+ - **CLP(FD)**: finite domains (integers). `:- use_module(library(clpfd)).`
770
+ - **CLP(Q)**: rationals. `:- use_module(library(clpq)).`
771
+ - **CLP(R)**: reals. `:- use_module(library(clpr)).`
587
772
 
588
773
  ```prolog
589
774
  :- use_module(library(clpfd)).
590
775
 
591
- agent_main(Total) :-
592
- [X,Y] ins 0..100,
776
+ % Small, fully bounded search; one witness.
777
+ solve_sum_product(Total, X, Y) :-
778
+ [X, Y] ins 0..100, % bound the domains; never leave them open
593
779
  X + Y #= Total,
594
780
  X * Y #= 2400,
595
- label([X,Y]),
596
- format(string(Msg), "X=~w, Y=~w", [X, Y]),
597
- answer(Msg).
781
+ once(label([X, Y])).
782
+
783
+ % A search bounded by inference count instead of by the domain.
784
+ bounded_label(Xs, Result) :-
785
+ call_with_inference_limit(label(Xs), 500000, Result).
786
+ ```
787
+
788
+ #### Optimisation (LP / MIP)
789
+
790
+ The CLP family here is **CLP(FD)** (integers), **CLP(Q)** (exact rationals) and
791
+ **CLP(R)** (reals) — there is no `clpfq`. `library(simplex)` loads but returns
792
+ unreliable answers in this runtime (its minimum/maximum come back wrong); do not
793
+ build on it.
794
+
795
+ **Continuous LP** — `clpr` (reals) / `clpq` (rationals), same interface. `{...}`
796
+ posts the constraints; `maximize/1` / `minimize/1` find the optimum:
797
+
798
+ ```prolog
799
+ :- use_module(library(clpr)).
800
+
801
+ lp(X, Y) :-
802
+ {X >= 0, Y >= 0, X =< 10, Y =< 10, X + 2*Y =< 14},
803
+ maximize(X + Y). % X = 10.0, Y = 2.0
804
+ ```
805
+
806
+ > **Caveat:** `maximize/1` / `minimize/1` bind the variables only when the optimum
807
+ > is a *unique vertex*. If the optimum is a face (a family of optima), they succeed
808
+ > and bind nothing. Use `sup/2` / `inf/2` to get the optimum **value** reliably —
809
+ > `{X >= 0, Y >= 0, X + Y =< 10, 2*X + Y =< 15}, sup(X + Y, S)` → `S = 10.0`.
810
+ > (`inf/3` / `sup/3` do not exist in this build.)
811
+
812
+ **Integer optimum** — negate the objective and use `bb_inf/5`; the 4th argument
813
+ comes back as the integer vertex:
814
+
815
+ ```prolog
816
+ :- use_module(library(clpr)).
817
+
818
+ mip(Inf, Vertex) :-
819
+ {X >= 0, Y >= 0, X + Y =< 4, X + 3*Y =< 6},
820
+ bb_inf([X, Y], -(3*X + 2*Y), Inf, Vertex, 0.001).
821
+ % Inf = -12.0, Vertex = [4,0] (negate the objective to maximise)
822
+ ```
823
+
824
+ **Exact integer optimum** — CLP(FD) with a `max(Expr)` label option. Prefer this
825
+ when the problem is genuinely integer: it is exact, bounded, and well-tested.
826
+ Bound every domain first and keep `label`/`labeling` inside
827
+ `call_with_inference_limit/3`:
828
+
829
+ ```prolog
830
+ :- use_module(library(clpfd)).
831
+
832
+ exact_max(X, Y) :-
833
+ [X, Y] ins 0..10,
834
+ X + Y #=< 4,
835
+ X + 3*Y #=< 6,
836
+ call_with_inference_limit(labeling([max(3*X + 2*Y), down], [X, Y]), 500000, _).
837
+ % X = 4, Y = 0
598
838
  ```
599
839
 
600
840
  ### Dictionaries (SWI-Prolog)
@@ -619,10 +859,8 @@ step(N, Desc) :-
619
859
  format(string(Msg), "Step ~w: ~w", [N, Desc]),
620
860
  output(Msg).
621
861
 
622
- % Main entry point
623
- agent_main :-
624
- param(topic, "Research topic", Topic),
625
-
862
+ % Main entry point; the topic is an argument.
863
+ agent_main(Topic) :-
626
864
  % Set up the assistant
627
865
  system("You are a thorough research assistant."),
628
866
  system("Provide detailed, accurate information."),
@@ -649,7 +887,7 @@ agent_main :-
649
887
  Run with:
650
888
  ```typescript
651
889
  for await (const event of dc.runDML(code, {
652
- params: { topic: 'quantum computing' }
890
+ args: ['quantum computing']
653
891
  })) {
654
892
  console.log(event.type, event.content);
655
893
  }
@@ -718,6 +956,11 @@ with_judgment(jev, choose("state", "Which team?", [billing, orders], Team)).
718
956
  require_judgment(calibrated, verify("state", "Is this urgent?", Truth)).
719
957
  ```
720
958
 
959
+ > **In the DML REPL**, an `llm` backend is always registered (it reuses the
960
+ > active model), and `jev` is registered when `judgment.jev.enabled` is set in
961
+ > `.deepclause/config.json` and its API key is available. `with_judgment(jev,
962
+ > ...)` fails if `jev` is not registered.
963
+
721
964
  `require_judgment/2` fails the wrapped goal before it runs when the active
722
965
  backend does not provide the capability, so a skill that depends on calibrated
723
966
  probabilities cannot silently run on an uncalibrated backend. Available
@@ -734,4 +977,33 @@ backtracking reuses an answer instead of re-querying the model.
734
977
  - Values are constrained to the options/levels you supply. A `choose` answer is
735
978
  always one of your option atoms.
736
979
  - Prefer one `judge/2` batch over several one-off calls when you need more than
737
- one or two judgments.
980
+ one or two judgments.
981
+ ## The DML REPL (`deepclause repl`)
982
+
983
+ DML skills can also be grown interactively in a persistent **living module**.
984
+
985
+ - `/goal <dml>` runs a goal and enumerates its solutions (the legacy dotted
986
+ `goal: <dml>.` form still works).
987
+ - Plain English builds the module: the **authoring agent** inspects and edits it
988
+ through tools (`listing`, `begin_turn`, `define`/`assert`/`assert_many`,
989
+ `retract`/`delete`, `execute`, `end_turn`/`rollback`). Edits are transactions:
990
+ `begin_turn` is required before any edit, `end_turn` commits a version.
991
+ Nothing is auto-run; the agent uses `execute` to test during a turn.
992
+ - There is **no implicit `agent_main` requirement** in the REPL. Run any
993
+ predicate with `/goal <name>(…)`. Define `agent_main` in the module when it
994
+ should also run with `deepclause run` / `/dc-run`.
995
+ - `freeze.` makes the module read-only; `export <file>.` serializes it.
996
+ `export harness.zip` bundles the module with its linked script files;
997
+ `export harness.dml` inlines them into one portable file.
998
+ - `input/2` / `exec(ask_user(...))` (module) ask the human. They never block in
999
+ non-interactive runs (`-g`, piped stdin, CI).
1000
+
1001
+ **Self-containment.** The harness is the `.dml` **plus the files it links**.
1002
+ Materialize each program with a DML goal (`make_directory_path(...)`,
1003
+ `write_file(...)`), link it with `script_file(Name, Path)`, and run it with
1004
+ `exec(bash(...))`. The
1005
+ exporter bundles the linked files, so they travel with the harness. Pass
1006
+ untrusted data through files or stdin, never interpolated into the shell
1007
+ command.
1008
+
1009
+ See [`docs/REPL.md`](../../../../docs/REPL.md) for the full guide.