deepclause-sdk 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -6
- package/dist/cli/config.d.ts +2 -2
- package/dist/cli/repl.d.ts +55 -4
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +675 -52
- package/dist/cli/repl.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/prolog-src/deepclause_mi.pl +516 -2
- package/dist/repl/backend.d.ts +9 -0
- package/dist/repl/backend.d.ts.map +1 -1
- package/dist/repl/backend.js +62 -5
- package/dist/repl/backend.js.map +1 -1
- package/dist/repl/harness-tools.d.ts +36 -0
- package/dist/repl/harness-tools.d.ts.map +1 -1
- package/dist/repl/harness-tools.js +173 -0
- package/dist/repl/harness-tools.js.map +1 -1
- package/dist/repl/history.d.ts +29 -0
- package/dist/repl/history.d.ts.map +1 -1
- package/dist/repl/history.js +71 -0
- package/dist/repl/history.js.map +1 -1
- package/dist/repl/index.d.ts +6 -0
- package/dist/repl/index.d.ts.map +1 -1
- package/dist/repl/index.js +9 -1
- package/dist/repl/index.js.map +1 -1
- package/dist/repl/picker.d.ts +3 -0
- package/dist/repl/picker.d.ts.map +1 -1
- package/dist/repl/picker.js +132 -0
- package/dist/repl/picker.js.map +1 -1
- package/dist/repl/process-backend.d.ts +31 -0
- package/dist/repl/process-backend.d.ts.map +1 -0
- package/dist/repl/process-backend.js +10 -0
- package/dist/repl/process-backend.js.map +1 -0
- package/dist/repl/process-executor.d.ts +67 -0
- package/dist/repl/process-executor.d.ts.map +1 -0
- package/dist/repl/process-executor.js +371 -0
- package/dist/repl/process-executor.js.map +1 -0
- package/dist/repl/process-worker.d.ts +10 -0
- package/dist/repl/process-worker.d.ts.map +1 -0
- package/dist/repl/process-worker.js +210 -0
- package/dist/repl/process-worker.js.map +1 -0
- package/dist/repl/processes.d.ts +282 -0
- package/dist/repl/processes.d.ts.map +1 -0
- package/dist/repl/processes.js +557 -0
- package/dist/repl/processes.js.map +1 -0
- package/dist/repl/render.d.ts +52 -2
- package/dist/repl/render.d.ts.map +1 -1
- package/dist/repl/render.js +52 -17
- package/dist/repl/render.js.map +1 -1
- package/dist/repl/session.d.ts +135 -3
- package/dist/repl/session.d.ts.map +1 -1
- package/dist/repl/session.js +413 -4
- package/dist/repl/session.js.map +1 -1
- package/dist/repl/status.d.ts +3 -1
- package/dist/repl/status.d.ts.map +1 -1
- package/dist/repl/status.js +4 -0
- package/dist/repl/status.js.map +1 -1
- package/dist/repl/tui/autocomplete.d.ts +19 -0
- package/dist/repl/tui/autocomplete.d.ts.map +1 -0
- package/dist/repl/tui/autocomplete.js +48 -0
- package/dist/repl/tui/autocomplete.js.map +1 -0
- package/dist/repl/tui/document.d.ts +51 -0
- package/dist/repl/tui/document.d.ts.map +1 -0
- package/dist/repl/tui/document.js +160 -0
- package/dist/repl/tui/document.js.map +1 -0
- package/dist/repl/tui/harness-view.d.ts +102 -0
- package/dist/repl/tui/harness-view.d.ts.map +1 -0
- package/dist/repl/tui/harness-view.js +323 -0
- package/dist/repl/tui/harness-view.js.map +1 -0
- package/dist/repl/tui/picker.d.ts +31 -0
- package/dist/repl/tui/picker.d.ts.map +1 -0
- package/dist/repl/tui/picker.js +43 -0
- package/dist/repl/tui/picker.js.map +1 -0
- package/dist/repl/tui/renderer.d.ts +98 -0
- package/dist/repl/tui/renderer.d.ts.map +1 -0
- package/dist/repl/tui/renderer.js +289 -0
- package/dist/repl/tui/renderer.js.map +1 -0
- package/dist/repl/tui/services-panel.d.ts +35 -0
- package/dist/repl/tui/services-panel.d.ts.map +1 -0
- package/dist/repl/tui/services-panel.js +108 -0
- package/dist/repl/tui/services-panel.js.map +1 -0
- package/dist/repl/tui/status-bar.d.ts +6 -2
- package/dist/repl/tui/status-bar.d.ts.map +1 -1
- package/dist/repl/tui/status-bar.js +82 -24
- package/dist/repl/tui/status-bar.js.map +1 -1
- package/dist/repl/tui/terminal.d.ts +28 -0
- package/dist/repl/tui/terminal.d.ts.map +1 -0
- package/dist/repl/tui/terminal.js +94 -0
- package/dist/repl/tui/terminal.js.map +1 -0
- package/dist/repl/tui/theme.d.ts +60 -0
- package/dist/repl/tui/theme.d.ts.map +1 -1
- package/dist/repl/tui/theme.js +142 -0
- package/dist/repl/tui/theme.js.map +1 -1
- package/dist/repl/tui/tool-pane.d.ts +68 -0
- package/dist/repl/tui/tool-pane.d.ts.map +1 -0
- package/dist/repl/tui/tool-pane.js +261 -0
- package/dist/repl/tui/tool-pane.js.map +1 -0
- package/dist/repl/tui/working-line.d.ts +23 -0
- package/dist/repl/tui/working-line.d.ts.map +1 -0
- package/dist/repl/tui/working-line.js +58 -0
- package/dist/repl/tui/working-line.js.map +1 -0
- package/dist/repl/worker-host.d.ts +80 -0
- package/dist/repl/worker-host.d.ts.map +1 -0
- package/dist/repl/worker-host.js +305 -0
- package/dist/repl/worker-host.js.map +1 -0
- package/dist/repl/worker-protocol.d.ts +123 -0
- package/dist/repl/worker-protocol.d.ts.map +1 -0
- package/dist/repl/worker-protocol.js +9 -0
- package/dist/repl/worker-protocol.js.map +1 -0
- package/dist/runner.d.ts +24 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +47 -0
- package/dist/runner.js.map +1 -1
- package/dist/system/assets/docs/AGENT_PROMPT.md +193 -0
- package/dist/system/assets/docs/DML_AUTHORING.md +21 -0
- package/dist/system/assets/docs/DML_REFERENCE.md +145 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/prolog-src/deepclause_mi.pl +516 -2
|
@@ -148,6 +148,7 @@
|
|
|
148
148
|
:- dynamic session_trace_log/2. % session_trace_log(SessionId, TraceLog) - accumulated trace entries
|
|
149
149
|
:- dynamic session_trace_enabled/2. % session_trace_enabled(SessionId, true/false)
|
|
150
150
|
:- dynamic session_pending_signal/2. % session_pending_signal(SessionId, Signal) - fallback for engine_fetch
|
|
151
|
+
:- dynamic session_proc_result/3. % session_proc_result(SessionId, Key, Value) - process primitive results
|
|
151
152
|
:- dynamic session_user_input/2. % session_user_input(SessionId, Input) - for ask_user tool
|
|
152
153
|
:- dynamic session_input_cancelled/1. % session_input_cancelled(SessionId) - input/2 should fail (non-interactive)
|
|
153
154
|
|
|
@@ -957,7 +958,11 @@ step_engine_handle(SessionId, Engine, Status, Content, Payload) :-
|
|
|
957
958
|
)
|
|
958
959
|
),
|
|
959
960
|
Error,
|
|
960
|
-
(
|
|
961
|
+
( Error = process_exit(_)
|
|
962
|
+
-> Status = finished,
|
|
963
|
+
Content = '',
|
|
964
|
+
Payload = none
|
|
965
|
+
; format(atom(ErrMsg), 'Engine error: ~w', [Error]),
|
|
961
966
|
Status = error,
|
|
962
967
|
Content = ErrMsg,
|
|
963
968
|
( session_trace_enabled(SessionId, true),
|
|
@@ -1304,6 +1309,13 @@ repl_listing_output(SessionId, Filter) :-
|
|
|
1304
1309
|
)
|
|
1305
1310
|
).
|
|
1306
1311
|
|
|
1312
|
+
%% A filter either names a predicate (`name/arity`), names a prefix, or is `all`.
|
|
1313
|
+
%% Anything else matches **nothing**.
|
|
1314
|
+
%%
|
|
1315
|
+
%% There used to be a final `repl_listing_match(_, _, _)` catch-all, which turned any
|
|
1316
|
+
%% filter it did not understand into "the whole module" — silently. `listing('alpha/1')`
|
|
1317
|
+
%% therefore listed every predicate, so the side view's drill-down showed the module
|
|
1318
|
+
%% instead of the predicate under the cursor.
|
|
1307
1319
|
repl_listing_match(all, _, _) :- !.
|
|
1308
1320
|
repl_listing_match(Name/Arity, Name, Arity) :- !.
|
|
1309
1321
|
repl_listing_match(Filter, Name, _) :-
|
|
@@ -1312,7 +1324,8 @@ repl_listing_match(Filter, Name, _) :-
|
|
|
1312
1324
|
( sub_atom(Name, 0, _, _, Filter)
|
|
1313
1325
|
; sub_atom(Filter, 0, _, _, Name)
|
|
1314
1326
|
).
|
|
1315
|
-
repl_listing_match(_, _, _)
|
|
1327
|
+
repl_listing_match(_, _, _) :-
|
|
1328
|
+
fail.
|
|
1316
1329
|
|
|
1317
1330
|
%% repl_user_predicate(+SessionId, +Name, +Arity)
|
|
1318
1331
|
%% Excludes reserved and internal predicates from listing/export.
|
|
@@ -2308,6 +2321,46 @@ repl_rollback(SessionId, Source, Result) :-
|
|
|
2308
2321
|
format(atom(Result), 'error(~w)', [RollbackError])
|
|
2309
2322
|
).
|
|
2310
2323
|
|
|
2324
|
+
%% repl_harness_view(+SessionId, -Rows)
|
|
2325
|
+
%% One row per predicate of the harness, for the live side view:
|
|
2326
|
+
%% "Name/Arity|ClauseCount|flag,flag"
|
|
2327
|
+
%% Text rather than terms, so the host does not have to decode compound terms through
|
|
2328
|
+
%% the bridge — the view needs identity (to diff) and a little detail, not structure.
|
|
2329
|
+
repl_harness_view(SessionId, Rows) :-
|
|
2330
|
+
repl_user_predicates(SessionId, Preds),
|
|
2331
|
+
findall(Row,
|
|
2332
|
+
( member(Name/Arity, Preds),
|
|
2333
|
+
repl_predicate_clause_count(SessionId, Name, Arity, Clauses),
|
|
2334
|
+
repl_harness_flags(SessionId, Name, Arity, Flags),
|
|
2335
|
+
( Flags == []
|
|
2336
|
+
-> FlagText = ""
|
|
2337
|
+
; atomic_list_concat(Flags, ',', FlagText)
|
|
2338
|
+
),
|
|
2339
|
+
format(atom(Row), "~w/~w|~w|~w", [Name, Arity, Clauses, FlagText])
|
|
2340
|
+
),
|
|
2341
|
+
Rows).
|
|
2342
|
+
|
|
2343
|
+
repl_predicate_clause_count(SessionId, Name, Arity, Count) :-
|
|
2344
|
+
functor(Head, Name, Arity),
|
|
2345
|
+
findall(x, clause(SessionId:Head, _), All),
|
|
2346
|
+
length(All, Count).
|
|
2347
|
+
|
|
2348
|
+
repl_harness_flags(SessionId, Name, Arity, Flags) :-
|
|
2349
|
+
findall(Flag,
|
|
2350
|
+
( member(Flag, [entry, tool, doc, touched]),
|
|
2351
|
+
repl_harness_flag(SessionId, Name, Arity, Flag)
|
|
2352
|
+
),
|
|
2353
|
+
Flags).
|
|
2354
|
+
|
|
2355
|
+
repl_harness_flag(_SessionId, agent_main, _Arity, entry).
|
|
2356
|
+
repl_harness_flag(SessionId, Name, _Arity, tool) :-
|
|
2357
|
+
session_user_tools(SessionId, Name).
|
|
2358
|
+
repl_harness_flag(SessionId, Name, Arity, doc) :-
|
|
2359
|
+
current_predicate(SessionId:doc/2),
|
|
2360
|
+
catch(SessionId:doc(Name/Arity, _), _, fail).
|
|
2361
|
+
repl_harness_flag(SessionId, Name, Arity, touched) :-
|
|
2362
|
+
session_edit_touched(SessionId, Name/Arity).
|
|
2363
|
+
|
|
2311
2364
|
%% repl_user_predicates(+SessionId, -Preds)
|
|
2312
2365
|
%% Sorted Name/Arity list of the harness's own predicates.
|
|
2313
2366
|
repl_user_predicates(SessionId, Preds) :-
|
|
@@ -2414,6 +2467,9 @@ repl_validate_docs(SessionId, Warnings) :-
|
|
|
2414
2467
|
list_to_set(Raw, Warnings).
|
|
2415
2468
|
|
|
2416
2469
|
doc_without_clauses(SessionId, Warning) :-
|
|
2470
|
+
% A harness with no `doc/2` at all would otherwise make this call an
|
|
2471
|
+
% undefined-procedure warning (`Unknown procedure: repl_x:doc/2`).
|
|
2472
|
+
current_predicate(SessionId:doc/2),
|
|
2417
2473
|
SessionId:doc(Name/Arity, _),
|
|
2418
2474
|
( \+ current_predicate(SessionId:Name/Arity)
|
|
2419
2475
|
; functor(Head, Name, Arity),
|
|
@@ -2922,6 +2978,25 @@ process_engine_result(request_agent_loop(Desc, Vars, Tools, Memory), request_age
|
|
|
2922
2978
|
payload{taskDescription: Desc, outputVars: Vars, userTools: Tools, memory: Memory, toolScope: none, reasoningEffort: none, recipeContext: ""}) :- !.
|
|
2923
2979
|
process_engine_result(request_exec(Tool, Args), request_exec, '',
|
|
2924
2980
|
payload{toolName: Tool, args: Args}) :- !.
|
|
2981
|
+
%% Process primitives (spawn/send/receive/...) are yielded to the host, which
|
|
2982
|
+
%% owns identity, mailboxes, links, monitors, and naming.
|
|
2983
|
+
process_engine_result(request_proc(Request), request_proc, '', Payload) :-
|
|
2984
|
+
proc_request_payload(Request, Payload).
|
|
2985
|
+
|
|
2986
|
+
%% proc_request_payload(+Request, -Payload)
|
|
2987
|
+
proc_request_payload(self, payload{op: self}) :- !.
|
|
2988
|
+
proc_request_payload(spawn(Goal), payload{op: spawn, goal: Goal}) :- !.
|
|
2989
|
+
proc_request_payload(spawn(Goal, Options), payload{op: spawn, goal: Goal, options: Options}) :- !.
|
|
2990
|
+
proc_request_payload(send(To, Message), payload{op: send, to: To, message: Message}) :- !.
|
|
2991
|
+
proc_request_payload(receive(Timeout), payload{op: receive, timeout: Timeout}) :- !.
|
|
2992
|
+
proc_request_payload(requeue(Message), payload{op: requeue, message: Message}) :- !.
|
|
2993
|
+
proc_request_payload(wait(Pid), payload{op: wait, pid: Pid}) :- !.
|
|
2994
|
+
proc_request_payload(exit(Reason), payload{op: exit, reason: Reason}) :- !.
|
|
2995
|
+
proc_request_payload(exit(Pid, Reason), payload{op: exit, pid: Pid, reason: Reason}) :- !.
|
|
2996
|
+
proc_request_payload(process_info(Pid), payload{op: process_info, pid: Pid}) :- !.
|
|
2997
|
+
proc_request_payload(register(Name, Pid), payload{op: register, name: Name, pid: Pid}) :- !.
|
|
2998
|
+
proc_request_payload(whereis(Name), payload{op: whereis, name: Name}) :- !.
|
|
2999
|
+
proc_request_payload(sleep(Milliseconds), payload{op: sleep, ms: Milliseconds}) :- !.
|
|
2925
3000
|
process_engine_result(request_sample_token(Prompt, Allowed, ModelSpec), request_sample_token, '',
|
|
2926
3001
|
payload{prompt: Prompt, allowedTokens: Allowed, modelSpec: ModelSpec}) :- !.
|
|
2927
3002
|
process_engine_result(request_sample_token(Prompt, Allowed), request_sample_token, '',
|
|
@@ -3010,6 +3085,13 @@ post_exec_result(SessionId, Status, Result) :-
|
|
|
3010
3085
|
assertz(session_exec_result(SessionId, result{status: Status, result: Result})),
|
|
3011
3086
|
post_signal_to_engine(SessionId, exec_done).
|
|
3012
3087
|
|
|
3088
|
+
%% post_proc_result(+SessionId, +Key, +Value)
|
|
3089
|
+
%% Reply to a process primitive (spawn/send/receive/...). Key names the result.
|
|
3090
|
+
post_proc_result(SessionId, Key, Value) :-
|
|
3091
|
+
retractall(session_proc_result(SessionId, Key, _)),
|
|
3092
|
+
assertz(session_proc_result(SessionId, Key, Value)),
|
|
3093
|
+
post_signal_to_engine(SessionId, proc_done).
|
|
3094
|
+
|
|
3013
3095
|
%% post_sample_token_result(+SessionId, +Status, +TokenOrError)
|
|
3014
3096
|
post_sample_token_result(SessionId, Status, TokenOrError) :-
|
|
3015
3097
|
retractall(session_sample_token_result(SessionId, _)),
|
|
@@ -3459,6 +3541,10 @@ process_tool_engine_result(request_agent_loop(Desc, Vars, Tools, Memory, ToolSco
|
|
|
3459
3541
|
%% Legacy 4-arg format (no tool scope)
|
|
3460
3542
|
process_tool_engine_result(request_agent_loop(Desc, Vars, Tools, Memory), request_agent_loop, '',
|
|
3461
3543
|
payload{taskDescription: Desc, outputVars: Vars, userTools: Tools, memory: Memory, toolScope: none, reasoningEffort: none, recipeContext: ""}) :- !.
|
|
3544
|
+
%% Process primitives (self/send/receive/spawn/...) reached inside a DML tool
|
|
3545
|
+
%% are yielded to the host exactly as in the main engine.
|
|
3546
|
+
process_tool_engine_result(request_proc(Request), request_proc, '', Payload) :-
|
|
3547
|
+
proc_request_payload(Request, Payload).
|
|
3462
3548
|
process_tool_engine_result(output(Text), output, Text, none) :- !.
|
|
3463
3549
|
process_tool_engine_result(log(Text), log, Text, none) :- !.
|
|
3464
3550
|
process_tool_engine_result(Other, error, Msg, none) :-
|
|
@@ -4144,6 +4230,410 @@ mi_call(exec(ToolCall, Output), StateIn, StateOut) :-
|
|
|
4144
4230
|
fail
|
|
4145
4231
|
).
|
|
4146
4232
|
|
|
4233
|
+
%% ============================================================
|
|
4234
|
+
%% Process Primitives (session-scoped subagents)
|
|
4235
|
+
%% ============================================================
|
|
4236
|
+
%% These yield to the TypeScript host, which owns process identity, mailboxes,
|
|
4237
|
+
%% links, monitors, and naming. See docs/DML_REPL_PROCESSES_SPEC.md.
|
|
4238
|
+
%% Goals and messages cross the boundary as canonical term strings, so a
|
|
4239
|
+
%% process never shares a variable with its spawner (invariant A).
|
|
4240
|
+
|
|
4241
|
+
%% mi_call(self(?Pid), +StateIn, -StateOut)
|
|
4242
|
+
mi_call(self(Pid), StateIn, StateIn) :-
|
|
4243
|
+
!,
|
|
4244
|
+
get_session_id(SessionId),
|
|
4245
|
+
engine_yield(request_proc(self)),
|
|
4246
|
+
get_next_signal(SessionId, _),
|
|
4247
|
+
session_proc_result(SessionId, self, Pid),
|
|
4248
|
+
retract(session_proc_result(SessionId, self, _)).
|
|
4249
|
+
|
|
4250
|
+
%% mi_call(spawn(+Goal, -Pid), +StateIn, -StateOut)
|
|
4251
|
+
mi_call(spawn(Goal, Pid), StateIn, StateIn) :-
|
|
4252
|
+
!,
|
|
4253
|
+
get_session_id(SessionId),
|
|
4254
|
+
copy_term(Goal, GoalCopy),
|
|
4255
|
+
term_string(GoalCopy, GoalText),
|
|
4256
|
+
engine_yield(request_proc(spawn(GoalText))),
|
|
4257
|
+
get_next_signal(SessionId, _),
|
|
4258
|
+
session_proc_result(SessionId, spawn, SpawnResult),
|
|
4259
|
+
retract(session_proc_result(SessionId, spawn, _)),
|
|
4260
|
+
( SpawnResult = ok(Pid)
|
|
4261
|
+
-> true
|
|
4262
|
+
; throw(error(process_spawn_failed(SpawnResult), spawn/2))
|
|
4263
|
+
).
|
|
4264
|
+
|
|
4265
|
+
%% mi_call(spawn_opt(+Goal, -Pid, +Options), +StateIn, -StateOut)
|
|
4266
|
+
mi_call(spawn_opt(Goal, Pid, Options), StateIn, StateIn) :-
|
|
4267
|
+
!,
|
|
4268
|
+
get_session_id(SessionId),
|
|
4269
|
+
copy_term(Goal, GoalCopy),
|
|
4270
|
+
term_string(GoalCopy, GoalText),
|
|
4271
|
+
( is_dict(Options) -> term_string(Options, OptionsText) ; OptionsText = "{}" ),
|
|
4272
|
+
engine_yield(request_proc(spawn(GoalText, OptionsText))),
|
|
4273
|
+
get_next_signal(SessionId, _),
|
|
4274
|
+
session_proc_result(SessionId, spawn, SpawnResult),
|
|
4275
|
+
retract(session_proc_result(SessionId, spawn, _)),
|
|
4276
|
+
( SpawnResult = ok(Pid)
|
|
4277
|
+
-> true
|
|
4278
|
+
; throw(error(process_spawn_failed(SpawnResult), spawn_opt/3))
|
|
4279
|
+
).
|
|
4280
|
+
|
|
4281
|
+
%% mi_call(send(+Target, +Message), +StateIn, -StateOut)
|
|
4282
|
+
mi_call(send(To, Message), StateIn, StateIn) :-
|
|
4283
|
+
!,
|
|
4284
|
+
get_session_id(SessionId),
|
|
4285
|
+
term_string(To, ToText),
|
|
4286
|
+
term_string(Message, MessageText),
|
|
4287
|
+
engine_yield(request_proc(send(ToText, MessageText))),
|
|
4288
|
+
get_next_signal(SessionId, _),
|
|
4289
|
+
session_proc_result(SessionId, send, SendResult),
|
|
4290
|
+
retract(session_proc_result(SessionId, send, _)),
|
|
4291
|
+
( SendResult == ok
|
|
4292
|
+
-> true
|
|
4293
|
+
; throw(error(process_send_failed(SendResult), send/2))
|
|
4294
|
+
).
|
|
4295
|
+
|
|
4296
|
+
%% mi_call(receive(?Message), +StateIn, -StateOut)
|
|
4297
|
+
mi_call(receive(Message), StateIn, StateIn) :-
|
|
4298
|
+
!,
|
|
4299
|
+
mi_call(receive(Message, 0), StateIn, StateIn).
|
|
4300
|
+
|
|
4301
|
+
%% mi_call(receive(?Message, +TimeoutMs), +StateIn, -StateOut)
|
|
4302
|
+
%% Fails on timeout, so a caller can branch on it.
|
|
4303
|
+
mi_call(receive(Message, TimeoutMs), StateIn, StateIn) :-
|
|
4304
|
+
!,
|
|
4305
|
+
get_session_id(SessionId),
|
|
4306
|
+
engine_yield(request_proc(receive(TimeoutMs))),
|
|
4307
|
+
get_next_signal(SessionId, _),
|
|
4308
|
+
session_proc_result(SessionId, receive, ReceiveResult),
|
|
4309
|
+
retract(session_proc_result(SessionId, receive, _)),
|
|
4310
|
+
ReceiveResult = ok(Message).
|
|
4311
|
+
|
|
4312
|
+
%% mi_call(receive_match(+Template, ?Message, +TimeoutMs), +StateIn, -StateOut)
|
|
4313
|
+
%% Selective receive: skip messages that do not unify with Template, requeue
|
|
4314
|
+
%% them in order, and fail on timeout. The template unifies in this process.
|
|
4315
|
+
mi_call(receive_match(Template, Message, TimeoutMs), StateIn, StateIn) :-
|
|
4316
|
+
!,
|
|
4317
|
+
get_session_id(SessionId),
|
|
4318
|
+
proc_now_ms(Start),
|
|
4319
|
+
receive_match_loop(Template, Message, TimeoutMs, Start, SessionId, []).
|
|
4320
|
+
|
|
4321
|
+
%% A plain monotonic clock for helpers (now_ms/1 is a mi_call special predicate).
|
|
4322
|
+
proc_now_ms(Milliseconds) :-
|
|
4323
|
+
get_time(Seconds),
|
|
4324
|
+
Milliseconds is round(Seconds * 1000).
|
|
4325
|
+
|
|
4326
|
+
receive_match_loop(Template, Message, TimeoutMs, Start, SessionId, Skipped) :-
|
|
4327
|
+
proc_now_ms(Now),
|
|
4328
|
+
( TimeoutMs > 0
|
|
4329
|
+
-> Left is TimeoutMs - (Now - Start)
|
|
4330
|
+
; Left = 0
|
|
4331
|
+
),
|
|
4332
|
+
( TimeoutMs > 0, Left =< 0
|
|
4333
|
+
-> requeue_skipped(Skipped, SessionId),
|
|
4334
|
+
fail
|
|
4335
|
+
; engine_yield(request_proc(receive(Left))),
|
|
4336
|
+
get_next_signal(SessionId, _),
|
|
4337
|
+
session_proc_result(SessionId, receive, Result),
|
|
4338
|
+
retract(session_proc_result(SessionId, receive, _)),
|
|
4339
|
+
( Result = ok(Term),
|
|
4340
|
+
( copy_term(Template, Copy), Copy = Term
|
|
4341
|
+
-> requeue_skipped(Skipped, SessionId),
|
|
4342
|
+
Template = Term,
|
|
4343
|
+
Message = Term
|
|
4344
|
+
; receive_match_loop(Template, Message, TimeoutMs, Start, SessionId, [Term|Skipped])
|
|
4345
|
+
)
|
|
4346
|
+
; requeue_skipped(Skipped, SessionId),
|
|
4347
|
+
fail
|
|
4348
|
+
)
|
|
4349
|
+
).
|
|
4350
|
+
|
|
4351
|
+
requeue_skipped(Skipped, SessionId) :-
|
|
4352
|
+
requeue_reversed(Skipped, [], Reversed),
|
|
4353
|
+
requeue_all(Reversed, SessionId).
|
|
4354
|
+
|
|
4355
|
+
%% Build the reversed list without library(lists) (deepclause_mi may not have it).
|
|
4356
|
+
requeue_reversed([], Acc, Acc).
|
|
4357
|
+
requeue_reversed([X|Xs], Acc, Out) :- requeue_reversed(Xs, [X|Acc], Out).
|
|
4358
|
+
|
|
4359
|
+
requeue_all([], _).
|
|
4360
|
+
requeue_all([Message|Messages], SessionId) :-
|
|
4361
|
+
term_string(Message, Text),
|
|
4362
|
+
engine_yield(request_proc(requeue(Text))),
|
|
4363
|
+
get_next_signal(SessionId, _),
|
|
4364
|
+
session_proc_result(SessionId, requeue, _),
|
|
4365
|
+
retract(session_proc_result(SessionId, requeue, _)),
|
|
4366
|
+
requeue_all(Messages, SessionId).
|
|
4367
|
+
|
|
4368
|
+
%% mi_call(exit(+Reason), +StateIn, -StateOut)
|
|
4369
|
+
%% Terminate this process. The host marks it killed; the frame is stopped by
|
|
4370
|
+
%% the throw below, which the runner maps to a clean termination.
|
|
4371
|
+
mi_call(exit(Reason), StateIn, StateIn) :-
|
|
4372
|
+
!,
|
|
4373
|
+
get_session_id(SessionId),
|
|
4374
|
+
term_string(Reason, ReasonText),
|
|
4375
|
+
engine_yield(request_proc(exit(ReasonText))),
|
|
4376
|
+
get_next_signal(SessionId, _),
|
|
4377
|
+
session_proc_result(SessionId, exit, _),
|
|
4378
|
+
retract(session_proc_result(SessionId, exit, _)),
|
|
4379
|
+
throw(process_exit(Reason)).
|
|
4380
|
+
|
|
4381
|
+
%% mi_call(exit(+Pid, +Reason), +StateIn, -StateOut)
|
|
4382
|
+
%% Terminate another process. Unlike exit/1 this returns; the target is killed.
|
|
4383
|
+
mi_call(exit(Pid, Reason), StateIn, StateIn) :-
|
|
4384
|
+
!,
|
|
4385
|
+
get_session_id(SessionId),
|
|
4386
|
+
term_string(Pid, PidText),
|
|
4387
|
+
term_string(Reason, ReasonText),
|
|
4388
|
+
engine_yield(request_proc(exit(PidText, ReasonText))),
|
|
4389
|
+
get_next_signal(SessionId, _),
|
|
4390
|
+
session_proc_result(SessionId, exit, ExitResult),
|
|
4391
|
+
retract(session_proc_result(SessionId, exit, _)),
|
|
4392
|
+
( ExitResult == ok
|
|
4393
|
+
-> true
|
|
4394
|
+
; throw(error(process_exit_failed(ExitResult), exit/2))
|
|
4395
|
+
).
|
|
4396
|
+
|
|
4397
|
+
%% mi_call(process_info(+Pid, -Info), +StateIn, -StateOut)
|
|
4398
|
+
mi_call(process_info(Pid, Info), StateIn, StateIn) :-
|
|
4399
|
+
!,
|
|
4400
|
+
get_session_id(SessionId),
|
|
4401
|
+
term_string(Pid, PidText),
|
|
4402
|
+
engine_yield(request_proc(process_info(PidText))),
|
|
4403
|
+
get_next_signal(SessionId, _),
|
|
4404
|
+
session_proc_result(SessionId, process_info, Info),
|
|
4405
|
+
retract(session_proc_result(SessionId, process_info, _)).
|
|
4406
|
+
|
|
4407
|
+
%% mi_call(register(+Name, +Pid), +StateIn, -StateOut)
|
|
4408
|
+
mi_call(register(Name, Pid), StateIn, StateIn) :-
|
|
4409
|
+
!,
|
|
4410
|
+
get_session_id(SessionId),
|
|
4411
|
+
term_string(Name, NameText),
|
|
4412
|
+
term_string(Pid, PidText),
|
|
4413
|
+
engine_yield(request_proc(register(NameText, PidText))),
|
|
4414
|
+
get_next_signal(SessionId, _),
|
|
4415
|
+
session_proc_result(SessionId, register, RegisterResult),
|
|
4416
|
+
retract(session_proc_result(SessionId, register, _)),
|
|
4417
|
+
( RegisterResult == ok
|
|
4418
|
+
-> true
|
|
4419
|
+
; throw(error(process_register_failed(RegisterResult), register/2))
|
|
4420
|
+
).
|
|
4421
|
+
|
|
4422
|
+
%% mi_call(whereis(+Name, ?Pid), +StateIn, -StateOut)
|
|
4423
|
+
mi_call(whereis(Name, Pid), StateIn, StateIn) :-
|
|
4424
|
+
!,
|
|
4425
|
+
get_session_id(SessionId),
|
|
4426
|
+
term_string(Name, NameText),
|
|
4427
|
+
engine_yield(request_proc(whereis(NameText))),
|
|
4428
|
+
get_next_signal(SessionId, _),
|
|
4429
|
+
session_proc_result(SessionId, whereis, WhereResult),
|
|
4430
|
+
retract(session_proc_result(SessionId, whereis, _)),
|
|
4431
|
+
WhereResult = ok(Pid).
|
|
4432
|
+
|
|
4433
|
+
%% mi_call(sleep(+Milliseconds), +StateIn, -StateOut)
|
|
4434
|
+
mi_call(sleep(Milliseconds), StateIn, StateIn) :-
|
|
4435
|
+
!,
|
|
4436
|
+
get_session_id(SessionId),
|
|
4437
|
+
engine_yield(request_proc(sleep(Milliseconds))),
|
|
4438
|
+
get_next_signal(SessionId, _),
|
|
4439
|
+
session_proc_result(SessionId, sleep, _),
|
|
4440
|
+
retract(session_proc_result(SessionId, sleep, _)).
|
|
4441
|
+
|
|
4442
|
+
%% mi_call(make_ref(-Ref), +StateIn, -StateOut)
|
|
4443
|
+
mi_call(make_ref(Ref), StateIn, StateIn) :-
|
|
4444
|
+
!,
|
|
4445
|
+
gensym(ref_, Ref).
|
|
4446
|
+
|
|
4447
|
+
%% mi_call(now_ms(-Milliseconds), +StateIn, -StateOut)
|
|
4448
|
+
mi_call(now_ms(Milliseconds), StateIn, StateIn) :-
|
|
4449
|
+
!,
|
|
4450
|
+
get_time(Seconds),
|
|
4451
|
+
Milliseconds is round(Seconds * 1000).
|
|
4452
|
+
|
|
4453
|
+
%% mi_call(serve(+Name, +Goal), +StateIn, -StateOut)
|
|
4454
|
+
%% Spawn a session-scoped process and register it under Name. Sugar over
|
|
4455
|
+
%% spawn/2 + register/2; the goal decides the process's shape.
|
|
4456
|
+
mi_call(serve(Name, Goal), StateIn, StateIn) :-
|
|
4457
|
+
!,
|
|
4458
|
+
get_session_id(SessionId),
|
|
4459
|
+
copy_term(Goal, GoalCopy),
|
|
4460
|
+
term_string(GoalCopy, GoalText),
|
|
4461
|
+
engine_yield(request_proc(spawn(GoalText))),
|
|
4462
|
+
get_next_signal(SessionId, _),
|
|
4463
|
+
session_proc_result(SessionId, spawn, SpawnResult),
|
|
4464
|
+
retract(session_proc_result(SessionId, spawn, _)),
|
|
4465
|
+
SpawnResult = ok(Pid),
|
|
4466
|
+
term_string(Name, NameText),
|
|
4467
|
+
term_string(Pid, PidText),
|
|
4468
|
+
engine_yield(request_proc(register(NameText, PidText))),
|
|
4469
|
+
get_next_signal(SessionId, _),
|
|
4470
|
+
session_proc_result(SessionId, register, _),
|
|
4471
|
+
retract(session_proc_result(SessionId, register, _)).
|
|
4472
|
+
|
|
4473
|
+
%% mi_call(service_cast(+Target, +Message), +StateIn, -StateOut)
|
|
4474
|
+
mi_call(service_cast(Target, Message), StateIn, StateIn) :-
|
|
4475
|
+
!,
|
|
4476
|
+
get_session_id(SessionId),
|
|
4477
|
+
term_string(Target, TargetText),
|
|
4478
|
+
term_string(Message, MessageText),
|
|
4479
|
+
engine_yield(request_proc(send(TargetText, MessageText))),
|
|
4480
|
+
get_next_signal(SessionId, _),
|
|
4481
|
+
session_proc_result(SessionId, send, _),
|
|
4482
|
+
retract(session_proc_result(SessionId, send, _)).
|
|
4483
|
+
|
|
4484
|
+
%% mi_call(service_call(+Target, +Request, -Reply), +StateIn, -StateOut)
|
|
4485
|
+
mi_call(service_call(Target, Request, Reply), StateIn, StateOut) :-
|
|
4486
|
+
!,
|
|
4487
|
+
mi_call(service_call(Target, Request, Reply, 300000), StateIn, StateOut).
|
|
4488
|
+
|
|
4489
|
+
%% mi_call(service_call(+Target, +Request, -Reply, +TimeoutMs), ...)
|
|
4490
|
+
%% Request/reply against a process using the request(From, Ref, Request) /
|
|
4491
|
+
%% reply(Ref, Value) protocol. Unrelated messages are ignored while waiting.
|
|
4492
|
+
mi_call(service_call(Target, Request, Reply, Timeout), StateIn, StateIn) :-
|
|
4493
|
+
!,
|
|
4494
|
+
get_session_id(SessionId),
|
|
4495
|
+
gensym(reply_ref_, Ref),
|
|
4496
|
+
engine_yield(request_proc(self)),
|
|
4497
|
+
get_next_signal(SessionId, _),
|
|
4498
|
+
session_proc_result(SessionId, self, Me),
|
|
4499
|
+
retract(session_proc_result(SessionId, self, _)),
|
|
4500
|
+
term_string(Target, TargetText),
|
|
4501
|
+
term_string(request(Me, Ref, Request), RequestText),
|
|
4502
|
+
engine_yield(request_proc(send(TargetText, RequestText))),
|
|
4503
|
+
get_next_signal(SessionId, _),
|
|
4504
|
+
session_proc_result(SessionId, send, _),
|
|
4505
|
+
retract(session_proc_result(SessionId, send, _)),
|
|
4506
|
+
service_await_reply(Ref, Reply, Timeout).
|
|
4507
|
+
|
|
4508
|
+
%% service_await_reply(+Ref, -Reply, +TimeoutMs)
|
|
4509
|
+
service_await_reply(Ref, Reply, Timeout) :-
|
|
4510
|
+
get_session_id(SessionId),
|
|
4511
|
+
engine_yield(request_proc(receive(Timeout))),
|
|
4512
|
+
get_next_signal(SessionId, _),
|
|
4513
|
+
session_proc_result(SessionId, receive, Result),
|
|
4514
|
+
retract(session_proc_result(SessionId, receive, _)),
|
|
4515
|
+
( Result = ok(reply(Ref, Reply))
|
|
4516
|
+
-> true
|
|
4517
|
+
; Result = ok(_)
|
|
4518
|
+
-> service_await_reply(Ref, Reply, Timeout)
|
|
4519
|
+
; fail
|
|
4520
|
+
).
|
|
4521
|
+
|
|
4522
|
+
%% mi_call(wait(+Pid[, -Outcome]), +StateIn, -StateOut)
|
|
4523
|
+
%% Block until a process terminates. Outcome is ok(Result), failed(Error), or
|
|
4524
|
+
%% killed(Reason); Result is the process's terminal text as a Prolog string.
|
|
4525
|
+
%% `wait/1` is semidet: it succeeds only on a successful finish.
|
|
4526
|
+
mi_call(wait(Pid), StateIn, StateIn) :-
|
|
4527
|
+
!,
|
|
4528
|
+
mi_call(wait(Pid, Outcome), StateIn, _),
|
|
4529
|
+
Outcome = ok(_).
|
|
4530
|
+
|
|
4531
|
+
mi_call(wait(Pid, Outcome), StateIn, StateIn) :-
|
|
4532
|
+
!,
|
|
4533
|
+
get_session_id(SessionId),
|
|
4534
|
+
term_string(Pid, PidText),
|
|
4535
|
+
engine_yield(request_proc(wait(PidText))),
|
|
4536
|
+
get_next_signal(SessionId, _),
|
|
4537
|
+
session_proc_result(SessionId, wait, Outcome),
|
|
4538
|
+
retract(session_proc_result(SessionId, wait, _)).
|
|
4539
|
+
|
|
4540
|
+
%% ============================================================
|
|
4541
|
+
%% Swarm / pmap: fan a worker over a list concurrently
|
|
4542
|
+
%% ============================================================
|
|
4543
|
+
%% Each item runs in its own process (spawned through the host), calling
|
|
4544
|
+
%% call(Worker, Item, Value). Results preserve input order. `Concurrency` is
|
|
4545
|
+
%% accepted for compatibility and not yet enforced (the host's process limit is).
|
|
4546
|
+
|
|
4547
|
+
proc_self(SessionId, Me) :-
|
|
4548
|
+
engine_yield(request_proc(self)),
|
|
4549
|
+
get_next_signal(SessionId, _),
|
|
4550
|
+
session_proc_result(SessionId, self, Me),
|
|
4551
|
+
retract(session_proc_result(SessionId, self, _)).
|
|
4552
|
+
|
|
4553
|
+
%% mi_call(swarm(+Worker, +Items, -Results), ...)
|
|
4554
|
+
mi_call(swarm(Worker, Items, Results), StateIn, StateOut) :-
|
|
4555
|
+
!,
|
|
4556
|
+
mi_call(swarm(Worker, Items, Results, 4), StateIn, StateOut).
|
|
4557
|
+
|
|
4558
|
+
%% mi_call(swarm(+Worker, +Items, -Results, +Concurrency), ...)
|
|
4559
|
+
%% Windowed fan-out: at most Concurrency items run at once.
|
|
4560
|
+
mi_call(swarm(Worker, Items, Results, Concurrency), StateIn, StateIn) :-
|
|
4561
|
+
!,
|
|
4562
|
+
get_session_id(SessionId),
|
|
4563
|
+
proc_self(SessionId, Me),
|
|
4564
|
+
( integer(Concurrency), Concurrency > 0 -> Conc = Concurrency ; Conc = 4 ),
|
|
4565
|
+
swarm_loop(Items, 1, [], Conc, Worker, Me, SessionId, [], Pairs),
|
|
4566
|
+
keysort(Pairs, Sorted),
|
|
4567
|
+
swarm_values(Sorted, Results).
|
|
4568
|
+
|
|
4569
|
+
%% Accumulate `Acc`, bind the collected pairs to `Pairs` at the base.
|
|
4570
|
+
swarm_loop(Pending, NextIndex, InFlight, Conc, Worker, Me, SessionId, Acc, Pairs) :-
|
|
4571
|
+
( Pending = [Item|Rest],
|
|
4572
|
+
length(InFlight, K), K < Conc
|
|
4573
|
+
-> swarm_spawn_one(Item, NextIndex, Worker, Me, SessionId, SpawnResult),
|
|
4574
|
+
Next is NextIndex + 1,
|
|
4575
|
+
( SpawnResult = ok(_Pid)
|
|
4576
|
+
-> swarm_loop(Rest, Next, [NextIndex|InFlight], Conc, Worker, Me, SessionId, Acc, Pairs)
|
|
4577
|
+
; % The host refused the spawn (e.g. the live-process limit): fail only
|
|
4578
|
+
% this item, so the swarm still completes and the reason is visible
|
|
4579
|
+
% instead of the whole call failing silently.
|
|
4580
|
+
swarm_loop(Rest, Next, InFlight, Conc, Worker, Me, SessionId,
|
|
4581
|
+
[NextIndex-failed(SpawnResult)|Acc], Pairs)
|
|
4582
|
+
)
|
|
4583
|
+
; InFlight = [_|_]
|
|
4584
|
+
-> swarm_receive(Index, Value, SessionId),
|
|
4585
|
+
selectchk(Index, InFlight, Rest),
|
|
4586
|
+
swarm_loop(Pending, NextIndex, Rest, Conc, Worker, Me, SessionId, [Index-Value|Acc], Pairs)
|
|
4587
|
+
; Pairs = Acc
|
|
4588
|
+
).
|
|
4589
|
+
|
|
4590
|
+
swarm_spawn_one(Item, Index, Worker, Me, SessionId, SpawnResult) :-
|
|
4591
|
+
term_string(deepclause_mi:dc_swarm_item(Worker, Item, Me, Index), GoalText),
|
|
4592
|
+
engine_yield(request_proc(spawn(GoalText))),
|
|
4593
|
+
get_next_signal(SessionId, _),
|
|
4594
|
+
session_proc_result(SessionId, spawn, SpawnResult),
|
|
4595
|
+
retract(session_proc_result(SessionId, spawn, _)).
|
|
4596
|
+
|
|
4597
|
+
swarm_receive(Index, Value, SessionId) :-
|
|
4598
|
+
engine_yield(request_proc(receive(0))),
|
|
4599
|
+
get_next_signal(SessionId, _),
|
|
4600
|
+
session_proc_result(SessionId, receive, R),
|
|
4601
|
+
retract(session_proc_result(SessionId, receive, _)),
|
|
4602
|
+
R = ok(swarm_result(Index, Value)).
|
|
4603
|
+
|
|
4604
|
+
swarm_values([], []).
|
|
4605
|
+
swarm_values([_-Value|Rest], [Value|Values]) :- swarm_values(Rest, Values).
|
|
4606
|
+
|
|
4607
|
+
%% dc_swarm_item(+Worker, +Item, +Parent, +Index) — the child goal.
|
|
4608
|
+
%% Catch a thrown error (an undefined worker, a budget, a tool failure) and
|
|
4609
|
+
%% report it as `failed(Error)`. Without the catch the child process crashes and
|
|
4610
|
+
%% never sends a result, so the parent's `swarm_receive` waits forever.
|
|
4611
|
+
%%
|
|
4612
|
+
%% The `call` must stay inline in this clause: a helper predicate defined in
|
|
4613
|
+
%% `deepclause_mi` is reached via the meta-interpreter's raw-Prolog fallback, and
|
|
4614
|
+
%% then `call(Worker, ...)` resolves in `deepclause_mi` instead of the session
|
|
4615
|
+
%% module (so every worker looked undefined).
|
|
4616
|
+
dc_swarm_item(Worker, Item, Parent, Index) :-
|
|
4617
|
+
catch(
|
|
4618
|
+
( call(Worker, Item, Result)
|
|
4619
|
+
-> Outcome = ok(Result)
|
|
4620
|
+
; Outcome = failed
|
|
4621
|
+
),
|
|
4622
|
+
Error,
|
|
4623
|
+
Outcome = failed(Error)
|
|
4624
|
+
),
|
|
4625
|
+
send(Parent, swarm_result(Index, Outcome)).
|
|
4626
|
+
|
|
4627
|
+
%% mi_call(pmap(+Worker, +Items, -Values), ...)
|
|
4628
|
+
%% Like swarm/3, but fails if any item failed.
|
|
4629
|
+
mi_call(pmap(Worker, Items, Values), StateIn, StateIn) :-
|
|
4630
|
+
!,
|
|
4631
|
+
mi_call(swarm(Worker, Items, Results), StateIn, _),
|
|
4632
|
+
pmap_ok(Results, Values).
|
|
4633
|
+
|
|
4634
|
+
pmap_ok([], []).
|
|
4635
|
+
pmap_ok([ok(Value)|Rest], [Value|Values]) :- pmap_ok(Rest, Values).
|
|
4636
|
+
|
|
4147
4637
|
%% ============================================================
|
|
4148
4638
|
%% Tool Scoping Predicates
|
|
4149
4639
|
%% ============================================================
|
|
@@ -5477,6 +5967,30 @@ is_mi_special_predicate(task_named(_,_,_)). %% Transformed form of task/N
|
|
|
5477
5967
|
is_mi_special_predicate(sample_token(_,_)).
|
|
5478
5968
|
is_mi_special_predicate(sample_token(_,_,_)).
|
|
5479
5969
|
is_mi_special_predicate(exec(_,_)).
|
|
5970
|
+
is_mi_special_predicate(spawn(_,_)).
|
|
5971
|
+
is_mi_special_predicate(spawn_opt(_,_,_)).
|
|
5972
|
+
is_mi_special_predicate(self(_)).
|
|
5973
|
+
is_mi_special_predicate(send(_,_)).
|
|
5974
|
+
is_mi_special_predicate(receive(_)).
|
|
5975
|
+
is_mi_special_predicate(receive(_,_)).
|
|
5976
|
+
is_mi_special_predicate(receive_match(_,_,_)).
|
|
5977
|
+
is_mi_special_predicate(exit(_)).
|
|
5978
|
+
is_mi_special_predicate(exit(_,_)).
|
|
5979
|
+
is_mi_special_predicate(process_info(_,_)).
|
|
5980
|
+
is_mi_special_predicate(register(_,_)).
|
|
5981
|
+
is_mi_special_predicate(whereis(_,_)).
|
|
5982
|
+
is_mi_special_predicate(sleep(_)).
|
|
5983
|
+
is_mi_special_predicate(make_ref(_)).
|
|
5984
|
+
is_mi_special_predicate(now_ms(_)).
|
|
5985
|
+
is_mi_special_predicate(serve(_,_)).
|
|
5986
|
+
is_mi_special_predicate(service_cast(_,_)).
|
|
5987
|
+
is_mi_special_predicate(service_call(_,_,_)).
|
|
5988
|
+
is_mi_special_predicate(service_call(_,_,_,_)).
|
|
5989
|
+
is_mi_special_predicate(swarm(_,_,_)).
|
|
5990
|
+
is_mi_special_predicate(swarm(_,_,_,_)).
|
|
5991
|
+
is_mi_special_predicate(pmap(_,_,_)).
|
|
5992
|
+
is_mi_special_predicate(wait(_)).
|
|
5993
|
+
is_mi_special_predicate(wait(_,_)).
|
|
5480
5994
|
is_mi_special_predicate(param(_,_)).
|
|
5481
5995
|
is_mi_special_predicate(param(_,_,_)).
|
|
5482
5996
|
%% Prompt predicates (like task but with fresh memory)
|