deepclause-sdk 0.0.85 → 0.0.86

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.
@@ -779,9 +779,9 @@ get_reasoning_effort(State, Effort) :-
779
779
  %% Recipe Context Helpers
780
780
  %% ============================================================
781
781
 
782
- %% load_recipe_content(+Query, -Content)
783
- load_recipe_content(Query, RecipeContent) :-
784
- exec(consult_recipes(query: Query, max_results: 1), Result),
782
+ %% load_recipe_content(+Query, +StateIn, -StateOut, -Content)
783
+ load_recipe_content(Query, StateIn, StateOut, RecipeContent) :-
784
+ mi_call(exec(consult_recipes(query: Query, max_results: 1), Result), StateIn, StateOut),
785
785
  get_dict(matches, Result, Matches),
786
786
  ( Matches = [Match|_]
787
787
  -> get_dict(content, Match, RecipeContent)
@@ -1484,8 +1484,8 @@ mi_call(with_reasoning(Goal, Effort), StateIn, StateOut) :-
1484
1484
  %% Run Goal with a recipe loaded as transient context (not persisted to memory).
1485
1485
  mi_call(with_recipe(Goal, Query), StateIn, StateOut) :-
1486
1486
  !,
1487
- load_recipe_content(Query, RecipeContent),
1488
- set_recipe_context(StateIn, RecipeContent, ScopedState),
1487
+ load_recipe_content(Query, StateIn, StateAfterRecipeLoad, RecipeContent),
1488
+ set_recipe_context(StateAfterRecipeLoad, RecipeContent, ScopedState),
1489
1489
  mi_call(Goal, ScopedState, StateWithRecipe),
1490
1490
  clear_recipe_context(StateWithRecipe, StateOut).
1491
1491
 
@@ -173,13 +173,19 @@ Note: There is no separate save_file or read_file tool. File operations go throu
173
173
 
174
174
  {ReasoningNote}
175
175
 
176
- Also specify a recipe query for each task if relevant (null otherwise).
177
-
178
- Return a JSON array of objects:
179
- [{\"description\": \"task description\", \"tools\": [\"tool_name\", ...], \"reasoning\": \"none|low|medium|high\", \"recipe\": \"query string or null\"}]
180
-
181
- Return ONLY the JSON array.", string(TasksJson)),
182
- ( catch(parse_plan_json(TasksJson, Steps), _, fail)
176
+ Also specify a recipe query for each task if relevant (NONE otherwise).
177
+
178
+ Return four ordered lists aligned 1:1:
179
+ - TaskDescriptions: plain task descriptions.
180
+ - ToolSpecs: each item must be either ALL or a comma-separated list of exact tool names from the available tools list above.
181
+ - ReasoningSpecs: each item must be exactly one of none, low, medium, high.
182
+ - RecipeSpecs: each item must be either NONE or a recipe query string.
183
+
184
+ Store the ordered task descriptions in TaskDescriptions.
185
+ Store the ordered tool specs in ToolSpecs.
186
+ Store the ordered reasoning specs in ReasoningSpecs.
187
+ Store the ordered recipe specs in RecipeSpecs.", list(string(TaskDescriptions)), list(string(ToolSpecs)), list(string(ReasoningSpecs)), list(string(RecipeSpecs))),
188
+ ( build_plan_steps_from_specs(TaskDescriptions, ToolSpecs, ReasoningSpecs, RecipeSpecs, Steps)
183
189
  -> true
184
190
  ; fallback_plan_steps_from_strategy(Strategy, Steps)
185
191
  ).
@@ -196,44 +202,66 @@ valid_plan_tool(create_new_skill).
196
202
  valid_plan_tool(ask_user).
197
203
  valid_plan_tool(inform_user).
198
204
 
199
- %% tool_name_to_atom(+Raw, -Atom)
200
- tool_name_to_atom(Raw, Atom) :-
201
- ( atom(Raw) -> Atom = Raw
202
- ; string(Raw) -> atom_string(Atom, Raw)
203
- ; Atom = Raw
205
+ default_plan_tools([run_bash, run_skill, consult_recipes, search_web, search_news, fetch_url, download_file, create_new_skill, ask_user, inform_user]).
206
+
207
+ build_plan_steps_from_specs([], [], [], [], []).
208
+ build_plan_steps_from_specs([Desc|RestDesc], [ToolSpec|RestTools], [ReasoningSpec|RestReasoning], [RecipeSpec|RestRecipes], [plan_step{description: Desc, tools: Tools, reasoning: Reasoning, recipe: Recipe}|RestSteps]) :-
209
+ normalize_tools_spec(ToolSpec, Tools),
210
+ normalize_reasoning_spec(ReasoningSpec, Reasoning),
211
+ normalize_recipe_spec(RecipeSpec, Recipe),
212
+ build_plan_steps_from_specs(RestDesc, RestTools, RestReasoning, RestRecipes, RestSteps).
213
+
214
+ normalize_tools_spec(Raw, Tools) :-
215
+ format(string(Text), "~w", [Raw]),
216
+ string_lower(Text, Lower),
217
+ ( Lower = "all"
218
+ -> default_plan_tools(Tools)
219
+ ; split_string(Text, ",", " []\t\n", Parts0),
220
+ include(non_empty_string, Parts0, Parts),
221
+ findall(ToolAtom,
222
+ ( member(Part, Parts),
223
+ tool_name_string_to_atom(Part, ToolAtom),
224
+ valid_plan_tool(ToolAtom)
225
+ ),
226
+ ValidTools),
227
+ ( ValidTools = []
228
+ -> default_plan_tools(Tools)
229
+ ; Tools = ValidTools
230
+ )
204
231
  ).
205
232
 
206
- %% parse_plan_json(+Json, -PlanSteps)
207
- parse_plan_json(Json, PlanSteps) :-
208
- atom_json_dict(Json, JsonArray, []),
209
- is_list(JsonArray),
210
- maplist(parse_plan_step, JsonArray, PlanSteps).
211
-
212
- parse_plan_step(Dict, plan_step{description: Desc, tools: Tools, reasoning: Reasoning, recipe: Recipe}) :-
213
- Desc = Dict.get(description),
214
- ( Desc = null -> throw(parse_error) ; true ),
215
- ToolsRaw = Dict.get(tools),
216
- ( is_list(ToolsRaw)
217
- -> findall(TA, (member(TR, ToolsRaw), tool_name_to_atom(TR, TA), valid_plan_tool(TA)), ValidTools),
218
- ( ValidTools = [] -> Tools = all ; Tools = ValidTools )
219
- ; Tools = all ),
220
- ReasoningRaw = Dict.get(reasoning),
221
- ( atom(ReasoningRaw) -> atom_string(ReasoningRaw, Reasoning)
222
- ; string(ReasoningRaw) -> Reasoning = ReasoningRaw
223
- ; Reasoning = "none"
224
- ),
225
- RecipeRaw = Dict.get(recipe),
226
- ( ( RecipeRaw = null ; var(RecipeRaw) )
233
+ normalize_reasoning_spec(Raw, Reasoning) :-
234
+ format(string(Text), "~w", [Raw]),
235
+ string_lower(Text, Lower),
236
+ normalize_reasoning_label(Lower, Reasoning).
237
+
238
+ normalize_reasoning_label("high", "high").
239
+ normalize_reasoning_label("medium", "medium").
240
+ normalize_reasoning_label("low", "low").
241
+ normalize_reasoning_label("none", "none").
242
+ normalize_reasoning_label(_, "none").
243
+
244
+ normalize_recipe_spec(Raw, Recipe) :-
245
+ format(string(Text0), "~w", [Raw]),
246
+ normalize_space(string(Text), Text0),
247
+ string_lower(Text, Lower),
248
+ ( Lower = ""
227
249
  -> Recipe = "none"
228
- ; atom(RecipeRaw)
229
- -> atom_string(RecipeRaw, Recipe)
230
- ; string(RecipeRaw)
231
- -> Recipe = RecipeRaw
232
- ; Recipe = "none"
250
+ ; Lower = "none"
251
+ -> Recipe = "none"
252
+ ; Recipe = Text
233
253
  ).
234
254
 
255
+ tool_name_string_to_atom(Text, Atom) :-
256
+ string_lower(Text, Lower),
257
+ atom_string(Atom, Lower).
258
+
259
+ non_empty_string(Text) :-
260
+ Text \= "".
261
+
235
262
  %% fallback_plan_steps_from_strategy(+Strategy, -Steps)
236
- fallback_plan_steps_from_strategy(Strategy, [plan_step{description: Strategy, tools: all, reasoning: "none", recipe: "none"}]).
263
+ fallback_plan_steps_from_strategy(Strategy, [plan_step{description: Strategy, tools: Tools, reasoning: "none", recipe: "none"}]) :-
264
+ default_plan_tools(Tools).
237
265
 
238
266
  %% assemble_multi_strategy_dml(+StrategyPlans, +CodingWorkflowRecipe, -PlanDml)
239
267
  assemble_multi_strategy_dml(StrategyPlans, CodingWorkflowRecipe, PlanDml) :-
@@ -271,10 +299,7 @@ build_single_task_line(Step, Line) :-
271
299
  Reasoning = Step.reasoning,
272
300
  Recipe = Step.recipe,
273
301
 
274
- ( Tools == all
275
- -> format(string(InnerTask), "task(~q)", [Desc])
276
- ; format(string(InnerTask), "with_tools(~w, task(~q))", [Tools, Desc])
277
- ),
302
+ format(string(InnerTask), "with_tools(~w, task(~q))", [Tools, Desc]),
278
303
 
279
304
  ( Reasoning \= "none"
280
305
  -> format(string(WithReasoning), "with_reasoning(~n ~w~n , ~w)", [InnerTask, Reasoning])
@@ -172,16 +172,17 @@ Note: There is no separate save_file or read_file tool. File operations go throu
172
172
 
173
173
  {ReasoningNote}
174
174
 
175
- Also specify a recipe query for each task if relevant (null otherwise). Use natural language queries like 'testing patterns' or 'codebase analysis'.
175
+ Also specify a recipe query for each task if relevant (NONE otherwise). Use natural language queries like 'testing patterns' or 'codebase analysis'.
176
176
 
177
- Return a JSON array of objects with these fields:
178
- - \"description\": the task description (copy from the plan above)
179
- - \"tools\": array of tool name strings from the available tools list above
180
- - \"reasoning\": one of \"none\", \"low\", \"medium\", \"high\"
181
- - \"recipe\": a recipe query string or null
177
+ Return three ordered lists aligned 1:1 with Tasks:
178
+ - ToolSpecs: each item must be either ALL or a comma-separated list of exact tool names from the available tools list above.
179
+ - ReasoningSpecs: each item must be exactly one of none, low, medium, high.
180
+ - RecipeSpecs: each item must be either NONE or a recipe query string.
182
181
 
183
- Return ONLY the JSON array, no other text.", string(AssignmentsJson)),
184
- ( catch(parse_plan_json(AssignmentsJson, PlanSteps), _, fail)
182
+ Store the ordered tool specs in ToolSpecs.
183
+ Store the ordered reasoning specs in ReasoningSpecs.
184
+ Store the ordered recipe specs in RecipeSpecs.", list(string(ToolSpecs)), list(string(ReasoningSpecs)), list(string(RecipeSpecs))),
185
+ ( build_plan_steps_from_specs(PlanTasks, ToolSpecs, ReasoningSpecs, RecipeSpecs, PlanSteps)
185
186
  -> true
186
187
  ; % Fallback: no tool/reasoning/recipe assignments
187
188
  fallback_plan_steps(PlanTasks, PlanSteps)
@@ -199,48 +200,68 @@ valid_plan_tool(create_new_skill).
199
200
  valid_plan_tool(ask_user).
200
201
  valid_plan_tool(inform_user).
201
202
 
202
- %% tool_name_to_atom(+Raw, -Atom)
203
- %% Converts a JSON string or atom to a Prolog atom
204
- tool_name_to_atom(Raw, Atom) :-
205
- ( atom(Raw) -> Atom = Raw
206
- ; string(Raw) -> atom_string(Atom, Raw)
207
- ; Atom = Raw
203
+ default_plan_tools([run_bash, run_skill, consult_recipes, search_web, search_news, fetch_url, download_file, create_new_skill, ask_user, inform_user]).
204
+
205
+ build_plan_steps_from_specs([], [], [], [], []).
206
+ build_plan_steps_from_specs([Desc|RestDesc], [ToolSpec|RestTools], [ReasoningSpec|RestReasoning], [RecipeSpec|RestRecipes], [plan_step{description: Desc, tools: Tools, reasoning: Reasoning, recipe: Recipe}|RestSteps]) :-
207
+ normalize_tools_spec(ToolSpec, Tools),
208
+ normalize_reasoning_spec(ReasoningSpec, Reasoning),
209
+ normalize_recipe_spec(RecipeSpec, Recipe),
210
+ build_plan_steps_from_specs(RestDesc, RestTools, RestReasoning, RestRecipes, RestSteps).
211
+
212
+ normalize_tools_spec(Raw, Tools) :-
213
+ format(string(Text), "~w", [Raw]),
214
+ string_lower(Text, Lower),
215
+ ( Lower = "all"
216
+ -> default_plan_tools(Tools)
217
+ ; split_string(Text, ",", " []\t\n", Parts0),
218
+ include(non_empty_string, Parts0, Parts),
219
+ findall(ToolAtom,
220
+ ( member(Part, Parts),
221
+ tool_name_string_to_atom(Part, ToolAtom),
222
+ valid_plan_tool(ToolAtom)
223
+ ),
224
+ ValidTools),
225
+ ( ValidTools = []
226
+ -> default_plan_tools(Tools)
227
+ ; Tools = ValidTools
228
+ )
208
229
  ).
209
230
 
210
- %% parse_plan_json(+Json, -PlanSteps)
211
- parse_plan_json(Json, PlanSteps) :-
212
- atom_json_dict(Json, JsonArray, []),
213
- is_list(JsonArray),
214
- maplist(parse_plan_step, JsonArray, PlanSteps).
215
-
216
- parse_plan_step(Dict, plan_step{description: Desc, tools: Tools, reasoning: Reasoning, recipe: Recipe}) :-
217
- Desc = Dict.get(description),
218
- ( Desc = null -> throw(parse_error) ; true ),
219
- ToolsRaw = Dict.get(tools),
220
- ( is_list(ToolsRaw)
221
- -> % Convert each tool name to atom, filter to valid tools
222
- findall(TA, (member(TR, ToolsRaw), tool_name_to_atom(TR, TA), valid_plan_tool(TA)), ValidTools),
223
- ( ValidTools = [] -> Tools = all ; Tools = ValidTools )
224
- ; Tools = all ),
225
- ReasoningRaw = Dict.get(reasoning),
226
- ( atom(ReasoningRaw) -> atom_string(ReasoningRaw, Reasoning)
227
- ; string(ReasoningRaw) -> Reasoning = ReasoningRaw
228
- ; Reasoning = "none"
229
- ),
230
- RecipeRaw = Dict.get(recipe),
231
- ( ( RecipeRaw = null ; var(RecipeRaw) )
231
+ normalize_reasoning_spec(Raw, Reasoning) :-
232
+ format(string(Text), "~w", [Raw]),
233
+ string_lower(Text, Lower),
234
+ normalize_reasoning_label(Lower, Reasoning).
235
+
236
+ normalize_reasoning_label("high", "high").
237
+ normalize_reasoning_label("medium", "medium").
238
+ normalize_reasoning_label("low", "low").
239
+ normalize_reasoning_label("none", "none").
240
+ normalize_reasoning_label(_, "none").
241
+
242
+ normalize_recipe_spec(Raw, Recipe) :-
243
+ format(string(Text0), "~w", [Raw]),
244
+ normalize_space(string(Text), Text0),
245
+ string_lower(Text, Lower),
246
+ ( Lower = ""
247
+ -> Recipe = "none"
248
+ ; Lower = "none"
232
249
  -> Recipe = "none"
233
- ; atom(RecipeRaw)
234
- -> atom_string(RecipeRaw, Recipe)
235
- ; string(RecipeRaw)
236
- -> Recipe = RecipeRaw
237
- ; Recipe = "none"
250
+ ; Recipe = Text
238
251
  ).
239
252
 
253
+ tool_name_string_to_atom(Text, Atom) :-
254
+ string_lower(Text, Lower),
255
+ atom_string(Atom, Lower).
256
+
257
+ non_empty_string(Text) :-
258
+ Text \= "".
259
+
240
260
  %% fallback_plan_steps(+PlanTasks, -PlanSteps)
241
261
  %% When JSON parsing fails, create steps with all tools and no reasoning/recipe.
242
262
  fallback_plan_steps([], []).
243
- fallback_plan_steps([Desc|Rest], [plan_step{description: Desc, tools: all, reasoning: "none", recipe: "none"}|RestSteps]) :-
263
+ fallback_plan_steps([Desc|Rest], [plan_step{description: Desc, tools: Tools, reasoning: "none", recipe: "none"}|RestSteps]) :-
264
+ default_plan_tools(Tools),
244
265
  fallback_plan_steps(Rest, RestSteps).
245
266
 
246
267
  assemble_plan_dml(PlanSystemPrompt, PlanSteps, PlanDml) :-
@@ -289,10 +310,7 @@ build_step_review_lines([Step|RestSteps], StepNumber, StepLines) :-
289
310
  Desc = Step.description,
290
311
  Tools = Step.tools,
291
312
  Reasoning = Step.reasoning,
292
- ( Tools == all
293
- -> format(string(CurrentStep), "~w. ~w [all tools, ~w]\n", [StepNumber, Desc, Reasoning])
294
- ; format(string(CurrentStep), "~w. ~w [tools: ~w, ~w]\n", [StepNumber, Desc, Tools, Reasoning])
295
- ),
313
+ format(string(CurrentStep), "~w. ~w [tools: ~w, ~w]\n", [StepNumber, Desc, Tools, Reasoning]),
296
314
  NextStepNumber is StepNumber + 1,
297
315
  build_step_review_lines(RestSteps, NextStepNumber, RestStepLines),
298
316
  string_concat(CurrentStep, RestStepLines, StepLines).
@@ -309,19 +327,13 @@ build_single_task_line(Step, Line) :-
309
327
  Reasoning = Step.reasoning,
310
328
  Recipe = Step.recipe,
311
329
 
312
- % Build inner task with tool scoping
313
- ( Tools == all
314
- -> format(string(InnerTask), "task(~q)", [Desc])
315
- ; format(string(InnerTask), "with_tools(~w, task(~q))", [Tools, Desc])
316
- ),
330
+ format(string(InnerTask), "with_tools(~w, task(~q))", [Tools, Desc]),
317
331
 
318
- % Wrap in with_reasoning if reasoning != none
319
332
  ( Reasoning \= "none"
320
333
  -> format(string(WithReasoning), "with_reasoning(~n ~w~n , ~w)", [InnerTask, Reasoning])
321
334
  ; WithReasoning = InnerTask
322
335
  ),
323
336
 
324
- % Wrap in with_recipe if recipe != none
325
337
  ( Recipe \= "none"
326
338
  -> format(string(Line), " with_recipe(~n ~w~n , '~w'),~n", [WithReasoning, Recipe])
327
339
  ; format(string(Line), " ~w,~n", [WithReasoning])
@@ -93,6 +93,13 @@ generate_all_strategy_tasks(Request, [Strategy|RestStrategies], [plan{strategy:
93
93
 
94
94
  %% generate_strategy_tasks(+Request, +Strategy, -Steps)
95
95
  generate_strategy_tasks(Request, Strategy, Steps) :-
96
+ ( param(model_info, ModelInfo)
97
+ -> ( get_dict(reasoning, ModelInfo, R), R == true
98
+ -> ReasoningNote = "The execution model supports reasoning. Assign reasoning effort per task: none, low, medium, or high."
99
+ ; ReasoningNote = "The execution model does not support reasoning. Set reasoning to 'none' for all tasks."
100
+ )
101
+ ; ReasoningNote = "Set reasoning to 'none' for all tasks."
102
+ ),
96
103
  task("List 3 to 7 focused execution tasks for this security analysis strategy.
97
104
 
98
105
  Target: {Request}
@@ -100,13 +107,101 @@ Strategy: {Strategy}
100
107
 
101
108
  Each task should be one concrete analysis step. Be specific about what to look for and which files to examine.
102
109
 
103
- Store the list of task descriptions in TaskDescriptions.", list(string(TaskDescriptions))),
104
- build_steps_from_descriptions(TaskDescriptions, Strategy, Steps).
110
+ Available tools (use ONLY these exact names):
111
+ - consult_recipes: Search recipe guidance and conventions
112
+ - search_web: Search the web for advisories, docs, and references
113
+ - search_news: Search recent news for relevant incidents or advisories
114
+ - fetch_url: Fetch a specific advisory or documentation page
115
+ - run_bash: Run grep, find, test, and scanner commands in the workspace
116
+ - ask_user: Ask the user to narrow scope or clarify assumptions
117
+ - inform_user: Send a status update
118
+
119
+ {ReasoningNote}
120
+
121
+ Also specify a recipe query for each task if relevant (NONE otherwise).
122
+
123
+ Return four ordered lists aligned 1:1:
124
+ - TaskDescriptions: plain task descriptions.
125
+ - ToolSpecs: each item must be either ALL or a comma-separated list of exact tool names from the available tools list above.
126
+ - ReasoningSpecs: each item must be exactly one of none, low, medium, high.
127
+ - RecipeSpecs: each item must be either NONE or a recipe query string.
128
+
129
+ Store the ordered task descriptions in TaskDescriptions.
130
+ Store the ordered tool specs in ToolSpecs.
131
+ Store the ordered reasoning specs in ReasoningSpecs.
132
+ Store the ordered recipe specs in RecipeSpecs.", list(string(TaskDescriptions)), list(string(ToolSpecs)), list(string(ReasoningSpecs)), list(string(RecipeSpecs))),
133
+ ( build_steps_from_specs(TaskDescriptions, ToolSpecs, ReasoningSpecs, RecipeSpecs, Steps)
134
+ -> true
135
+ ; fallback_plan_steps_from_strategy(Strategy, Steps)
136
+ ).
137
+
138
+ valid_plan_tool(consult_recipes).
139
+ valid_plan_tool(search_web).
140
+ valid_plan_tool(search_news).
141
+ valid_plan_tool(fetch_url).
142
+ valid_plan_tool(run_bash).
143
+ valid_plan_tool(ask_user).
144
+ valid_plan_tool(inform_user).
145
+
146
+ default_plan_tools([consult_recipes, search_web, search_news, fetch_url, run_bash, ask_user, inform_user]).
147
+
148
+ build_steps_from_specs([], [], [], [], []).
149
+ build_steps_from_specs([Desc|RestDesc], [ToolSpec|RestTools], [ReasoningSpec|RestReasoning], [RecipeSpec|RestRecipes], [plan_step{description: Desc, tools: Tools, reasoning: Reasoning, recipe: Recipe}|RestSteps]) :-
150
+ normalize_tools_spec(ToolSpec, Tools),
151
+ normalize_reasoning_spec(ReasoningSpec, Reasoning),
152
+ normalize_recipe_spec(RecipeSpec, Recipe),
153
+ build_steps_from_specs(RestDesc, RestTools, RestReasoning, RestRecipes, RestSteps).
154
+
155
+ normalize_tools_spec(Raw, Tools) :-
156
+ format(string(Text), "~w", [Raw]),
157
+ string_lower(Text, Lower),
158
+ ( Lower = "all"
159
+ -> default_plan_tools(Tools)
160
+ ; split_string(Text, ",", " []\t\n", Parts0),
161
+ include(non_empty_string, Parts0, Parts),
162
+ findall(ToolAtom,
163
+ ( member(Part, Parts),
164
+ tool_name_string_to_atom(Part, ToolAtom),
165
+ valid_plan_tool(ToolAtom)
166
+ ),
167
+ ValidTools),
168
+ ( ValidTools = []
169
+ -> default_plan_tools(Tools)
170
+ ; Tools = ValidTools
171
+ )
172
+ ).
173
+
174
+ normalize_reasoning_spec(Raw, Reasoning) :-
175
+ format(string(Text), "~w", [Raw]),
176
+ string_lower(Text, Lower),
177
+ normalize_reasoning_label(Lower, Reasoning).
178
+
179
+ normalize_reasoning_label("high", "high").
180
+ normalize_reasoning_label("medium", "medium").
181
+ normalize_reasoning_label("low", "low").
182
+ normalize_reasoning_label("none", "none").
183
+ normalize_reasoning_label(_, "none").
184
+
185
+ normalize_recipe_spec(Raw, Recipe) :-
186
+ format(string(Text0), "~w", [Raw]),
187
+ normalize_space(string(Text), Text0),
188
+ string_lower(Text, Lower),
189
+ ( Lower = ""
190
+ -> Recipe = "none"
191
+ ; Lower = "none"
192
+ -> Recipe = "none"
193
+ ; Recipe = Text
194
+ ).
195
+
196
+ tool_name_string_to_atom(Text, Atom) :-
197
+ string_lower(Text, Lower),
198
+ atom_string(Atom, Lower).
105
199
 
106
- %% build_steps_from_descriptions(+Descriptions, +Strategy, -Steps)
107
- build_steps_from_descriptions([], _, []).
108
- build_steps_from_descriptions([Desc|Rest], Strategy, [plan_step{description: Desc, tools: all, reasoning: "none", recipe: "none"}|RestSteps]) :-
109
- build_steps_from_descriptions(Rest, Strategy, RestSteps).
200
+ non_empty_string(Text) :-
201
+ Text \= "".
202
+
203
+ fallback_plan_steps_from_strategy(Strategy, [plan_step{description: Strategy, tools: Tools, reasoning: "none", recipe: "none"}]) :-
204
+ default_plan_tools(Tools).
110
205
 
111
206
  %% assemble_multi_strategy_dml(+StrategyPlans, -PlanDml)
112
207
  assemble_multi_strategy_dml(StrategyPlans, PlanDml) :-
@@ -156,7 +251,19 @@ build_single_task_line(Step, Num, PrevSum, Line) :-
156
251
  Desc = Step.description,
157
252
  format(string(VarName), "Sum~w", [Num]),
158
253
  format(string(DescWithCtx), "~w. Store your findings summary in ~w.", [Desc, VarName]),
159
- format(string(Line), " task(~q, string(~w)),~n", [DescWithCtx, VarName]).
254
+ Tools = Step.tools,
255
+ Reasoning = Step.reasoning,
256
+ Recipe = Step.recipe,
257
+ format(string(BaseTask), "task(~q, string(~w))", [DescWithCtx, VarName]),
258
+ format(string(WithTools), "with_tools(~w, ~w)", [Tools, BaseTask]),
259
+ ( Reasoning \= "none"
260
+ -> format(string(WithReasoning), "with_reasoning(~n ~w~n , ~w)", [WithTools, Reasoning])
261
+ ; WithReasoning = WithTools
262
+ ),
263
+ ( Recipe \= "none"
264
+ -> format(string(Line), " with_recipe(~n ~w~n , '~w'),~n", [WithReasoning, Recipe])
265
+ ; format(string(Line), " ~w,~n", [WithReasoning])
266
+ ).
160
267
 
161
268
  %% build_review_message(+FilePath, +StrategyPlans, -ReviewMessage)
162
269
  build_review_message(FilePath, StrategyPlans, ReviewMessage) :-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepclause-sdk",
3
- "version": "0.0.85",
3
+ "version": "0.0.86",
4
4
  "description": "DeepClause CLI Tool, TUI and Typescript SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -779,9 +779,9 @@ get_reasoning_effort(State, Effort) :-
779
779
  %% Recipe Context Helpers
780
780
  %% ============================================================
781
781
 
782
- %% load_recipe_content(+Query, -Content)
783
- load_recipe_content(Query, RecipeContent) :-
784
- exec(consult_recipes(query: Query, max_results: 1), Result),
782
+ %% load_recipe_content(+Query, +StateIn, -StateOut, -Content)
783
+ load_recipe_content(Query, StateIn, StateOut, RecipeContent) :-
784
+ mi_call(exec(consult_recipes(query: Query, max_results: 1), Result), StateIn, StateOut),
785
785
  get_dict(matches, Result, Matches),
786
786
  ( Matches = [Match|_]
787
787
  -> get_dict(content, Match, RecipeContent)
@@ -1484,8 +1484,8 @@ mi_call(with_reasoning(Goal, Effort), StateIn, StateOut) :-
1484
1484
  %% Run Goal with a recipe loaded as transient context (not persisted to memory).
1485
1485
  mi_call(with_recipe(Goal, Query), StateIn, StateOut) :-
1486
1486
  !,
1487
- load_recipe_content(Query, RecipeContent),
1488
- set_recipe_context(StateIn, RecipeContent, ScopedState),
1487
+ load_recipe_content(Query, StateIn, StateAfterRecipeLoad, RecipeContent),
1488
+ set_recipe_context(StateAfterRecipeLoad, RecipeContent, ScopedState),
1489
1489
  mi_call(Goal, ScopedState, StateWithRecipe),
1490
1490
  clear_recipe_context(StateWithRecipe, StateOut).
1491
1491