deepclause-sdk 0.0.69 → 0.0.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +125 -10
- package/dist/agent.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +64 -7
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/config.d.ts +15 -12
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +34 -5
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/default-skills.d.ts +1 -0
- package/dist/cli/default-skills.d.ts.map +1 -1
- package/dist/cli/default-skills.js +31 -0
- package/dist/cli/default-skills.js.map +1 -1
- package/dist/cli/tui.d.ts +15 -1
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +209 -7
- package/dist/cli/tui.js.map +1 -1
- package/dist/prolog/bridge.d.ts +15 -0
- package/dist/prolog/bridge.d.ts.map +1 -1
- package/dist/prolog/bridge.js +68 -0
- package/dist/prolog/bridge.js.map +1 -1
- package/dist/prolog-src/deepclause_mi.pl +135 -7
- package/dist/runner.d.ts +8 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +78 -0
- package/dist/runner.js.map +1 -1
- package/dist/system/assets/docs/DML_REFERENCE.md +656 -0
- package/dist/system/assets/docs/TUI.md +11 -0
- package/dist/system/assets/index.d.ts +3 -2
- package/dist/system/assets/index.d.ts.map +1 -1
- package/dist/system/assets/index.js +5 -0
- package/dist/system/assets/index.js.map +1 -1
- package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +56 -1
- package/dist/system/assets/skills/plan.dml +259 -0
- package/dist/system/runtime/dml-executor.d.ts.map +1 -1
- package/dist/system/runtime/dml-executor.js +2 -14
- package/dist/system/runtime/dml-executor.js.map +1 -1
- package/dist/system/runtime/runtime-tools.d.ts +1 -0
- package/dist/system/runtime/runtime-tools.d.ts.map +1 -1
- package/dist/system/runtime/runtime-tools.js +95 -0
- package/dist/system/runtime/runtime-tools.js.map +1 -1
- package/dist/system/runtime/shell-manager.js +1 -1
- package/dist/system/runtime/shell-manager.js.map +1 -1
- package/package.json +4 -3
- package/src/prolog-src/deepclause_mi.pl +135 -7
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
# DML Language Reference
|
|
2
|
+
|
|
3
|
+
**DML** (DeepClause Meta Language) is a simplified Prolog dialect for programming AI agents. It combines declarative logic programming with LLM-powered task execution.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Program Structure](#program-structure)
|
|
8
|
+
- [Entry Point](#entry-point)
|
|
9
|
+
- [Core Predicates](#core-predicates)
|
|
10
|
+
- [task/1, task/2, task/3, task/4](#task-predicates)
|
|
11
|
+
- [exec/2](#exec2)
|
|
12
|
+
- [Tool Definitions](#tool-definitions)
|
|
13
|
+
- [Tool Scoping](#tool-scoping)
|
|
14
|
+
- [system/1, user/1](#memory-predicates)
|
|
15
|
+
- [output/1, yield/1, log/1](#output-predicates)
|
|
16
|
+
- [answer/1](#answer1)
|
|
17
|
+
- [param/3](#param3)
|
|
18
|
+
- [Control Flow](#control-flow)
|
|
19
|
+
- [String Interpolation](#string-interpolation)
|
|
20
|
+
- [Backtracking](#backtracking)
|
|
21
|
+
- [Full Prolog Support](#full-prolog-support)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Program Structure
|
|
26
|
+
|
|
27
|
+
A DML program is a collection of Prolog clauses. Comments use `%` for single lines or `/* */` for blocks:
|
|
28
|
+
|
|
29
|
+
```prolog
|
|
30
|
+
% This is a single line comment
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
This is a
|
|
34
|
+
multi-line comment
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
% Define helper predicates
|
|
38
|
+
greet(Name, Greeting) :-
|
|
39
|
+
format(string(Greeting), "Hello, ~w!", [Name]).
|
|
40
|
+
|
|
41
|
+
% Main entry point
|
|
42
|
+
agent_main :-
|
|
43
|
+
greet("World", Msg),
|
|
44
|
+
answer(Msg).
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Entry Point
|
|
50
|
+
|
|
51
|
+
Every DML program must define `agent_main` as the entry point. It can have 0, 1, or 2 arguments:
|
|
52
|
+
|
|
53
|
+
### agent_main/0
|
|
54
|
+
```prolog
|
|
55
|
+
agent_main :-
|
|
56
|
+
task("Do something"),
|
|
57
|
+
answer("Done").
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### agent_main/1
|
|
61
|
+
Receives the first parameter:
|
|
62
|
+
```prolog
|
|
63
|
+
agent_main(Name) :-
|
|
64
|
+
format(string(Msg), "Hello, ~w!", [Name]),
|
|
65
|
+
answer(Msg).
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### agent_main/2
|
|
69
|
+
Receives first two parameters:
|
|
70
|
+
```prolog
|
|
71
|
+
agent_main(Name, Task) :-
|
|
72
|
+
system("You are a helpful assistant."),
|
|
73
|
+
task(Task),
|
|
74
|
+
answer("Complete").
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Core Predicates
|
|
80
|
+
|
|
81
|
+
### `sample_token(+Prompt, -Token)`
|
|
82
|
+
|
|
83
|
+
Run a fresh prompt and normalize the result down to a single raw token string.
|
|
84
|
+
This is useful when the model should emit one grammar symbol, label, or keyword
|
|
85
|
+
instead of a full sentence.
|
|
86
|
+
|
|
87
|
+
```prolog
|
|
88
|
+
agent_main :-
|
|
89
|
+
sample_token("Pick a SQL keyword for starting a query.", Token),
|
|
90
|
+
answer(Token).
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `sample_token(+Prompt, +Allowed, -Token)`
|
|
94
|
+
|
|
95
|
+
Same as `sample_token/2`, but constrains the result to an allowed token list.
|
|
96
|
+
If the model returns something outside that list, DML falls back deterministically
|
|
97
|
+
to the first allowed token. The runtime still samples just one model token, so
|
|
98
|
+
the prompt can stay terse and the grammar frontier can live in `Allowed`.
|
|
99
|
+
|
|
100
|
+
```prolog
|
|
101
|
+
agent_main :-
|
|
102
|
+
sample_token("Pick the next token for a query.", ["select", "update"], Token),
|
|
103
|
+
answer(Token).
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Task Predicates
|
|
107
|
+
|
|
108
|
+
#### `task(+Description)`
|
|
109
|
+
|
|
110
|
+
Invoke an LLM to perform a task. The description is sent to the model.
|
|
111
|
+
|
|
112
|
+
```prolog
|
|
113
|
+
agent_main :-
|
|
114
|
+
system("You are a coding assistant."),
|
|
115
|
+
task("Write a function to calculate factorial in Python."),
|
|
116
|
+
answer("Code generated!").
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### `task(+Description, -Var1)`
|
|
120
|
+
|
|
121
|
+
Invoke LLM and bind output to a variable. Mention the variable name in the description:
|
|
122
|
+
|
|
123
|
+
```prolog
|
|
124
|
+
agent_main :-
|
|
125
|
+
task("Calculate 2 + 2 and store the result in Answer.", Answer),
|
|
126
|
+
format(string(Msg), "The answer is: ~w", [Answer]),
|
|
127
|
+
answer(Msg).
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### `task(+Description, -Var1, -Var2)`
|
|
131
|
+
|
|
132
|
+
Bind multiple variables:
|
|
133
|
+
|
|
134
|
+
```prolog
|
|
135
|
+
agent_main :-
|
|
136
|
+
task("Generate a name and age for a character. Store name in Name and age in Age.", Name, Age),
|
|
137
|
+
format(string(Msg), "Character: ~w, Age: ~w", [Name, Age]),
|
|
138
|
+
answer(Msg).
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `task(+Description, -Var1, -Var2, -Var3)`
|
|
142
|
+
|
|
143
|
+
Bind up to three variables.
|
|
144
|
+
|
|
145
|
+
### Type-Safe Output Variables
|
|
146
|
+
|
|
147
|
+
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.
|
|
148
|
+
|
|
149
|
+
| Wrapper | Description | Zod Equivalent |
|
|
150
|
+
|---------|-------------|----------------|
|
|
151
|
+
| `string(Var)` | Default string type | `z.string()` |
|
|
152
|
+
| `integer(Var)` | Integer number | `z.number().int()` |
|
|
153
|
+
| `number(Var)` | Any number (float or int) | `z.number()` |
|
|
154
|
+
| `float(Var)` | Alias for number | `z.number()` |
|
|
155
|
+
| `boolean(Var)` | Boolean value | `z.boolean()` |
|
|
156
|
+
| `list(Type(Var))` | Array of specified type | `z.array(Type)` |
|
|
157
|
+
| `object(Var)` | Dictionary/Object | `z.record(z.unknown())` |
|
|
158
|
+
|
|
159
|
+
**Examples:**
|
|
160
|
+
|
|
161
|
+
```prolog
|
|
162
|
+
% Enforce integer result
|
|
163
|
+
task("Calculate 10 + 5", integer(Result)).
|
|
164
|
+
|
|
165
|
+
% Enforce boolean result
|
|
166
|
+
task("Is this true?", boolean(IsTrue)).
|
|
167
|
+
|
|
168
|
+
% Enforce list of strings
|
|
169
|
+
task("List 3 colors", list(string(Colors))).
|
|
170
|
+
|
|
171
|
+
% Enforce object result
|
|
172
|
+
task("Extract user details", object(User)).
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Note:** The LLM during `task()` can only call tools defined in DML (see [Tool Definitions](#tool-definitions)). Registered TypeScript tools are not automatically available - this gives you control over what the LLM can do.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### `exec(+ToolCall, -Output)`
|
|
180
|
+
|
|
181
|
+
Execute a registered TypeScript tool directly and capture its output.
|
|
182
|
+
|
|
183
|
+
```prolog
|
|
184
|
+
% Assuming 'calculator' tool is registered in TypeScript
|
|
185
|
+
agent_main :-
|
|
186
|
+
exec(calculator(expression: "15 * 23"), Result),
|
|
187
|
+
format(string(Msg), "Calculation result: ~w", [Result]),
|
|
188
|
+
answer(Msg).
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Tool arguments use `key: value` syntax:
|
|
192
|
+
|
|
193
|
+
```prolog
|
|
194
|
+
exec(fetch_url(url: "https://example.com"), Response)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Or positional if the tool supports it:
|
|
198
|
+
|
|
199
|
+
```prolog
|
|
200
|
+
exec(get_time, CurrentTime)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### Tool Definitions
|
|
206
|
+
|
|
207
|
+
Define tools in DML that the LLM can call during `task()`. Tools use the `tool/2` predicate with a description:
|
|
208
|
+
|
|
209
|
+
```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).
|
|
213
|
+
|
|
214
|
+
agent_main :-
|
|
215
|
+
system("You have a calculate tool."),
|
|
216
|
+
task("What is the square root of 144?"),
|
|
217
|
+
answer("Done").
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Tool definitions have the form:
|
|
221
|
+
```prolog
|
|
222
|
+
tool(name(Arg1, Arg2, ..., Result), "Description") :- Body.
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The last argument is typically the output. The description is shown to the LLM.
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
You can add Prolog logic in tool implementations:
|
|
229
|
+
```prolog
|
|
230
|
+
tool(safe_divide(A, B, Result), "Safely divide two numbers") :-
|
|
231
|
+
( B =:= 0
|
|
232
|
+
-> Result = error("Division by zero")
|
|
233
|
+
; exec(calculator(expression: A/B), Result)
|
|
234
|
+
).
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### Using `task()` Inside Tools
|
|
238
|
+
|
|
239
|
+
Tools can use `task()` and `prompt()` internally to combine Prolog logic with LLM reasoning:
|
|
240
|
+
|
|
241
|
+
```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)) :-
|
|
246
|
+
Sum is A + B, % Prolog computation
|
|
247
|
+
format(string(Desc), "Explain ~w + ~w = ~w to a child", [A, B, Sum]),
|
|
248
|
+
task(Desc, Explanation). % LLM explanation
|
|
249
|
+
|
|
250
|
+
% A tool that uses LLM for formatting
|
|
251
|
+
:- tool(format_data(Data), "Format data nicely using LLM").
|
|
252
|
+
|
|
253
|
+
tool(format_data(Data, FormattedOutput)) :-
|
|
254
|
+
format(string(Desc), "Format this data nicely: ~w", [Data]),
|
|
255
|
+
task(Desc, FormattedOutput).
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**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.
|
|
259
|
+
|
|
260
|
+
**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
|
+
|
|
262
|
+
```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]),
|
|
268
|
+
task(Desc, Summary).
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### Tool Scoping
|
|
274
|
+
|
|
275
|
+
You can control which tools are available to nested `task()` calls using `with_tools/2` and `without_tools/2`.
|
|
276
|
+
|
|
277
|
+
#### `with_tools(+ToolList, +Goal)`
|
|
278
|
+
|
|
279
|
+
Run Goal with only the specified tools available to nested tasks:
|
|
280
|
+
|
|
281
|
+
```prolog
|
|
282
|
+
% Only allow tool_a and tool_b in the nested task
|
|
283
|
+
tool(restricted_task(Input, Output), "Runs with limited tools") :-
|
|
284
|
+
with_tools([tool_a, tool_b], (
|
|
285
|
+
format(string(Desc), "Process '~w' using available tools", [Input]),
|
|
286
|
+
task(Desc, Output)
|
|
287
|
+
)).
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### `without_tools(+ToolList, +Goal)`
|
|
291
|
+
|
|
292
|
+
Run Goal with the specified tools excluded from nested tasks:
|
|
293
|
+
|
|
294
|
+
```prolog
|
|
295
|
+
% Exclude expensive_tool from the nested task
|
|
296
|
+
tool(cheap_task(Input, Output), "Runs without expensive tools") :-
|
|
297
|
+
without_tools([expensive_tool], (
|
|
298
|
+
format(string(Desc), "Process '~w' cheaply", [Input]),
|
|
299
|
+
task(Desc, Output)
|
|
300
|
+
)).
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### Using Tool Scoping in `agent_main`
|
|
304
|
+
|
|
305
|
+
You can also use `with_tools/2` and `without_tools/2` directly in `agent_main`:
|
|
306
|
+
|
|
307
|
+
```prolog
|
|
308
|
+
agent_main :-
|
|
309
|
+
system("You are a safe assistant."),
|
|
310
|
+
|
|
311
|
+
% Run task with only safe tools
|
|
312
|
+
with_tools([read_file, list_files], (
|
|
313
|
+
task("Analyze the files in the workspace.", Analysis)
|
|
314
|
+
)),
|
|
315
|
+
|
|
316
|
+
output(Analysis),
|
|
317
|
+
answer("Done").
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Automatic call stack exclusion:** When a tool calls `task()`, the calling tool is automatically excluded from the nested agent's available tools to prevent infinite recursion. This happens in addition to any manual scoping via `with_tools/2` or `without_tools/2`.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
### Memory Predicates
|
|
325
|
+
|
|
326
|
+
Memory predicates build the conversation context sent to the LLM.
|
|
327
|
+
|
|
328
|
+
#### `system(+Text)`
|
|
329
|
+
|
|
330
|
+
Add a system message (instructions for the LLM):
|
|
331
|
+
|
|
332
|
+
```prolog
|
|
333
|
+
agent_main :-
|
|
334
|
+
system("You are a helpful cooking assistant."),
|
|
335
|
+
system("Always provide measurements in metric units."),
|
|
336
|
+
task("Suggest a recipe for pasta."),
|
|
337
|
+
answer("Done").
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### `user(+Text)`
|
|
341
|
+
|
|
342
|
+
Add a user message to the context:
|
|
343
|
+
|
|
344
|
+
```prolog
|
|
345
|
+
agent_main :-
|
|
346
|
+
system("You are a helpful assistant."),
|
|
347
|
+
user("I want to learn about machine learning."),
|
|
348
|
+
task("Explain the basics of machine learning."),
|
|
349
|
+
answer("Explained!").
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### Output Predicates
|
|
355
|
+
|
|
356
|
+
#### `output(+Text)`
|
|
357
|
+
|
|
358
|
+
Emit an output event to the caller. Does NOT affect the LLM conversation. Useful for progress updates:
|
|
359
|
+
|
|
360
|
+
```prolog
|
|
361
|
+
agent_main :-
|
|
362
|
+
output("Starting analysis..."),
|
|
363
|
+
task("Analyze the data"),
|
|
364
|
+
output("Analysis complete!"),
|
|
365
|
+
answer("Done").
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
#### `yield(+Text)`
|
|
369
|
+
|
|
370
|
+
Alias for `output/1`.
|
|
371
|
+
|
|
372
|
+
#### `log(+Text)`
|
|
373
|
+
|
|
374
|
+
Emit a log event. Similar to output but typed as 'log' for filtering:
|
|
375
|
+
|
|
376
|
+
```prolog
|
|
377
|
+
agent_main :-
|
|
378
|
+
log("Debug: entering main"),
|
|
379
|
+
task("Process request"),
|
|
380
|
+
log("Debug: task completed"),
|
|
381
|
+
answer("Done").
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### `answer(+Text)`
|
|
387
|
+
|
|
388
|
+
Emit the final answer and **commit** - no backtracking occurs after `answer/1`:
|
|
389
|
+
|
|
390
|
+
```prolog
|
|
391
|
+
agent_main :-
|
|
392
|
+
task("Generate a poem"),
|
|
393
|
+
answer("Poem complete!"). % Execution stops here
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Important:** `answer/1` commits the execution. After answering, the program completes and does not try alternative clauses.
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
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
|
+
## Control Flow
|
|
420
|
+
|
|
421
|
+
DML supports standard Prolog control flow:
|
|
422
|
+
|
|
423
|
+
### Conjunction (and)
|
|
424
|
+
```prolog
|
|
425
|
+
goal1, goal2, goal3
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Disjunction (or)
|
|
429
|
+
```prolog
|
|
430
|
+
(goal1 ; goal2)
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### If-Then-Else
|
|
434
|
+
```prolog
|
|
435
|
+
(Condition -> Then ; Else)
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### If-Then (soft cut)
|
|
439
|
+
```prolog
|
|
440
|
+
(Condition -> Then)
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Negation as Failure
|
|
444
|
+
```prolog
|
|
445
|
+
\+ goal
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Cut
|
|
449
|
+
```prolog
|
|
450
|
+
!
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Catch/Throw
|
|
454
|
+
```prolog
|
|
455
|
+
catch(Goal, Error, Recovery)
|
|
456
|
+
throw(Error)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## String Interpolation
|
|
462
|
+
|
|
463
|
+
Text arguments support `{variable}` interpolation with parameters:
|
|
464
|
+
|
|
465
|
+
```prolog
|
|
466
|
+
agent_main :-
|
|
467
|
+
param(topic, "Research topic", Topic),
|
|
468
|
+
system("You are a research assistant."),
|
|
469
|
+
task("Research the topic: {topic}"), % Topic is interpolated
|
|
470
|
+
answer("Research on {topic} complete!").
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Backtracking
|
|
476
|
+
|
|
477
|
+
DML supports full Prolog backtracking, **including across LLM calls**. This enables powerful retry logic:
|
|
478
|
+
|
|
479
|
+
### Multiple Clauses
|
|
480
|
+
```prolog
|
|
481
|
+
% Try first approach
|
|
482
|
+
agent_main :-
|
|
483
|
+
output("Trying approach 1..."),
|
|
484
|
+
task("Solve using method A"),
|
|
485
|
+
fail. % Force failure to try next clause
|
|
486
|
+
|
|
487
|
+
% Fallback approach
|
|
488
|
+
agent_main :-
|
|
489
|
+
output("Trying approach 2..."),
|
|
490
|
+
task("Solve using method B"),
|
|
491
|
+
answer("Solved!").
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### State Restoration
|
|
495
|
+
|
|
496
|
+
When backtracking occurs, the memory state is automatically restored:
|
|
497
|
+
|
|
498
|
+
```prolog
|
|
499
|
+
agent_main :-
|
|
500
|
+
system("Context A"), % This is in memory
|
|
501
|
+
output("Trying path A"),
|
|
502
|
+
fail. % Memory is rolled back!
|
|
503
|
+
|
|
504
|
+
agent_main :-
|
|
505
|
+
system("Context B"), % Fresh memory
|
|
506
|
+
output("Trying path B"),
|
|
507
|
+
answer("Done").
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Disjunction Backtracking
|
|
511
|
+
|
|
512
|
+
```prolog
|
|
513
|
+
agent_main :-
|
|
514
|
+
(
|
|
515
|
+
task("Try difficult approach"),
|
|
516
|
+
fail % Backtrack
|
|
517
|
+
;
|
|
518
|
+
task("Try easier approach")
|
|
519
|
+
),
|
|
520
|
+
answer("Completed").
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## Full Prolog Support
|
|
526
|
+
|
|
527
|
+
DML is built on SWI-Prolog, so you have access to the full Prolog language:
|
|
528
|
+
|
|
529
|
+
### Lists
|
|
530
|
+
```prolog
|
|
531
|
+
process_items([]).
|
|
532
|
+
process_items([H|T]) :-
|
|
533
|
+
format(string(Msg), "Processing: ~w", [H]),
|
|
534
|
+
output(Msg),
|
|
535
|
+
process_items(T).
|
|
536
|
+
|
|
537
|
+
agent_main :-
|
|
538
|
+
process_items([apple, banana, cherry]),
|
|
539
|
+
answer("All items processed").
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Not all builtin SWI Prolog predicates are guaranteed to work at this stage!
|
|
543
|
+
|
|
544
|
+
### Arithmetic
|
|
545
|
+
```prolog
|
|
546
|
+
agent_main :-
|
|
547
|
+
X is 10 + 5 * 2,
|
|
548
|
+
format(string(Msg), "Result: ~w", [X]),
|
|
549
|
+
answer(Msg).
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### String Formatting
|
|
553
|
+
```prolog
|
|
554
|
+
agent_main :-
|
|
555
|
+
format(string(S), "Hello ~w, you are ~d years old", [alice, 30]),
|
|
556
|
+
answer(S).
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Findall
|
|
560
|
+
```prolog
|
|
561
|
+
color(red).
|
|
562
|
+
color(green).
|
|
563
|
+
color(blue).
|
|
564
|
+
|
|
565
|
+
agent_main :-
|
|
566
|
+
findall(C, color(C), Colors),
|
|
567
|
+
format(string(Msg), "Colors: ~w", [Colors]),
|
|
568
|
+
answer(Msg).
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Assert/Retract (within session)
|
|
572
|
+
```prolog
|
|
573
|
+
agent_main :-
|
|
574
|
+
assertz(fact(42)),
|
|
575
|
+
fact(X),
|
|
576
|
+
format(string(Msg), "Stored fact: ~w", [X]),
|
|
577
|
+
answer(Msg).
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Constraint Logic Programming (CLP)
|
|
581
|
+
|
|
582
|
+
DML supports Prolog's CLP libraries for solving optimization and logic problems without needing Python:
|
|
583
|
+
|
|
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)).`
|
|
587
|
+
|
|
588
|
+
```prolog
|
|
589
|
+
:- use_module(library(clpfd)).
|
|
590
|
+
|
|
591
|
+
agent_main(Total) :-
|
|
592
|
+
[X,Y] ins 0..100,
|
|
593
|
+
X + Y #= Total,
|
|
594
|
+
X * Y #= 2400,
|
|
595
|
+
label([X,Y]),
|
|
596
|
+
format(string(Msg), "X=~w, Y=~w", [X, Y]),
|
|
597
|
+
answer(Msg).
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Dictionaries (SWI-Prolog)
|
|
601
|
+
```prolog
|
|
602
|
+
agent_main :-
|
|
603
|
+
D = point{x: 10, y: 20},
|
|
604
|
+
X = D.x,
|
|
605
|
+
format(string(Msg), "X coordinate: ~w", [X]),
|
|
606
|
+
answer(Msg).
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
## Complete Example
|
|
612
|
+
|
|
613
|
+
```prolog
|
|
614
|
+
% research_assistant.dml
|
|
615
|
+
% A multi-step research assistant
|
|
616
|
+
|
|
617
|
+
% Helper to log progress
|
|
618
|
+
step(N, Desc) :-
|
|
619
|
+
format(string(Msg), "Step ~w: ~w", [N, Desc]),
|
|
620
|
+
output(Msg).
|
|
621
|
+
|
|
622
|
+
% Main entry point
|
|
623
|
+
agent_main :-
|
|
624
|
+
param(topic, "Research topic", Topic),
|
|
625
|
+
|
|
626
|
+
% Set up the assistant
|
|
627
|
+
system("You are a thorough research assistant."),
|
|
628
|
+
system("Provide detailed, accurate information."),
|
|
629
|
+
|
|
630
|
+
% Step 1: Overview
|
|
631
|
+
step(1, "Getting overview"),
|
|
632
|
+
format(string(Task1), "Provide a brief overview of ~w", [Topic]),
|
|
633
|
+
task(Task1),
|
|
634
|
+
|
|
635
|
+
% Step 2: Key concepts
|
|
636
|
+
step(2, "Identifying key concepts"),
|
|
637
|
+
task("List the 3 most important concepts related to this topic. Store them in Concepts.", Concepts),
|
|
638
|
+
|
|
639
|
+
% Step 3: Deep dive
|
|
640
|
+
step(3, "Deep dive analysis"),
|
|
641
|
+
format(string(Task3), "Explain these concepts in detail: ~w", [Concepts]),
|
|
642
|
+
task(Task3),
|
|
643
|
+
|
|
644
|
+
% Complete
|
|
645
|
+
format(string(FinalMsg), "Research on '~w' complete!", [Topic]),
|
|
646
|
+
answer(FinalMsg).
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
Run with:
|
|
650
|
+
```typescript
|
|
651
|
+
for await (const event of dc.runDML(code, {
|
|
652
|
+
params: { topic: 'quantum computing' }
|
|
653
|
+
})) {
|
|
654
|
+
console.log(event.type, event.content);
|
|
655
|
+
}
|
|
656
|
+
```
|
|
@@ -11,6 +11,8 @@ The TUI is the operator interface around a single built-in agent: the conductor.
|
|
|
11
11
|
- The upper-right pane shows live execution activity.
|
|
12
12
|
- The lower-right pane shows context, token usage, system asset sources, and shell execution details.
|
|
13
13
|
|
|
14
|
+
The local `.deepclause/docs/` folder contains editable workspace docs such as `TUI.md` and `DML_REFERENCE.md`. The system `plan` skill reads `DML_REFERENCE.md` and `.deepclause/system/DML_COMPILER_PROMPT.md` before generating new plan files.
|
|
15
|
+
|
|
14
16
|
## Command Bar
|
|
15
17
|
|
|
16
18
|
The command bar accepts three main input styles plus direct skill execution:
|
|
@@ -18,6 +20,9 @@ The command bar accepts three main input styles plus direct skill execution:
|
|
|
18
20
|
- Plain text sends a normal request to the conductor.
|
|
19
21
|
- `/...` runs a built-in slash command.
|
|
20
22
|
- `/<skill> [args]` runs a compiled local skill directly.
|
|
23
|
+
- `/plan <request>` runs the system `plan` skill from `.deepclause/system/plan.dml`.
|
|
24
|
+
- `/<plan> [args]` runs `plans/<plan>.dml` when no compiled local skill matches that name.
|
|
25
|
+
- `/run <file> [args]` runs a workspace DML file directly.
|
|
21
26
|
- `!<command>` runs a shell command directly in the configured workspace shell.
|
|
22
27
|
|
|
23
28
|
Examples:
|
|
@@ -26,6 +31,8 @@ Examples:
|
|
|
26
31
|
summarize the latest test failures
|
|
27
32
|
/sessions
|
|
28
33
|
/set-model openai:gpt-4.1 --slot run
|
|
34
|
+
/plan create a simple repo cleanup workflow
|
|
35
|
+
/run plans/repo_cleanup.dml
|
|
29
36
|
/compile create a skill that reviews changelogs
|
|
30
37
|
/deep-research transformers scaling laws
|
|
31
38
|
!git status
|
|
@@ -41,6 +48,8 @@ Common built-in slash commands:
|
|
|
41
48
|
- `/new [title]` creates a new conductor session.
|
|
42
49
|
- `/sessions` refreshes or switches sessions.
|
|
43
50
|
- `/set-model <model> [--slot <slot>]` updates the configured model for all slots or one slot.
|
|
51
|
+
- `/plan <request>` runs the system plan skill and writes a simple standalone plan under `plans/`.
|
|
52
|
+
- `/run <file> [args]` runs a workspace DML file directly.
|
|
44
53
|
- `/compile <spec>` runs the skill creator.
|
|
45
54
|
- `/skill-creator <spec>` is an alias for `/compile`.
|
|
46
55
|
- `/cancel` aborts the current running task, skill, or shell command.
|
|
@@ -48,6 +57,7 @@ Common built-in slash commands:
|
|
|
48
57
|
- `/quit` or `/exit` closes the TUI.
|
|
49
58
|
|
|
50
59
|
Any other `/name` is treated as a compiled skill invocation if that skill exists in the local catalog.
|
|
60
|
+
If no compiled skill matches, the TUI looks for `plans/<name>.dml` and runs that file directly.
|
|
51
61
|
|
|
52
62
|
## Direct Shell Mode
|
|
53
63
|
|
|
@@ -126,6 +136,7 @@ The conductor is not the same thing as a compiled skill.
|
|
|
126
136
|
|
|
127
137
|
- The conductor handles freeform user requests and orchestration.
|
|
128
138
|
- Compiled skills are reusable DML workers in `.deepclause/tools/`.
|
|
139
|
+
- The `plan` system skill lives at `.deepclause/system/plan.dml` and follows the same override model as the other system DML assets.
|
|
129
140
|
- `/set-model` updates the configured gateway, run, and compile model selection for future turns, or only one slot when `--slot` is provided.
|
|
130
141
|
- `/compile` and `/skill-creator` use the skill creator to turn a spec into a validated local skill.
|
|
131
142
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export type SystemSkillAssetName = 'conductor' | 'skill-creator';
|
|
1
|
+
export type SystemSkillAssetName = 'conductor' | 'skill-creator' | 'plan';
|
|
2
2
|
export type SystemPromptAssetName = 'conductor' | 'skill-creator' | 'task';
|
|
3
3
|
export type SystemCompactorAssetName = 'default-session-compactor' | 'default-loop-compactor';
|
|
4
|
-
export type WorkspaceDocAssetName = 'tui';
|
|
4
|
+
export type WorkspaceDocAssetName = 'tui' | 'dml-reference';
|
|
5
5
|
interface SystemAssetLookupOptions {
|
|
6
6
|
workspaceRoot?: string;
|
|
7
7
|
workspacePath?: string;
|
|
@@ -15,6 +15,7 @@ export declare function getWorkspaceRecipeAssetsDir(workspaceRoot: string): stri
|
|
|
15
15
|
export declare function getSystemAssetSourcePaths(workspaceRoot?: string): {
|
|
16
16
|
conductorDml: string;
|
|
17
17
|
conductorPrompt: string;
|
|
18
|
+
planDml: string;
|
|
18
19
|
skillCreatorDml: string;
|
|
19
20
|
skillCreatorPrompt: string;
|
|
20
21
|
taskPrompt: string;
|