deepclause-sdk 0.0.4 → 0.0.6
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 +3 -0
- package/dist/cli/compile.d.ts +0 -38
- package/dist/cli/compile.d.ts.map +1 -1
- package/dist/cli/compile.js +88 -527
- package/dist/cli/compile.js.map +1 -1
- package/dist/cli/config.d.ts +6 -6
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/run.d.ts +1 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +11 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/compiler.d.ts +39 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +402 -0
- package/dist/compiler.js.map +1 -0
- package/dist/compiler_prompt.d.ts +20 -0
- package/dist/compiler_prompt.d.ts.map +1 -0
- package/dist/compiler_prompt.js +870 -0
- package/dist/compiler_prompt.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/prolog-src/deepclause_mi.pl +41 -10
- package/dist/runner.d.ts +1 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +10 -1
- package/dist/runner.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +31 -0
- package/dist/sdk.js.map +1 -1
- package/dist/tools.d.ts +9 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +51 -0
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/prolog-src/deepclause_mi.pl +41 -10
|
@@ -0,0 +1,870 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepClause SDK - MD to DML Conversion Prompt
|
|
3
|
+
*
|
|
4
|
+
* Contains the base prompt template for converting Markdown task descriptions to DML.
|
|
5
|
+
*/
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Prompt Template
|
|
8
|
+
// =============================================================================
|
|
9
|
+
export const DML_CONVERSION_PROMPT = `# Markdown to DML Conversion Prompt
|
|
10
|
+
|
|
11
|
+
You are an expert DML (DeepClause Meta Language) programmer. Your task is to convert
|
|
12
|
+
natural language task descriptions written in Markdown into executable DML programs.
|
|
13
|
+
|
|
14
|
+
## Tool Types in DML
|
|
15
|
+
|
|
16
|
+
There are two kinds of tools in DML:
|
|
17
|
+
|
|
18
|
+
### 1. DML Tool Wrappers (via \`tool/3\`)
|
|
19
|
+
These are predicates you define in DML using the \`tool/3\` syntax. They are pure DML logic
|
|
20
|
+
and typically wrap one or more external tools for convenience or composition. They are
|
|
21
|
+
**not** registered as external dependencies.
|
|
22
|
+
|
|
23
|
+
\`\`\`prolog
|
|
24
|
+
tool(search(Query, Results), "Search the web for information") :-
|
|
25
|
+
exec(web_search(query: Query), Results).
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
### 2. External Tools (MCP/AgentVM)
|
|
29
|
+
These are provided by the runtime (via MCP servers or built-in AgentVM) and are invoked
|
|
30
|
+
directly with \`exec/2\`. Only these are registered as dependencies in the meta file.
|
|
31
|
+
|
|
32
|
+
## Available External Tools
|
|
33
|
+
|
|
34
|
+
{TOOLS_TABLE}
|
|
35
|
+
|
|
36
|
+
**Note:** Only tools invoked via \`exec/2\` that correspond to external MCP or AgentVM
|
|
37
|
+
tools are registered as dependencies. DML tool wrappers are not registered unless they
|
|
38
|
+
call external tools.
|
|
39
|
+
|
|
40
|
+
## DML Language Overview
|
|
41
|
+
|
|
42
|
+
DML is a simplified Prolog dialect designed for AI agent programming. It combines
|
|
43
|
+
declarative logic programming with LLM-powered task execution.
|
|
44
|
+
|
|
45
|
+
### Program Structure
|
|
46
|
+
|
|
47
|
+
Every DML program must have an \`agent_main\` entry point that accepts 0+ arguments:
|
|
48
|
+
|
|
49
|
+
\`\`\`prolog
|
|
50
|
+
% No arguments
|
|
51
|
+
agent_main :- ...
|
|
52
|
+
|
|
53
|
+
% One argument
|
|
54
|
+
agent_main(Topic) :- ...
|
|
55
|
+
|
|
56
|
+
% Two arguments (alphabetical order for dict unpacking)
|
|
57
|
+
agent_main(MaxResults, Topic) :- ...
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
### Core Predicates
|
|
61
|
+
|
|
62
|
+
#### Task Execution
|
|
63
|
+
|
|
64
|
+
| Predicate | Description |
|
|
65
|
+
|-----------|-------------|
|
|
66
|
+
| \`task(Description)\` | Execute an LLM task with accumulated memory |
|
|
67
|
+
| \`task(Description, Var)\` | Execute task, bind result to Var |
|
|
68
|
+
| \`task(Description, Var1, Var2)\` | Execute task, bind two results |
|
|
69
|
+
| \`task(Description, Var1, Var2, Var3)\` | Execute task, bind three results |
|
|
70
|
+
|
|
71
|
+
**Type-Safe Output Variables:**
|
|
72
|
+
You can wrap output variables with type specifiers to enforce strict validation:
|
|
73
|
+
- \`string(Var)\` (Default)
|
|
74
|
+
- \`integer(Var)\` - Enforces integer type
|
|
75
|
+
- \`number(Var)\` or \`float(Var)\` - Enforces numeric type
|
|
76
|
+
- \`boolean(Var)\` - Enforces boolean type
|
|
77
|
+
- \`list(string(Var))\` - Enforces array of strings (or other types)
|
|
78
|
+
- \`object(Var)\` - Enforces object/dict type
|
|
79
|
+
|
|
80
|
+
\`\`\`prolog
|
|
81
|
+
task("Calculate result", integer(Result))
|
|
82
|
+
task("List items", list(string(Items)))
|
|
83
|
+
task("Check status", boolean(IsComplete))
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
**Important:** Variable names in the description must match the Prolog variables:
|
|
87
|
+
\`\`\`prolog
|
|
88
|
+
task("Analyze this and store the result in Summary.", Summary)
|
|
89
|
+
\`\`\`
|
|
90
|
+
|
|
91
|
+
#### Fresh LLM Calls (No Memory)
|
|
92
|
+
|
|
93
|
+
| Predicate | Description |
|
|
94
|
+
|-----------|-------------|
|
|
95
|
+
| \`prompt(Description)\` | Execute LLM with **empty memory** (fresh context) |
|
|
96
|
+
| \`prompt(Description, Var)\` | Fresh LLM call, bind result to Var |
|
|
97
|
+
| \`prompt(Description, Var1, Var2)\` | Fresh LLM call, bind two results |
|
|
98
|
+
| \`prompt(Description, Var1, Var2, Var3)\` | Fresh LLM call, bind three results |
|
|
99
|
+
|
|
100
|
+
**When to use \`prompt()\` vs \`task()\`:**
|
|
101
|
+
- Use \`task()\` when you want the LLM to have context from previous \`system()\`, \`user()\`, and \`task()\` calls
|
|
102
|
+
- Use \`prompt()\` when you want a completely fresh LLM call without any prior conversation context
|
|
103
|
+
|
|
104
|
+
\`\`\`prolog
|
|
105
|
+
agent_main :-
|
|
106
|
+
system("You are a helpful assistant."),
|
|
107
|
+
task("What is 2+2?"), % LLM sees the system message
|
|
108
|
+
prompt("What is 3+3?"). % LLM does NOT see any prior context
|
|
109
|
+
\`\`\`
|
|
110
|
+
|
|
111
|
+
#### Direct Tool Execution
|
|
112
|
+
|
|
113
|
+
| Predicate | Description |
|
|
114
|
+
|-----------|-------------|
|
|
115
|
+
| \`exec(Tool, Result)\` | Execute external tool directly |
|
|
116
|
+
|
|
117
|
+
\`\`\`prolog
|
|
118
|
+
exec(web_search(query: "AI news"), Results)
|
|
119
|
+
exec(vm_exec(command: "echo hello"), Result)
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
**Important:** \`vm_exec\` returns a dict with \`stdout\`, \`stderr\`, and \`exitCode\` fields.
|
|
123
|
+
Use \`get_dict/3\` to extract values:
|
|
124
|
+
\`\`\`prolog
|
|
125
|
+
exec(vm_exec(command: "echo hello"), Result),
|
|
126
|
+
get_dict(stdout, Result, Output),
|
|
127
|
+
output(Output).
|
|
128
|
+
\`\`\`
|
|
129
|
+
|
|
130
|
+
**VM Working Directory:** The VM starts with the working directory set to \`/workspace\`, which is
|
|
131
|
+
mounted to your actual workspace. Files are directly accessible:
|
|
132
|
+
\`\`\`prolog
|
|
133
|
+
exec(vm_exec(command: "cat README.md"), Result), % Reads workspace/README.md
|
|
134
|
+
get_dict(stdout, Result, Content).
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
#### Memory Management
|
|
138
|
+
|
|
139
|
+
| Predicate | Description |
|
|
140
|
+
|-----------|-------------|
|
|
141
|
+
| \`system(Text)\` | Add system message (LLM instructions) |
|
|
142
|
+
| \`user(Text)\` | Add user message to context |
|
|
143
|
+
| \`push_context\` | Save memory state (for isolation) |
|
|
144
|
+
| \`push_context(clear)\` | Save and clear memory |
|
|
145
|
+
| \`pop_context\` | Restore previous memory state |
|
|
146
|
+
| \`clear_memory\` | Clear all accumulated memory |
|
|
147
|
+
|
|
148
|
+
**Note:** Memory is automatically restored on backtracking, so \`push_context\`/\`pop_context\`
|
|
149
|
+
are primarily useful for manual isolation within a clause.
|
|
150
|
+
|
|
151
|
+
#### Output
|
|
152
|
+
|
|
153
|
+
| Predicate | Description |
|
|
154
|
+
|-----------|-------------|
|
|
155
|
+
| \`output(Text)\` | Emit progress/intermediate output |
|
|
156
|
+
| \`yield(Text)\` | Alias for output/1 |
|
|
157
|
+
| \`log(Text)\` | Emit debug/log message |
|
|
158
|
+
| \`answer(Text)\` | Emit final answer (commits execution) |
|
|
159
|
+
|
|
160
|
+
#### Tool Definitions
|
|
161
|
+
|
|
162
|
+
Define tools that the LLM can call during \`task()\` execution:
|
|
163
|
+
|
|
164
|
+
\`\`\`prolog
|
|
165
|
+
% Tool wrapper (description is second arg, body calls exec)
|
|
166
|
+
tool(search(Query, Results), "Search the web for information") :-
|
|
167
|
+
exec(web_search(query: Query), Results).
|
|
168
|
+
\`\`\`
|
|
169
|
+
|
|
170
|
+
**CRITICAL: Tools are LLM-only!** Tools defined with \`tool/3\` can ONLY be called by the
|
|
171
|
+
LLM during \`task()\` execution. You CANNOT call tools directly from DML code:
|
|
172
|
+
|
|
173
|
+
\`\`\`prolog
|
|
174
|
+
% WRONG - tools cannot be called directly from DML!
|
|
175
|
+
agent_main :-
|
|
176
|
+
search("AI news", Results), % ERROR: search/2 is not a regular predicate
|
|
177
|
+
output(Results).
|
|
178
|
+
|
|
179
|
+
% CORRECT - let the LLM call the tool via task()
|
|
180
|
+
agent_main :-
|
|
181
|
+
system("You are a research assistant. Use the search tool to find information."),
|
|
182
|
+
task("Search for AI news and summarize the results.", Summary),
|
|
183
|
+
output(Summary).
|
|
184
|
+
|
|
185
|
+
% CORRECT - use exec() directly if you need to call the external tool from DML
|
|
186
|
+
agent_main :-
|
|
187
|
+
exec(web_search(query: "AI news"), Results), % Direct external tool call
|
|
188
|
+
get_dict(results, Results, Data),
|
|
189
|
+
output(Data).
|
|
190
|
+
\`\`\`
|
|
191
|
+
#### Using \`task()\` and \`prompt()\` Inside Tools
|
|
192
|
+
|
|
193
|
+
Tools can use \`task()\` or \`prompt()\` internally to combine Prolog logic with LLM reasoning:
|
|
194
|
+
|
|
195
|
+
\`\`\`prolog
|
|
196
|
+
% A tool that computes then explains
|
|
197
|
+
tool(explain_calculation(A, B, Explanation), "Calculate and explain the result") :-
|
|
198
|
+
Sum is A + B, % Prolog computation
|
|
199
|
+
format(string(Desc), "Explain ~w + ~w = ~w to a child", [A, B, Sum]),
|
|
200
|
+
task(Desc, Explanation). % LLM explanation
|
|
201
|
+
\`\`\`
|
|
202
|
+
|
|
203
|
+
**Memory Isolation:** Nested \`task()\` calls inside tools run with **fresh memory** - they
|
|
204
|
+
do NOT have access to the parent's accumulated memory. If you need context, either:
|
|
205
|
+
1. Pass it as a tool argument
|
|
206
|
+
2. Add it explicitly with \`system()\` inside the tool
|
|
207
|
+
|
|
208
|
+
\`\`\`prolog
|
|
209
|
+
% Pass context explicitly as an argument
|
|
210
|
+
tool(analyze_with_context(Context, Data, Result), "Analyze data with given context") :-
|
|
211
|
+
system(Context), % Add context to this tool's memory
|
|
212
|
+
format(string(Desc), "Analyze: ~w", [Data]),
|
|
213
|
+
task(Desc, Result).
|
|
214
|
+
\`\`\`
|
|
215
|
+
|
|
216
|
+
**Automatic Recursion Prevention:** When \`task()\` runs inside a tool, the nested agent
|
|
217
|
+
cannot call the tool that is currently executing. This prevents infinite recursion.
|
|
218
|
+
|
|
219
|
+
#### Tool Scoping
|
|
220
|
+
|
|
221
|
+
Control which tools are available to nested \`task()\` calls:
|
|
222
|
+
|
|
223
|
+
| Predicate | Description |
|
|
224
|
+
|-----------|-------------|
|
|
225
|
+
| \`with_tools(ToolList, Goal)\` | Run Goal with only specified tools available |
|
|
226
|
+
| \`without_tools(ToolList, Goal)\` | Run Goal excluding specified tools |
|
|
227
|
+
|
|
228
|
+
\`\`\`prolog
|
|
229
|
+
% Only allow search tool in nested task
|
|
230
|
+
tool(safe_research(Topic, Result), "Research with limited tools") :-
|
|
231
|
+
with_tools([search], (
|
|
232
|
+
format(string(Desc), "Research ~w using search", [Topic]),
|
|
233
|
+
task(Desc, Result)
|
|
234
|
+
)).
|
|
235
|
+
|
|
236
|
+
% Exclude expensive tools from nested task
|
|
237
|
+
tool(cheap_task(Input, Output), "Process without expensive tools") :-
|
|
238
|
+
without_tools([expensive_api], (
|
|
239
|
+
task("Process {Input} cheaply", Output)
|
|
240
|
+
)).
|
|
241
|
+
\`\`\`
|
|
242
|
+
#### Built-in Agent Tools
|
|
243
|
+
|
|
244
|
+
During \`task()\` execution, the LLM has access to these built-in tools (plus any you define with \`tool/3\`):
|
|
245
|
+
|
|
246
|
+
| Tool | Description |
|
|
247
|
+
|------|-------------|
|
|
248
|
+
| \`store(variable, value)\` | Store a result in an output variable |
|
|
249
|
+
| \`ask_user(prompt)\` | Ask the user for input or clarification |
|
|
250
|
+
| \`finish(success)\` | Complete the task |
|
|
251
|
+
|
|
252
|
+
**Remember:** These tools (and your custom \`tool/3\` definitions) are only available to the
|
|
253
|
+
LLM during \`task()\` calls. DML code uses \`exec()\` for direct external tool access.
|
|
254
|
+
|
|
255
|
+
**Important:** If your task might need user input (clarification, choices, confirmation),
|
|
256
|
+
you should define an \`ask_user\` tool wrapper so the LLM can request input:
|
|
257
|
+
|
|
258
|
+
\`\`\`prolog
|
|
259
|
+
% Define ask_user wrapper so LLM can request user input during task()
|
|
260
|
+
tool(ask_user(Prompt, Response), "Ask the user a question and get their response") :-
|
|
261
|
+
exec(ask_user(prompt: Prompt), Result),
|
|
262
|
+
get_dict(user_response, Result, Response).
|
|
263
|
+
\`\`\`
|
|
264
|
+
|
|
265
|
+
### String Interpolation
|
|
266
|
+
|
|
267
|
+
DML supports **automatic string interpolation** using \`{Variable}\` syntax in task descriptions
|
|
268
|
+
and output predicates. This is the preferred method:
|
|
269
|
+
|
|
270
|
+
\`\`\`prolog
|
|
271
|
+
agent_main(Topic) :-
|
|
272
|
+
task("Research the topic: {Topic}"),
|
|
273
|
+
output("Finished researching {Topic}"),
|
|
274
|
+
answer("Done").
|
|
275
|
+
\`\`\`
|
|
276
|
+
|
|
277
|
+
**IMPORTANT:** Never mix \`{Variable}\` interpolation with \`format/3\`. Choose one approach:
|
|
278
|
+
|
|
279
|
+
**Option 1: String Interpolation (preferred for simple cases)**
|
|
280
|
+
\`\`\`prolog
|
|
281
|
+
% Variables are automatically substituted
|
|
282
|
+
task("Analyze {Data} and summarize in Summary.", Summary),
|
|
283
|
+
output("Analysis complete for {Data}")
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
**Option 2: format/3 for complex string building (Prolog-style)**
|
|
287
|
+
\`\`\`prolog
|
|
288
|
+
% format/3 writes to a string variable - use ~w for terms, ~s for strings
|
|
289
|
+
format(string(Message), "Found ~d results for query: ~w", [Count, Query]),
|
|
290
|
+
output(Message)
|
|
291
|
+
\`\`\`
|
|
292
|
+
|
|
293
|
+
**WRONG - Never do this:**
|
|
294
|
+
\`\`\`prolog
|
|
295
|
+
% DON'T mix interpolation and format
|
|
296
|
+
output(format("Value: {X}", [X])) % WRONG! format doesn't return a value
|
|
297
|
+
|
|
298
|
+
% DON'T use {Var} inside format strings
|
|
299
|
+
format(string(S), "Topic: {Topic}", []) % WRONG! Use ~w instead
|
|
300
|
+
\`\`\`
|
|
301
|
+
|
|
302
|
+
### Control Flow
|
|
303
|
+
|
|
304
|
+
\`\`\`prolog
|
|
305
|
+
% Conjunction (and)
|
|
306
|
+
goal1, goal2, goal3
|
|
307
|
+
|
|
308
|
+
% Disjunction (or)
|
|
309
|
+
(goal1 ; goal2)
|
|
310
|
+
|
|
311
|
+
% If-then-else
|
|
312
|
+
(Condition -> Then ; Else)
|
|
313
|
+
|
|
314
|
+
% Negation as failure
|
|
315
|
+
\\+ goal
|
|
316
|
+
|
|
317
|
+
% Cut (commit to this branch)
|
|
318
|
+
!
|
|
319
|
+
|
|
320
|
+
% Exception handling
|
|
321
|
+
catch(Goal, Error, Recovery)
|
|
322
|
+
throw(some_error)
|
|
323
|
+
\`\`\`
|
|
324
|
+
|
|
325
|
+
### Logic & Optimization (CLP)
|
|
326
|
+
|
|
327
|
+
DML supports Prolog's Constraint Logic Programming (CLP) libraries. Use these instead of Python for mathematical optimization, scheduling, or strict logic puzzles:
|
|
328
|
+
|
|
329
|
+
- **CLP(FD)**: Finite domains (integers). Use \`:- use_module(library(clpfd)).\`
|
|
330
|
+
- **CLP(Q)**: Rational numbers (exact fractions). Use \`:- use_module(library(clpq)).\`
|
|
331
|
+
- **CLP(R)**: Real numbers (floating point). Use \`:- use_module(library(clpr)).\`
|
|
332
|
+
|
|
333
|
+
\`\`\`prolog
|
|
334
|
+
:- use_module(library(clpfd)).
|
|
335
|
+
|
|
336
|
+
% Solve: find X and Y such that X+Y=10 and X*Y=24
|
|
337
|
+
solve(X, Y) :-
|
|
338
|
+
[X,Y] ins 0..10,
|
|
339
|
+
X + Y #= 10,
|
|
340
|
+
X * Y #= 24,
|
|
341
|
+
label([X,Y]).
|
|
342
|
+
\`\`\`
|
|
343
|
+
|
|
344
|
+
### Backtracking
|
|
345
|
+
|
|
346
|
+
DML supports full Prolog backtracking across LLM calls:
|
|
347
|
+
|
|
348
|
+
\`\`\`prolog
|
|
349
|
+
% Try multiple approaches
|
|
350
|
+
agent_main :-
|
|
351
|
+
( try_approach_1
|
|
352
|
+
; try_approach_2 % Falls back if first fails
|
|
353
|
+
; fallback_approach
|
|
354
|
+
),
|
|
355
|
+
answer("Done").
|
|
356
|
+
\`\`\`
|
|
357
|
+
|
|
358
|
+
### List Processing
|
|
359
|
+
|
|
360
|
+
\`\`\`prolog
|
|
361
|
+
% Recursive list processing
|
|
362
|
+
process_items([]).
|
|
363
|
+
process_items([H|T]) :-
|
|
364
|
+
process_one(H),
|
|
365
|
+
process_items(T).
|
|
366
|
+
|
|
367
|
+
% Using findall
|
|
368
|
+
findall(X, some_condition(X), Results)
|
|
369
|
+
|
|
370
|
+
% Using maplist
|
|
371
|
+
maplist(process_one, Items)
|
|
372
|
+
\`\`\`
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Common Patterns
|
|
377
|
+
|
|
378
|
+
### Pattern 1: Simple Task Agent
|
|
379
|
+
\`\`\`prolog
|
|
380
|
+
agent_main(Topic) :-
|
|
381
|
+
system("You are a helpful research assistant."),
|
|
382
|
+
task("Research {Topic} and provide a comprehensive summary."),
|
|
383
|
+
answer("Research complete!").
|
|
384
|
+
\`\`\`
|
|
385
|
+
|
|
386
|
+
### Pattern 2: Multi-Step Workflow
|
|
387
|
+
\`\`\`prolog
|
|
388
|
+
agent_main(Topic) :-
|
|
389
|
+
system("You are a thorough research assistant."),
|
|
390
|
+
|
|
391
|
+
output("Step 1: Gathering information..."),
|
|
392
|
+
task("Search for recent information about {Topic}. Store findings in Findings.", Findings),
|
|
393
|
+
|
|
394
|
+
output("Step 2: Analyzing..."),
|
|
395
|
+
task("Analyze these findings: {Findings}. Store your analysis in Analysis.", Analysis),
|
|
396
|
+
|
|
397
|
+
output("Step 3: Generating report..."),
|
|
398
|
+
task("Create a comprehensive report based on this analysis: {Analysis}"),
|
|
399
|
+
|
|
400
|
+
answer("Report generated!").
|
|
401
|
+
\`\`\`
|
|
402
|
+
|
|
403
|
+
### Pattern 3: Tool-Enabled Agent
|
|
404
|
+
\`\`\`prolog
|
|
405
|
+
tool(search(Query, Results), "Search the web") :-
|
|
406
|
+
exec(web_search(query: Query), Results).
|
|
407
|
+
|
|
408
|
+
agent_main(Topic) :-
|
|
409
|
+
system("You are a research assistant with web search. Use the search tool."),
|
|
410
|
+
task("Research {Topic} using available tools."),
|
|
411
|
+
answer("Research complete!").
|
|
412
|
+
\`\`\`
|
|
413
|
+
|
|
414
|
+
### Pattern 3b: Tool with Nested LLM Call
|
|
415
|
+
\`\`\`prolog
|
|
416
|
+
% A tool that uses LLM to analyze search results
|
|
417
|
+
tool(smart_search(Query, Summary), "Search and summarize results") :-
|
|
418
|
+
exec(web_search(query: Query), Results),
|
|
419
|
+
format(string(Desc), "Summarize these search results: ~w", [Results]),
|
|
420
|
+
task(Desc, Summary). % Nested task CANNOT call smart_search (recursion prevention)
|
|
421
|
+
|
|
422
|
+
agent_main(Topic) :-
|
|
423
|
+
system("Use smart_search to research topics."),
|
|
424
|
+
task("Research {Topic}."),
|
|
425
|
+
answer("Done!").
|
|
426
|
+
\`\`\`
|
|
427
|
+
|
|
428
|
+
### Pattern 4: Code Execution (Use Sparingly!)
|
|
429
|
+
\`\`\`prolog
|
|
430
|
+
% ONLY use exec/Python when you need:
|
|
431
|
+
% - External packages (pandas, numpy, etc.)
|
|
432
|
+
% - Shell commands (find, grep, sed, awk, curl)
|
|
433
|
+
% - Complex imperative logic that's awkward in Prolog
|
|
434
|
+
%
|
|
435
|
+
% NOTE: vm_exec returns a dict with stdout, stderr, exitCode - use get_dict to extract
|
|
436
|
+
% NOTE: The VM starts in /workspace which is your actual workspace directory
|
|
437
|
+
|
|
438
|
+
agent_main(Task) :-
|
|
439
|
+
system("You are a coding assistant."),
|
|
440
|
+
|
|
441
|
+
task("Write Python code to solve: {Task}. Store only the code in Code.", Code),
|
|
442
|
+
|
|
443
|
+
% Write code to a file in the workspace (VM cwd is /workspace)
|
|
444
|
+
open('script.py', write, S),
|
|
445
|
+
write(S, Code),
|
|
446
|
+
close(S),
|
|
447
|
+
|
|
448
|
+
output("Executing code..."),
|
|
449
|
+
exec(vm_exec(command: "python3 script.py"), Result), % Runs in /workspace
|
|
450
|
+
get_dict(stdout, Result, Output),
|
|
451
|
+
|
|
452
|
+
task("Explain this execution result: {Output}"),
|
|
453
|
+
|
|
454
|
+
answer("Done!").
|
|
455
|
+
\`\`\`
|
|
456
|
+
|
|
457
|
+
### Pattern 5: Data Analysis with VM
|
|
458
|
+
\`\`\`prolog
|
|
459
|
+
% Good use of exec: requires pandas package
|
|
460
|
+
% NOTE: vm_exec returns a dict - use get_dict to extract stdout
|
|
461
|
+
agent_main(CsvPath, Question) :-
|
|
462
|
+
system("You are a data analyst."),
|
|
463
|
+
|
|
464
|
+
output("Setting up environment..."),
|
|
465
|
+
exec(vm_exec(command: "pip install pandas"), _),
|
|
466
|
+
|
|
467
|
+
output("Analyzing data..."),
|
|
468
|
+
task("Write Python code to load {CsvPath} with pandas and answer: {Question}. Store only the code in Code.", Code),
|
|
469
|
+
|
|
470
|
+
% Write code to file and execute
|
|
471
|
+
open('analysis.py', write, S),
|
|
472
|
+
write(S, Code),
|
|
473
|
+
close(S),
|
|
474
|
+
exec(vm_exec(command: "python3 analysis.py"), Result),
|
|
475
|
+
get_dict(stdout, Result, Output),
|
|
476
|
+
|
|
477
|
+
task("Interpret and explain these analysis results: {Output}"),
|
|
478
|
+
|
|
479
|
+
answer("Analysis complete!").
|
|
480
|
+
\`\`\`
|
|
481
|
+
|
|
482
|
+
### Pattern 6: File I/O (Use Prolog, NOT Python!)
|
|
483
|
+
\`\`\`prolog
|
|
484
|
+
% GOOD: Use Prolog's native file I/O
|
|
485
|
+
agent_main(Content) :-
|
|
486
|
+
task("Generate a report about {Content}. Store in Report.", Report),
|
|
487
|
+
|
|
488
|
+
% Write to file using Prolog (not Python!)
|
|
489
|
+
open('output.md', write, Stream),
|
|
490
|
+
write(Stream, Report),
|
|
491
|
+
close(Stream),
|
|
492
|
+
|
|
493
|
+
answer("Report saved to output.md").
|
|
494
|
+
|
|
495
|
+
% Build filename from parts
|
|
496
|
+
agent_main(Name, Content) :-
|
|
497
|
+
task("Generate content about {Name}. Store in Text.", Text),
|
|
498
|
+
|
|
499
|
+
% Construct filename using atom operations
|
|
500
|
+
atom_string(NameAtom, Name),
|
|
501
|
+
atom_concat(NameAtom, '_report.md', FilenameAtom),
|
|
502
|
+
atom_string(FilenameAtom, Filename),
|
|
503
|
+
|
|
504
|
+
open(Filename, write, Stream),
|
|
505
|
+
write(Stream, Text),
|
|
506
|
+
close(Stream),
|
|
507
|
+
|
|
508
|
+
output("Saved to {Filename}"),
|
|
509
|
+
answer("Done!").
|
|
510
|
+
\`\`\`
|
|
511
|
+
|
|
512
|
+
### Pattern 7: Using format/3 for Complex Strings
|
|
513
|
+
\`\`\`prolog
|
|
514
|
+
% When you need to build strings with numbers or complex formatting
|
|
515
|
+
agent_main(Items) :-
|
|
516
|
+
length(Items, Count),
|
|
517
|
+
format(string(StatusMsg), "Processing ~d items", [Count]),
|
|
518
|
+
output(StatusMsg),
|
|
519
|
+
|
|
520
|
+
process_all(Items),
|
|
521
|
+
|
|
522
|
+
format(string(DoneMsg), "Completed processing ~d items successfully", [Count]),
|
|
523
|
+
answer(DoneMsg).
|
|
524
|
+
\`\`\`
|
|
525
|
+
|
|
526
|
+
### Pattern 8: Interactive Agent (User Input)
|
|
527
|
+
\`\`\`prolog
|
|
528
|
+
% When the task may need user clarification or choices
|
|
529
|
+
% Define ask_user wrapper so LLM can interact with user
|
|
530
|
+
tool(ask_user(Prompt, Response), "Ask the user a question") :-
|
|
531
|
+
exec(ask_user(prompt: Prompt), Result),
|
|
532
|
+
get_dict(user_response, Result, Response).
|
|
533
|
+
|
|
534
|
+
agent_main(Task) :-
|
|
535
|
+
system("You are a helpful assistant. If you need clarification, use the ask_user tool."),
|
|
536
|
+
|
|
537
|
+
task("Help the user with: {Task}. If anything is unclear, ask for clarification."),
|
|
538
|
+
|
|
539
|
+
answer("Task completed!").
|
|
540
|
+
\`\`\`
|
|
541
|
+
|
|
542
|
+
### Pattern 9: Error Handling with catch/throw
|
|
543
|
+
\`\`\`prolog
|
|
544
|
+
% Safe tool call with error recovery
|
|
545
|
+
agent_main(Query) :-
|
|
546
|
+
catch(
|
|
547
|
+
(
|
|
548
|
+
exec(web_search(query: Query), Results),
|
|
549
|
+
task("Summarize: {Results}")
|
|
550
|
+
),
|
|
551
|
+
Error,
|
|
552
|
+
(
|
|
553
|
+
format(string(ErrMsg), "Search failed: ~w. Proceeding without search.", [Error]),
|
|
554
|
+
output(ErrMsg),
|
|
555
|
+
task("Answer based on your knowledge: {Query}")
|
|
556
|
+
)
|
|
557
|
+
),
|
|
558
|
+
answer("Done!").
|
|
559
|
+
\`\`\`
|
|
560
|
+
|
|
561
|
+
### Pattern 10: Fresh Context with prompt()
|
|
562
|
+
\`\`\`prolog
|
|
563
|
+
% Use prompt() for independent sub-tasks that shouldn't share context
|
|
564
|
+
agent_main(Topic) :-
|
|
565
|
+
system("You are a research assistant."),
|
|
566
|
+
|
|
567
|
+
% Main research with accumulated context
|
|
568
|
+
task("Research {Topic} deeply.", MainFindings),
|
|
569
|
+
|
|
570
|
+
% Independent critique - fresh context, no bias from main research
|
|
571
|
+
prompt("As a skeptical reviewer, critique this research: {MainFindings}. Store critique in Critique.", Critique),
|
|
572
|
+
|
|
573
|
+
% Back to main context for final synthesis
|
|
574
|
+
task("Address this critique: {Critique}"),
|
|
575
|
+
|
|
576
|
+
answer("Research complete with peer review!").
|
|
577
|
+
\`\`\`
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## When to Use exec() vs Prolog
|
|
582
|
+
|
|
583
|
+
### Use Prolog Native Functionality For:
|
|
584
|
+
- **File I/O**: \`open/3\`, \`write/2\`, \`read/2\`, \`close/1\`
|
|
585
|
+
- **String manipulation**: \`atom_concat/3\`, \`atom_string/2\`, \`split_string/4\`
|
|
586
|
+
- **List operations**: \`append/3\`, \`member/2\`, \`findall/3\`, \`maplist/2\`
|
|
587
|
+
- **Arithmetic**: \`is/2\`, comparison operators
|
|
588
|
+
- **Logic and control flow**: conjunctions, disjunctions, conditionals
|
|
589
|
+
|
|
590
|
+
### Use exec() ONLY For:
|
|
591
|
+
- **External packages**: pandas, numpy, requests, matplotlib, etc.
|
|
592
|
+
- **Shell commands**: find, grep, sed, awk, curl, git
|
|
593
|
+
- **System operations**: environment variables, process management
|
|
594
|
+
- **Complex imperative logic**: loops with side effects, mutable state
|
|
595
|
+
|
|
596
|
+
### BAD Example - Unnecessary Python:
|
|
597
|
+
\`\`\`prolog
|
|
598
|
+
% DON'T do this - Python for simple file writing
|
|
599
|
+
exec(vm_exec(command: "python3 -c \"open('out.txt','w').write('hello')\""), _)
|
|
600
|
+
\`\`\`
|
|
601
|
+
|
|
602
|
+
### GOOD Example - Use Prolog:
|
|
603
|
+
\`\`\`prolog
|
|
604
|
+
% DO this instead - native Prolog file I/O
|
|
605
|
+
open('out.txt', write, S),
|
|
606
|
+
write(S, Content),
|
|
607
|
+
close(S)
|
|
608
|
+
\`\`\`
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## File Access Patterns with vm_exec
|
|
613
|
+
|
|
614
|
+
AgentVM runs a sandboxed Alpine Linux VM using **BusyBox** (not GNU coreutils).
|
|
615
|
+
Some GNU-specific options may not be available. The workspace is mounted at \`/workspace\`.
|
|
616
|
+
|
|
617
|
+
**Important:** \`vm_exec\` returns a dict - always extract stdout:
|
|
618
|
+
\`\`\`prolog
|
|
619
|
+
exec(vm_exec(command: "ls /workspace"), Result),
|
|
620
|
+
get_dict(stdout, Result, Output).
|
|
621
|
+
\`\`\`
|
|
622
|
+
|
|
623
|
+
### Common File Operations
|
|
624
|
+
|
|
625
|
+
| Operation | Command | Example |
|
|
626
|
+
|-----------|---------|---------|
|
|
627
|
+
| List files | \`ls {dir}\` | \`ls /workspace/src\` |
|
|
628
|
+
| Find by name | \`find {dir} -name '{pattern}' -type f\` | \`find /workspace -name '*.ts' -type f\` |
|
|
629
|
+
| Find shallow | \`find {dir} -maxdepth 1 -name '{pattern}'\` | \`find /workspace/src -maxdepth 1 -name '*.ts'\` |
|
|
630
|
+
| Read file | \`cat {path}\` | \`cat /workspace/README.md\` |
|
|
631
|
+
| Read first N lines | \`head -{n} {path}\` | \`head -10 /workspace/file.ts\` |
|
|
632
|
+
| Read last N lines | \`tail -{n} {path}\` | \`tail -5 /workspace/file.ts\` |
|
|
633
|
+
| Read line range | \`sed -n '{start},{end}p' {path}\` | \`sed -n '1,10p' /workspace/file.ts\` |
|
|
634
|
+
| Grep in file | \`grep '{pattern}' {path}\` | \`grep 'import' /workspace/file.ts\` |
|
|
635
|
+
| Grep with line nums | \`grep -n '{pattern}' {path}\` | \`grep -n 'export' /workspace/file.ts\` |
|
|
636
|
+
| Grep recursive | \`grep -rn '{pattern}' {dir}\` | \`grep -rn 'TODO' /workspace/src\` |
|
|
637
|
+
| File exists | \`test -f {path} && echo yes\` | \`test -f /workspace/file.ts && echo yes\` |
|
|
638
|
+
| Dir exists | \`test -d {path} && echo yes\` | \`test -d /workspace/src && echo yes\` |
|
|
639
|
+
| File size | \`stat -c %s {path}\` | \`stat -c %s /workspace/file.ts\` |
|
|
640
|
+
| Line count | \`wc -l < {path}\` | \`wc -l < /workspace/file.ts\` |
|
|
641
|
+
| Count files | \`find ... \\| wc -l\` | \`find /workspace -name '*.ts' \\| wc -l\` |
|
|
642
|
+
| Basename | \`basename {path}\` | \`basename /workspace/src/file.ts\` |
|
|
643
|
+
| Dirname | \`dirname {path}\` | \`dirname /workspace/src/file.ts\` |
|
|
644
|
+
|
|
645
|
+
### DML File Access Patterns
|
|
646
|
+
|
|
647
|
+
#### List Directory
|
|
648
|
+
\`\`\`prolog
|
|
649
|
+
list_files(Dir, Files) :-
|
|
650
|
+
format(string(Cmd), "ls ~w", [Dir]),
|
|
651
|
+
exec(vm_exec(command: Cmd), Result),
|
|
652
|
+
get_dict(stdout, Result, Output),
|
|
653
|
+
split_string(Output, "\\n", "\\s\\t\\r\\n", Files).
|
|
654
|
+
\`\`\`
|
|
655
|
+
|
|
656
|
+
#### Find Files by Pattern
|
|
657
|
+
\`\`\`prolog
|
|
658
|
+
find_files(Dir, Pattern, Files) :-
|
|
659
|
+
format(string(Cmd), "find ~w -name '~w' -type f", [Dir, Pattern]),
|
|
660
|
+
exec(vm_exec(command: Cmd), Result),
|
|
661
|
+
get_dict(stdout, Result, Output),
|
|
662
|
+
split_string(Output, "\\n", "\\s\\t\\r\\n", Files).
|
|
663
|
+
\`\`\`
|
|
664
|
+
|
|
665
|
+
#### Read File
|
|
666
|
+
\`\`\`prolog
|
|
667
|
+
read_file(Path, Content) :-
|
|
668
|
+
format(string(Cmd), "cat ~w", [Path]),
|
|
669
|
+
exec(vm_exec(command: Cmd), Result),
|
|
670
|
+
get_dict(stdout, Result, Content).
|
|
671
|
+
\`\`\`
|
|
672
|
+
|
|
673
|
+
#### Read First N Lines
|
|
674
|
+
\`\`\`prolog
|
|
675
|
+
read_head(Path, N, Content) :-
|
|
676
|
+
format(string(Cmd), "head -~d ~w", [N, Path]),
|
|
677
|
+
exec(vm_exec(command: Cmd), Result),
|
|
678
|
+
get_dict(stdout, Result, Content).
|
|
679
|
+
\`\`\`
|
|
680
|
+
|
|
681
|
+
#### Read Line Range
|
|
682
|
+
\`\`\`prolog
|
|
683
|
+
read_lines(Path, Start, End, Content) :-
|
|
684
|
+
format(string(Cmd), "sed -n '~d,~dp' ~w", [Start, End, Path]),
|
|
685
|
+
exec(vm_exec(command: Cmd), Result),
|
|
686
|
+
get_dict(stdout, Result, Content).
|
|
687
|
+
\`\`\`
|
|
688
|
+
|
|
689
|
+
#### Grep in File
|
|
690
|
+
\`\`\`prolog
|
|
691
|
+
grep(Path, Pattern, Matches) :-
|
|
692
|
+
format(string(Cmd), "grep -n '~w' ~w || true", [Pattern, Path]),
|
|
693
|
+
exec(vm_exec(command: Cmd), Result),
|
|
694
|
+
get_dict(stdout, Result, Matches).
|
|
695
|
+
\`\`\`
|
|
696
|
+
|
|
697
|
+
#### Recursive Grep
|
|
698
|
+
\`\`\`prolog
|
|
699
|
+
grep_recursive(Dir, Pattern, Matches) :-
|
|
700
|
+
format(string(Cmd), "grep -rn '~w' ~w || true", [Pattern, Dir]),
|
|
701
|
+
exec(vm_exec(command: Cmd), Result),
|
|
702
|
+
get_dict(stdout, Result, Matches).
|
|
703
|
+
\`\`\`
|
|
704
|
+
|
|
705
|
+
#### File Exists Check
|
|
706
|
+
\`\`\`prolog
|
|
707
|
+
file_exists(Path) :-
|
|
708
|
+
format(string(Cmd), "test -f ~w && echo yes || echo no", [Path]),
|
|
709
|
+
exec(vm_exec(command: Cmd), Result),
|
|
710
|
+
get_dict(stdout, Result, "yes").
|
|
711
|
+
\`\`\`
|
|
712
|
+
|
|
713
|
+
#### Line Count
|
|
714
|
+
\`\`\`prolog
|
|
715
|
+
line_count(Path, Count) :-
|
|
716
|
+
format(string(Cmd), "wc -l < ~w", [Path]),
|
|
717
|
+
exec(vm_exec(command: Cmd), Result),
|
|
718
|
+
get_dict(stdout, Result, Output),
|
|
719
|
+
normalize_space(atom(CountAtom), Output),
|
|
720
|
+
atom_number(CountAtom, Count).
|
|
721
|
+
\`\`\`
|
|
722
|
+
|
|
723
|
+
### BusyBox Limitations
|
|
724
|
+
|
|
725
|
+
BusyBox in Alpine Linux has limited options compared to GNU coreutils:
|
|
726
|
+
- \`grep --include\` is NOT supported - use \`find ... -exec grep\` instead
|
|
727
|
+
- Some \`find\` options may differ
|
|
728
|
+
- Use \`|| true\` with grep to prevent failures when no matches found
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
## Conversion Guidelines
|
|
733
|
+
|
|
734
|
+
1. **Identify the core task** - What is the primary goal?
|
|
735
|
+
2. **Determine parameters** - What inputs does the agent need?
|
|
736
|
+
3. **Map to patterns** - Which DML pattern best fits?
|
|
737
|
+
4. **Prefer Prolog native operations** - Use Prolog for file I/O, strings, lists
|
|
738
|
+
5. **Use exec() sparingly** - Only for packages, shell commands, imperative logic
|
|
739
|
+
6. **Define required tools** - What external capabilities are needed?
|
|
740
|
+
7. **Handle edge cases** - Add fallbacks and error handling
|
|
741
|
+
8. **Add progress output** - Keep users informed with \`output/1\`
|
|
742
|
+
9. **Add ask_user wrapper** - If the task might need user input, clarification, or choices
|
|
743
|
+
|
|
744
|
+
## CRITICAL: Tools are LLM-Only
|
|
745
|
+
|
|
746
|
+
**Tools defined with \`tool/3\` can ONLY be called by the LLM during \`task()\` execution.**
|
|
747
|
+
|
|
748
|
+
- \`tool/3\` defines capabilities for the LLM to use
|
|
749
|
+
- DML code CANNOT call tools directly as predicates
|
|
750
|
+
- If DML code needs external functionality, use \`exec()\` directly
|
|
751
|
+
|
|
752
|
+
\`\`\`prolog
|
|
753
|
+
% WRONG - cannot call tool from DML code
|
|
754
|
+
agent_main :-
|
|
755
|
+
my_search("query", Results). % ERROR!
|
|
756
|
+
|
|
757
|
+
% CORRECT - use exec() for direct access
|
|
758
|
+
agent_main :-
|
|
759
|
+
exec(web_search(query: "query"), Results).
|
|
760
|
+
|
|
761
|
+
% CORRECT - let LLM use the tool via task()
|
|
762
|
+
agent_main :-
|
|
763
|
+
task("Search for information about X.", Summary).
|
|
764
|
+
\`\`\`
|
|
765
|
+
|
|
766
|
+
## CRITICAL: String Handling Rules
|
|
767
|
+
|
|
768
|
+
**NEVER do any of these:**
|
|
769
|
+
- \`output(format(...))\` - format/3 doesn't return a value, it binds to first arg
|
|
770
|
+
- \`answer(format(...))\` - same issue
|
|
771
|
+
- Mixing \`{Var}\` and \`~w\` in the same string
|
|
772
|
+
- Using \`{Var}\` inside format/3 format strings
|
|
773
|
+
|
|
774
|
+
**DO this instead:**
|
|
775
|
+
- Use \`{Variable}\` interpolation directly: \`output("Processing {Item}")\`
|
|
776
|
+
- Or use format/3 properly: \`format(string(Msg), "Count: ~d", [N]), output(Msg)\`
|
|
777
|
+
|
|
778
|
+
## CRITICAL: Prolog vs exec() Rules
|
|
779
|
+
|
|
780
|
+
**Use Prolog for:**
|
|
781
|
+
- File I/O: \`open/3\`, \`write/2\`, \`close/1\`
|
|
782
|
+
- String building: \`atom_concat/3\`, \`atom_string/2\`
|
|
783
|
+
- All standard logic and data manipulation
|
|
784
|
+
|
|
785
|
+
**Use exec() ONLY for:**
|
|
786
|
+
- External packages (pandas, numpy)
|
|
787
|
+
- Shell commands (grep, curl, find)
|
|
788
|
+
- Complex imperative tasks
|
|
789
|
+
|
|
790
|
+
## Output Requirements
|
|
791
|
+
|
|
792
|
+
Your DML output must:
|
|
793
|
+
|
|
794
|
+
1. Start with a comment header describing the program
|
|
795
|
+
2. Define any tool wrappers needed with \`tool/3\`
|
|
796
|
+
3. **If the task may need user input, define an \`ask_user\` tool wrapper**
|
|
797
|
+
4. Have a single \`agent_main\` entry point
|
|
798
|
+
5. Use appropriate system prompts
|
|
799
|
+
6. Include progress outputs for long-running tasks
|
|
800
|
+
7. End with \`answer/1\` to signal completion
|
|
801
|
+
8. Handle stated edge cases
|
|
802
|
+
9. **Only use tools from the Available External Tools list**
|
|
803
|
+
10. **Use ONLY {Variable} interpolation OR format/3, never mix them**
|
|
804
|
+
11. **NEVER pass format(...) directly to output/1 or answer/1**
|
|
805
|
+
12. **Use Prolog native file I/O, NOT Python exec() for simple file operations**
|
|
806
|
+
|
|
807
|
+
Output ONLY the DML code, no explanations or markdown code fences.
|
|
808
|
+
`;
|
|
809
|
+
// =============================================================================
|
|
810
|
+
// Tool Table Building
|
|
811
|
+
// =============================================================================
|
|
812
|
+
/**
|
|
813
|
+
* Build the tools table for the prompt
|
|
814
|
+
*/
|
|
815
|
+
export function buildToolsTable(tools) {
|
|
816
|
+
if (tools.length === 0) {
|
|
817
|
+
return 'No additional tools configured.';
|
|
818
|
+
}
|
|
819
|
+
const lines = [];
|
|
820
|
+
// Group by provider
|
|
821
|
+
const byProvider = new Map();
|
|
822
|
+
for (const tool of tools) {
|
|
823
|
+
const existing = byProvider.get(tool.provider) || [];
|
|
824
|
+
existing.push(tool);
|
|
825
|
+
byProvider.set(tool.provider, existing);
|
|
826
|
+
}
|
|
827
|
+
for (const [provider, providerTools] of byProvider) {
|
|
828
|
+
const isBuiltIn = provider === 'agentvm';
|
|
829
|
+
lines.push(`### ${isBuiltIn ? 'Built-in Tools (AgentVM)' : `${provider} (MCP)`}`);
|
|
830
|
+
lines.push('');
|
|
831
|
+
lines.push('| Tool | Description |');
|
|
832
|
+
lines.push('|------|-------------|');
|
|
833
|
+
for (const tool of providerTools) {
|
|
834
|
+
// Format tool signature
|
|
835
|
+
let signature = tool.name;
|
|
836
|
+
if (tool.schema && typeof tool.schema === 'object') {
|
|
837
|
+
const schema = tool.schema;
|
|
838
|
+
if (schema.properties) {
|
|
839
|
+
const params = Object.keys(schema.properties).join(', ');
|
|
840
|
+
signature = `${tool.name}(${params})`;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
lines.push(`| \`${signature}\` | ${tool.description} |`);
|
|
844
|
+
}
|
|
845
|
+
lines.push('');
|
|
846
|
+
}
|
|
847
|
+
return lines.join('\n');
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Build the complete compilation prompt with tools injected
|
|
851
|
+
*/
|
|
852
|
+
export function buildCompilationPrompt(tools) {
|
|
853
|
+
const toolsTable = buildToolsTable(tools);
|
|
854
|
+
return DML_CONVERSION_PROMPT.replace('{TOOLS_TABLE}', toolsTable);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Build the user message containing the markdown to convert
|
|
858
|
+
*/
|
|
859
|
+
export function buildUserMessage(markdown) {
|
|
860
|
+
return `Convert the following Markdown task description into a DML program:
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
${markdown}
|
|
865
|
+
|
|
866
|
+
---
|
|
867
|
+
|
|
868
|
+
Output only valid DML code.`;
|
|
869
|
+
}
|
|
870
|
+
//# sourceMappingURL=compiler_prompt.js.map
|