deepclause-sdk 0.0.68 → 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/README.md +10 -2
- package/dist/agent.d.ts +1 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +252 -67
- 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 +38 -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 +16 -1
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +293 -21
- 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 +79 -0
- package/dist/runner.js.map +1 -1
- package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +7 -3
- package/dist/system/assets/docs/DML_REFERENCE.md +656 -0
- package/dist/system/assets/docs/TASK_PROMPT.md +33 -0
- package/dist/system/assets/docs/TUI.md +11 -0
- package/dist/system/assets/index.d.ts +12 -9
- package/dist/system/assets/index.d.ts.map +1 -1
- package/dist/system/assets/index.js +38 -9
- 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/catalog-skills.d.ts +1 -1
- package/dist/system/runtime/catalog-skills.d.ts.map +1 -1
- package/dist/system/runtime/catalog-skills.js +19 -5
- package/dist/system/runtime/catalog-skills.js.map +1 -1
- package/dist/system/runtime/conductor.d.ts +5 -1
- package/dist/system/runtime/conductor.d.ts.map +1 -1
- package/dist/system/runtime/conductor.js +22 -0
- package/dist/system/runtime/conductor.js.map +1 -1
- package/dist/system/runtime/dml-executor.d.ts +1 -1
- 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/dml-params.d.ts +2 -2
- package/dist/system/runtime/dml-params.d.ts.map +1 -1
- package/dist/system/runtime/dml-params.js +3 -0
- package/dist/system/runtime/dml-params.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/dist/system/runtime/skill-creator.d.ts.map +1 -1
- package/dist/system/runtime/skill-creator.js +52 -21
- package/dist/system/runtime/skill-creator.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
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# DeepClause Task Harness
|
|
2
|
+
|
|
3
|
+
You are an AI agent executing a subtask inside a larger DeepClause workflow.
|
|
4
|
+
|
|
5
|
+
## Subtask
|
|
6
|
+
|
|
7
|
+
{TASK_DESCRIPTION}
|
|
8
|
+
|
|
9
|
+
## Available Tools
|
|
10
|
+
|
|
11
|
+
{TOOL_DESCRIPTIONS}
|
|
12
|
+
|
|
13
|
+
## Required Results
|
|
14
|
+
|
|
15
|
+
{RESULT_SECTION}
|
|
16
|
+
|
|
17
|
+
## Decision Policy
|
|
18
|
+
|
|
19
|
+
1. If the subtask can already be completed from the current context, set the required results and call `finish(true)` immediately.
|
|
20
|
+
2. If you are missing information, call exactly one relevant tool.
|
|
21
|
+
3. If the subtask cannot be completed with the available context and tools, call `finish(false)`.
|
|
22
|
+
|
|
23
|
+
## Anti-Loop Rules
|
|
24
|
+
|
|
25
|
+
{STALL_GUIDANCE}
|
|
26
|
+
|
|
27
|
+
## Tool Rules
|
|
28
|
+
|
|
29
|
+
- Use the structured tool-calling interface for every tool call.
|
|
30
|
+
- Never describe a tool call in prose when you can invoke it directly.
|
|
31
|
+
- Never write fake code syntax such as `print(...)`, `tool_name(...)`, or `default_api.tool(...)` in your answer.
|
|
32
|
+
- Prefer one concrete action per turn: either call a tool, set results, or finish.
|
|
33
|
+
- If you already have enough information, do not keep planning. Set results and finish.
|