@lmctl-ai/lmctl 0.1.342 → 0.2.2

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.
Files changed (182) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +11 -51
  3. package/data/price-aliases.json +1 -0
  4. package/data/price-data.json +1 -1
  5. package/dist/cli/batch.d.ts +2 -0
  6. package/dist/cli/busy-evidence.d.ts +27 -0
  7. package/dist/cli/chat-cycle.d.ts +59 -0
  8. package/dist/cli/chat-exec.d.ts +83 -0
  9. package/dist/cli/chat-policy.d.ts +22 -0
  10. package/dist/cli/chat.d.ts +23 -0
  11. package/dist/cli/code-resolver.d.ts +8 -0
  12. package/dist/cli/common.d.ts +54 -0
  13. package/dist/cli/context.d.ts +12 -0
  14. package/dist/cli/cost.d.ts +2 -0
  15. package/dist/cli/export.d.ts +2 -0
  16. package/dist/cli/index.d.ts +3 -0
  17. package/dist/cli/index.js +1062 -1400
  18. package/dist/cli/infra.d.ts +78 -0
  19. package/dist/cli/ls.d.ts +2 -0
  20. package/dist/cli/mailbox-cli.d.ts +6 -0
  21. package/dist/cli/managed.d.ts +62 -0
  22. package/dist/cli/mcp-install.d.ts +23 -0
  23. package/dist/cli/mcp.d.ts +2 -0
  24. package/dist/cli/paths.d.ts +50 -0
  25. package/dist/cli/plan-wizard.d.ts +42 -0
  26. package/dist/cli/plan.d.ts +20 -0
  27. package/dist/cli/queue-delivery.d.ts +107 -0
  28. package/dist/cli/ratelimit.d.ts +3 -0
  29. package/dist/cli/remote-fetch.d.ts +7 -0
  30. package/dist/cli/run-queries.d.ts +82 -0
  31. package/dist/cli/running.d.ts +5 -0
  32. package/dist/cli/schema.sql +20 -1
  33. package/dist/cli/script.d.ts +6 -0
  34. package/dist/cli/script.js +2097 -0
  35. package/dist/cli/self-identity.d.ts +25 -0
  36. package/dist/cli/session-idle.d.ts +118 -0
  37. package/dist/cli/status.d.ts +22 -0
  38. package/dist/cli/tail.d.ts +18 -0
  39. package/dist/cli/target-resolver.d.ts +139 -0
  40. package/dist/cli/team-status.d.ts +91 -0
  41. package/dist/cli/teamfile-compat.d.ts +71 -0
  42. package/dist/cli/teamfile-store.d.ts +18 -0
  43. package/dist/cli/teamfile-template.d.ts +40 -0
  44. package/dist/cli/template-env.d.ts +25 -0
  45. package/dist/cli/terminal-lock.d.ts +25 -0
  46. package/dist/cli/terminal.d.ts +23 -0
  47. package/dist/cli/time-filter.d.ts +10 -0
  48. package/dist/cli/update-notifier.d.ts +11 -0
  49. package/dist/cli/version-util.d.ts +2 -0
  50. package/dist/config/seed_templates.d.ts +1 -0
  51. package/dist/db/backfill-event-log.d.ts +26 -0
  52. package/dist/db/delegation.d.ts +37 -0
  53. package/dist/db/escalation_vocab.d.ts +45 -0
  54. package/dist/db/event-log.d.ts +40 -0
  55. package/dist/db/index.d.ts +1213 -0
  56. package/dist/db/inflight-acquire.d.ts +70 -0
  57. package/dist/db/invocation-event-projections.d.ts +65 -0
  58. package/dist/db/ledger-identity.test.d.ts +1 -0
  59. package/dist/db/live-event-projections.d.ts +92 -0
  60. package/dist/db/migrate.d.ts +51 -0
  61. package/dist/db/open-readonly.d.ts +2 -0
  62. package/dist/db/process-liveness.d.ts +37 -0
  63. package/dist/db/sqlite.d.ts +47 -0
  64. package/dist/db/sqlite.test.d.ts +1 -0
  65. package/dist/db/terminal-lock.d.ts +14 -0
  66. package/dist/db/tracked-invocation-reconcile.d.ts +52 -0
  67. package/dist/db/tracked-invocation.d.ts +116 -0
  68. package/dist/mcp/dispatch.d.ts +45 -0
  69. package/dist/mcp/mediation.d.ts +128 -0
  70. package/dist/mcp/path-warning.d.ts +7 -0
  71. package/dist/mcp/server.d.ts +63 -0
  72. package/dist/mcp/tools.d.ts +24 -0
  73. package/dist/providers/adapter.d.ts +265 -0
  74. package/dist/providers/adapters/agy-adapter.d.ts +17 -0
  75. package/dist/providers/adapters/claude-adapter.d.ts +20 -0
  76. package/dist/providers/adapters/codex-adapter.d.ts +22 -0
  77. package/dist/providers/adapters/copilot-adapter.d.ts +16 -0
  78. package/dist/providers/adapters/dsh-adapter.d.ts +89 -0
  79. package/dist/providers/adapters/gemini-adapter.d.ts +44 -0
  80. package/dist/providers/adapters/hermes-adapter.d.ts +71 -0
  81. package/dist/providers/adapters/index.d.ts +35 -0
  82. package/dist/providers/adapters/kimi-adapter.d.ts +16 -0
  83. package/dist/providers/adapters/lmplayer-adapter.d.ts +14 -0
  84. package/dist/providers/adapters/opencode-adapter.d.ts +11 -0
  85. package/dist/providers/adapters/pi-adapter.d.ts +17 -0
  86. package/dist/providers/adapters/print-turn.d.ts +29 -0
  87. package/dist/providers/adapters/qwen-adapter.d.ts +11 -0
  88. package/dist/providers/agy.d.ts +32 -0
  89. package/dist/providers/base-adapter.d.ts +107 -0
  90. package/dist/providers/base.d.ts +12 -0
  91. package/dist/providers/binary-check.d.ts +102 -0
  92. package/dist/providers/bundle.d.ts +118 -0
  93. package/dist/providers/claude-mock.d.ts +90 -0
  94. package/dist/providers/claude.d.ts +21 -0
  95. package/dist/providers/codex-config.d.ts +15 -0
  96. package/dist/providers/codex.d.ts +25 -0
  97. package/dist/providers/config/model-selection-lint.d.ts +45 -0
  98. package/dist/providers/config/team-config.d.ts +183 -0
  99. package/dist/providers/config/types.d.ts +146 -0
  100. package/dist/providers/config/user-config.d.ts +88 -0
  101. package/dist/providers/copilot.d.ts +21 -0
  102. package/dist/providers/debug.d.ts +128 -0
  103. package/dist/providers/dsh-sidecar.d.ts +65 -0
  104. package/dist/providers/dsh-zstd.d.ts +27 -0
  105. package/dist/providers/dsh.d.ts +37 -0
  106. package/dist/providers/frontmatter.d.ts +46 -0
  107. package/dist/providers/gemini-session-reader.d.ts +151 -0
  108. package/dist/providers/gemini.d.ts +39 -0
  109. package/dist/providers/hermes.d.ts +90 -0
  110. package/dist/providers/index.d.ts +421 -0
  111. package/dist/providers/kimi.d.ts +37 -0
  112. package/dist/providers/model-catalog.d.ts +141 -0
  113. package/dist/providers/one-shot-timeout.d.ts +1 -0
  114. package/dist/providers/opencode-config.d.ts +62 -0
  115. package/dist/providers/opencode.d.ts +40 -0
  116. package/dist/providers/parsers/acp.d.ts +47 -0
  117. package/dist/providers/parsers/codex-app-server.d.ts +60 -0
  118. package/dist/providers/parsers/stream-json.d.ts +57 -0
  119. package/dist/providers/passive-readers/agy.d.ts +155 -0
  120. package/dist/providers/passive-readers/copilot.d.ts +173 -0
  121. package/dist/providers/passive-readers/dsh.d.ts +34 -0
  122. package/dist/providers/passive-readers/kimi.d.ts +44 -0
  123. package/dist/providers/passive-readers/opencode.d.ts +89 -0
  124. package/dist/providers/passive-readers/qwen.d.ts +151 -0
  125. package/dist/providers/passive-readers/shared.d.ts +138 -0
  126. package/dist/providers/passive-session-reader.d.ts +188 -0
  127. package/dist/providers/path-utils.d.ts +1 -0
  128. package/dist/providers/pi.d.ts +32 -0
  129. package/dist/providers/pricing.d.ts +107 -0
  130. package/dist/providers/qwen.d.ts +22 -0
  131. package/dist/providers/ratelimit-readings.d.ts +32 -0
  132. package/dist/providers/registry.d.ts +31 -0
  133. package/dist/providers/resume.d.ts +43 -0
  134. package/dist/providers/seed-instruction.d.ts +3 -0
  135. package/dist/providers/self-session-env.d.ts +21 -0
  136. package/dist/providers/session-limit.d.ts +9 -0
  137. package/dist/providers/strip-ansi.d.ts +5 -0
  138. package/dist/providers/transport-errors.d.ts +94 -0
  139. package/dist/providers/transport-lifecycle.d.ts +63 -0
  140. package/dist/providers/transport-wrappers.d.ts +110 -0
  141. package/dist/providers/transports/acp-profiles/config-option-step.d.ts +24 -0
  142. package/dist/providers/transports/acp-profiles/copilot.d.ts +12 -0
  143. package/dist/providers/transports/acp-profiles/gemini.d.ts +22 -0
  144. package/dist/providers/transports/acp-profiles/hermes.d.ts +27 -0
  145. package/dist/providers/transports/acp-profiles/index.d.ts +19 -0
  146. package/dist/providers/transports/acp-profiles/kimi.d.ts +24 -0
  147. package/dist/providers/transports/acp-profiles/opencode.d.ts +26 -0
  148. package/dist/providers/transports/acp-profiles/types.d.ts +258 -0
  149. package/dist/providers/transports/acp-rpc.d.ts +18 -0
  150. package/dist/providers/transports/acp.d.ts +215 -0
  151. package/dist/providers/transports/codex-app-server.d.ts +190 -0
  152. package/dist/providers/transports/hold-open.d.ts +120 -0
  153. package/dist/providers/transports/manager.d.ts +21 -0
  154. package/dist/providers/transports/stream-json.d.ts +162 -0
  155. package/dist/providers/transports/types.d.ts +56 -0
  156. package/dist/providers/types.d.ts +154 -0
  157. package/dist/providers/yolo-contract.d.ts +131 -0
  158. package/dist/script/adapter.d.ts +101 -0
  159. package/dist/script/batch-script.d.ts +7 -0
  160. package/dist/script/index.d.ts +3 -0
  161. package/dist/script/lmscript.d.ts +550 -0
  162. package/dist/shared/policy.d.ts +74 -0
  163. package/dist/shared-lib/db.d.ts +25 -0
  164. package/dist/shared-lib/passive-session-reader.d.ts +2 -0
  165. package/dist/shared-lib/provider-parse.d.ts +6 -0
  166. package/dist/templates/basedir.d.ts +52 -0
  167. package/dist/uri/lmctl_uri.d.ts +38 -0
  168. package/durable-memory/model_selection.md +108 -25
  169. package/examples/README.md +103 -0
  170. package/examples/anonymous-panel.lms +3 -0
  171. package/examples/batch-prompts.txt +9 -0
  172. package/examples/batchscript.lms +67 -0
  173. package/examples/n8n/agent-lib.lms +56 -0
  174. package/examples/n8n/git-lib.lms +93 -0
  175. package/examples/n8n/mock-support.db +0 -0
  176. package/examples/n8n/multi-agent-review.lms +107 -0
  177. package/examples/n8n/news-digest.lms +159 -0
  178. package/examples/n8n/rag-search.lms +163 -0
  179. package/examples/n8n/support-agent.lms +88 -0
  180. package/examples/n8n/ticket-triage.lms +156 -0
  181. package/package.json +13 -17
  182. package/dist/cli/side_effect_classifier.json +0 -19
@@ -0,0 +1,107 @@
1
+ # multi-agent-review.lms -- n8n Conversion: Hierarchical Multi-Agent Audit & Review Pipeline
2
+ # Represents Shape 5: Supervisor / Multi-Agent Delegation (Decompose -> Specialist Workers -> Synthesizer)
3
+ #
4
+ # Usage:
5
+ # node dist/cli/index.js script examples/n8n/multi-agent-review.lms [teamfile]
6
+
7
+ import "./agent-lib.lms";
8
+ import "./git-lib.lms";
9
+
10
+ teamfile = "examples/n8n/n8n-team.lmctl";
11
+ if (len(args) > 0) { teamfile = args[0]; }
12
+
13
+ repo = ".";
14
+ head = git_head_short(repo);
15
+ changed = git_changed(repo);
16
+
17
+ print("=== Hierarchical Multi-Agent Review Pipeline (Shape 5) ===");
18
+ print("Team: " + teamfile);
19
+ print("Repository Head: " + head);
20
+ print(format("Modified/Tracked Files: {0}", len(changed)));
21
+ for (c = 0; c < min(5, len(changed)); c = c + 1) {
22
+ print(" - " + changed[c]);
23
+ }
24
+ print("");
25
+
26
+ diff_summary = "Diff Overview:\n" +
27
+ "- Added LMScript wrappers for external commands (system curl/gh/sqlite3)\n" +
28
+ "- Implemented 5 n8n workflow conversions under examples/n8n/\n" +
29
+ "- Verified syntax and execution contracts";
30
+
31
+ # --- Stage 1: Security Audit Specialist ---
32
+ print("--- [Supervisor] Dispatching Stage 1: Security Audit ---");
33
+ auditor_prompt = "You are a Specialist Security Auditor.\n" +
34
+ "Evaluate the following architectural and code changes for security vulnerabilities, injection risks in system() calls, credentials leakage, and blast radius:\n\n" +
35
+ diff_summary + "\n\n" +
36
+ "List any vulnerabilities or confirm SECURITY_PASSED.\n" +
37
+ "End your turn with DONE on its own last line.";
38
+
39
+ res_sec = run_stage(teamfile, "Auditor", "security_audit", auditor_prompt);
40
+ st_sec = res_sec[0];
41
+ reply_sec = res_sec[1];
42
+
43
+ if (needs_human(st_sec)) {
44
+ print("Security audit failed or requires human guidance. Stopping pipeline.");
45
+ lm_exit(1);
46
+ }
47
+
48
+ raw_sec = reply_sec;
49
+ if (type(reply_sec) == "object" && has_key(reply_sec, "reply")) {
50
+ raw_sec = reply_sec.reply;
51
+ }
52
+
53
+ print("");
54
+
55
+ # --- Stage 2: Code Quality & Architecture Review Specialist ---
56
+ print("--- [Supervisor] Dispatching Stage 2: Quality & Architecture Review ---");
57
+ reviewer_prompt = "You are a Senior Code Quality Reviewer.\n" +
58
+ "Review the following changes for coding standards, type safety, modularity, and error handling:\n\n" +
59
+ diff_summary + "\n\n" +
60
+ "Security Audit Findings:\n" + raw_sec + "\n\n" +
61
+ "Provide your review verdict (APPROVED or CHANGES_REQUESTED).\n" +
62
+ "End your turn with DONE on its own last line.";
63
+
64
+ res_rev = run_stage(teamfile, "Reviewer", "code_review", reviewer_prompt);
65
+ st_rev = res_rev[0];
66
+ reply_rev = res_rev[1];
67
+
68
+ if (needs_human(st_rev)) {
69
+ print("Quality review failed or requires human guidance. Stopping pipeline.");
70
+ lm_exit(1);
71
+ }
72
+
73
+ raw_rev = reply_rev;
74
+ if (type(reply_rev) == "object" && has_key(reply_rev, "reply")) {
75
+ raw_rev = reply_rev.reply;
76
+ }
77
+
78
+ print("");
79
+
80
+ # --- Stage 3: Lead Synthesizer & Signoff ---
81
+ print("--- [Supervisor] Dispatching Stage 3: Lead Synthesis & Final Signoff ---");
82
+ lead_prompt = "You are the Team Lead.\n" +
83
+ "Review the findings from the Security Auditor and Quality Reviewer:\n\n" +
84
+ "Security Auditor Report:\n" + raw_sec + "\n\n" +
85
+ "Quality Reviewer Report:\n" + raw_rev + "\n\n" +
86
+ "Provide a concise final release recommendation and decision.\n" +
87
+ "End your turn with DONE on its own last line.";
88
+
89
+ res_lead = run_stage(teamfile, "Lead", "lead_synthesis", lead_prompt);
90
+ st_lead = res_lead[0];
91
+ reply_lead = res_lead[1];
92
+
93
+ if (needs_human(st_lead)) {
94
+ print("Lead synthesis requires human intervention.");
95
+ lm_exit(1);
96
+ }
97
+
98
+ raw_lead = reply_lead;
99
+ if (type(reply_lead) == "object" && has_key(reply_lead, "reply")) {
100
+ raw_lead = reply_lead.reply;
101
+ }
102
+
103
+ print("");
104
+ print("=== Final Pipeline Decision ===");
105
+ print(raw_lead);
106
+ print("");
107
+ print("Multi-agent review pipeline complete.");
@@ -0,0 +1,159 @@
1
+ # news-digest.lms -- n8n Conversion: Scheduled Poll & Batched AI Digest
2
+ # Represents Shape 3: Scheduled Cron -> Source Poll / Diff -> Batched LLM Transform -> Aggregate & Notify
3
+ #
4
+ # Usage:
5
+ # node dist/cli/index.js script examples/n8n/news-digest.lms [teamfile] [alias] [--dry-run]
6
+
7
+ import "./agent-lib.lms";
8
+
9
+ # --- External Service Wrappers over system() ---
10
+
11
+ fn curl_fetch_json(url) {
12
+ cmd = format("curl -s -m 10 \"{0}\"", url);
13
+ out = system(cmd);
14
+ if (out[2] != 0 || len(trim(out[0])) == 0) {
15
+ return null;
16
+ }
17
+ return json_parse(trim(out[0]));
18
+ }
19
+
20
+ fn curl_post_webhook(url, body_json) {
21
+ cmd = format("curl -s -o /dev/null -w \"%{http_code}\" -m 10 -X POST -H \"Content-Type: application/json\" -d '{0}' \"{1}\"", body_json, url);
22
+ out = system(cmd);
23
+ return trim(out[0]);
24
+ }
25
+
26
+ # --- Main Script ---
27
+
28
+ teamfile = "examples/n8n/n8n-team.lmctl";
29
+ alias = "DigestAgent";
30
+ dry_run = false;
31
+
32
+ if (len(args) > 0) { teamfile = args[0]; }
33
+ if (len(args) > 1) { alias = args[1]; }
34
+ if (contains(args, "--dry-run")) { dry_run = true; }
35
+
36
+ print("=== Scheduled Poll & Batched AI Digest (Shape 3) ===");
37
+ print("Target: " + teamfile + ":" + alias);
38
+ print("");
39
+
40
+ # Step 1: Poll source items (fetch Hacker News top stories or use fallback feeds)
41
+ print("[Step 1: Poll Source] Fetching top items via curl wrapper...");
42
+ hn_ids = curl_fetch_json("https://hacker-news.firebaseio.com/v0/topstories.json");
43
+
44
+ items_to_process = [];
45
+ if (hn_ids != null && type(hn_ids) == "array" && len(hn_ids) > 0) {
46
+ # Take top 3 stories for the batch run
47
+ max_count = min(3, len(hn_ids));
48
+ print(format(" Discovered live feed. Fetching top {0} story details...", max_count));
49
+ for (idx = 0; idx < max_count; idx = idx + 1) {
50
+ id = hn_ids[idx];
51
+ story = curl_fetch_json(format("https://hacker-news.firebaseio.com/v0/item/{0}.json", id));
52
+ if (story != null && has_key(story, "title")) {
53
+ push(items_to_process, {
54
+ "title": story.title,
55
+ "url": get(story, "url", "https://news.ycombinator.com/item?id=" + str(id)),
56
+ "score": get(story, "score", 0)
57
+ });
58
+ }
59
+ }
60
+ }
61
+
62
+ # Fallback dataset if offline or network rate-limited
63
+ if (len(items_to_process) == 0) {
64
+ print(" Using baseline feed items for batch transform...");
65
+ items_to_process = [
66
+ {
67
+ "title": "SQLite release 3.49 introduces enhanced JSONB performance",
68
+ "url": "https://sqlite.org/draft/releaselog/3_49_0.html",
69
+ "score": 412
70
+ },
71
+ {
72
+ "title": "Anthropic publishes model context protocol specification",
73
+ "url": "https://www.anthropic.com/news/model-context-protocol",
74
+ "score": 689
75
+ },
76
+ {
77
+ "title": "Zero-dependency CLI architectures in modern systems engineering",
78
+ "url": "https://example.com/blog/zero-dependency-cli",
79
+ "score": 185
80
+ }
81
+ ];
82
+ }
83
+
84
+ print(format(" Processing {0} items in batch transform loop.", len(items_to_process)));
85
+ print("");
86
+
87
+ # Step 2: Batched LLM Transform Loop (n8n SplitInBatches equivalent)
88
+ digest_entries = [];
89
+
90
+ for (i = 0; i < len(items_to_process); i = i + 1) {
91
+ item = items_to_process[i];
92
+ print(format("--- Transforming Item {0}/{1}: \"{2}\"", i + 1, len(items_to_process), item.title));
93
+
94
+ prompt_text = format(
95
+ "You are a technical news analyst preparing an executive briefing.\n" +
96
+ "Article Title: {0}\n" +
97
+ "URL: {1}\n" +
98
+ "Upvotes/Score: {2}\n\n" +
99
+ "Task: Provide a 1-sentence analytical summary and assign a topic tag (e.g., #AI, #Database, #Systems, #Security).\n" +
100
+ "Format as: [TAG] <One sentence summary>\n\n" +
101
+ "End your turn with DONE on its own last line.",
102
+ item.title, item.url, str(item.score)
103
+ );
104
+
105
+ res = run_stage(teamfile, alias, "transform_item_" + str(i + 1), prompt_text);
106
+ st = res[0];
107
+ reply_obj = res[1];
108
+
109
+ if (needs_human(st)) {
110
+ print("Batch item transformation failed. Stopping batch.");
111
+ lm_exit(1);
112
+ }
113
+
114
+ raw_reply = reply_obj;
115
+ if (type(reply_obj) == "object" && has_key(reply_obj, "reply")) {
116
+ raw_reply = reply_obj.reply;
117
+ }
118
+
119
+ # Clean summary line
120
+ sum_lines = lines(trim(raw_reply));
121
+ clean_summary = "";
122
+ for (line_idx = 0; line_idx < len(sum_lines); line_idx = line_idx + 1) {
123
+ curr_line = trim(sum_lines[line_idx]);
124
+ if (curr_line != "DONE" && len(curr_line) > 0) {
125
+ clean_summary = curr_line;
126
+ break;
127
+ }
128
+ }
129
+
130
+ push(digest_entries, format("- **[{0}]({1})** ({2} pts)\n {3}", item.title, item.url, str(item.score), clean_summary));
131
+ }
132
+
133
+ # Step 3: Aggregate into formatted Markdown Digest
134
+ print("");
135
+ print("[Step 3: Aggregate & Publish] Assembling daily digest...");
136
+
137
+ digest_content = "# Daily Engineering & AI Intelligence Digest\n\n" +
138
+ "*Automated aggregation via LMScript (n8n Shape 3 pattern)*\n\n" +
139
+ "### Top Stories & Analysis\n\n" +
140
+ join(digest_entries, "\n\n") + "\n\n" +
141
+ "---\n*Generated at unix epoch: " + str(clock()) + "*\n";
142
+
143
+ digest_file = "examples/n8n/daily-digest.md";
144
+ write_file(digest_file, digest_content);
145
+ print(" Saved consolidated digest to " + digest_file);
146
+ print("");
147
+
148
+ # Step 4: Dispatch notification
149
+ if (dry_run) {
150
+ print("[Step 4: Notify] [dry-run] Would POST digest to Slack webhook endpoint.");
151
+ } else {
152
+ print("[Step 4: Notify] Sending notification to webhook endpoint via curl...");
153
+ webhook_payload = json_stringify({ "text": digest_content });
154
+ status = curl_post_webhook("https://hooks.slack.com/services/mock/endpoint", webhook_payload);
155
+ print(" Webhook dispatch returned HTTP status: " + status);
156
+ }
157
+
158
+ print("");
159
+ print("Digest pipeline complete.");
@@ -0,0 +1,163 @@
1
+ # rag-search.lms -- n8n Conversion: Document Ingestion & Vector RAG Pipeline
2
+ # Represents Shape 4: Document Ingestion & RAG (Chunk -> Embed -> Vector Store -> Top-k Retrieval -> Augmented LLM)
3
+ #
4
+ # Usage:
5
+ # node dist/cli/index.js script examples/n8n/rag-search.lms [teamfile] [alias]
6
+
7
+ import "./agent-lib.lms";
8
+
9
+ # --- External Embedding & Vector Wrappers over system() ---
10
+
11
+ fn curl_get_openai_embedding(text, api_key) {
12
+ if (len(api_key) == 0) {
13
+ return { "error": "MISSING_API_KEY", "vector": [] };
14
+ }
15
+ payload = json_stringify({
16
+ "input": text,
17
+ "model": "text-embedding-3-small"
18
+ });
19
+ cmd = format("curl -s https://api.openai.com/v1/embeddings -H \"Authorization: Bearer {0}\" -H \"Content-Type: application/json\" -d '{1}'", api_key, payload);
20
+ out = system(cmd, 15000);
21
+ if (out[2] != 0 || len(trim(out[0])) == 0) {
22
+ return { "error": "CURL_FAILED", "details": trim(out[1]), "vector": [] };
23
+ }
24
+ res = json_parse(trim(out[0]));
25
+ if (res == null || !has_key(res, "data")) {
26
+ return { "error": "API_ERROR", "details": trim(out[0]), "vector": [] };
27
+ }
28
+ return { "error": null, "vector": res.data[0].embedding };
29
+ }
30
+
31
+ # Linear algebra vector math in LMScript
32
+ fn cosine_similarity(v1, v2) {
33
+ if (len(v1) != len(v2) || len(v1) == 0) { return 0.0; }
34
+ dot = 0.0;
35
+ norm_a = 0.0;
36
+ norm_b = 0.0;
37
+ for (i = 0; i < len(v1); i = i + 1) {
38
+ dot = dot + (v1[i] * v2[i]);
39
+ norm_a = norm_a + (v1[i] * v1[i]);
40
+ norm_b = norm_b + (v2[i] * v2[i]);
41
+ }
42
+ denom = sqrt(norm_a) * sqrt(norm_b);
43
+ if (denom == 0.0) { return 0.0; }
44
+ return dot / denom;
45
+ }
46
+
47
+ # Document chunking primitive
48
+ fn chunk_text_by_paragraphs(doc_text) {
49
+ raw_paras = split(doc_text, "\n\n");
50
+ chunks = [];
51
+ for (i = 0; i < len(raw_paras); i = i + 1) {
52
+ p = trim(raw_paras[i]);
53
+ if (len(p) > 20) {
54
+ push(chunks, p);
55
+ }
56
+ }
57
+ return chunks;
58
+ }
59
+
60
+ # --- Main Script ---
61
+
62
+ teamfile = "examples/n8n/n8n-team.lmctl";
63
+ alias = "RagAgent";
64
+ if (len(args) > 0) { teamfile = args[0]; }
65
+ if (len(args) > 1) { alias = args[1]; }
66
+
67
+ # Check for API key in environment
68
+ api_key = "";
69
+ env_key = system("echo -n \"$OPENAI_API_KEY\"");
70
+ if (len(trim(env_key[0])) > 0) {
71
+ api_key = trim(env_key[0]);
72
+ }
73
+
74
+ sample_doc = "# Antigravity Architecture Guide\n\n" +
75
+ "Antigravity uses a three-layer agent architecture: immutable role prompt, disposable session, and canonical durable-memory.\n\n" +
76
+ "The command-line interface lmctl is strictly stateless. Persistent daemon processes, time-series metrics, and background mail relays belong to the sibling tool lmbee.\n\n" +
77
+ "LMScript is an embedded scripting language executed via lmctl script. It provides core standard functions and lmctl orchestration host functions like lm_prompt and lm_members.\n\n" +
78
+ "Worktrees are used for isolated experimental branches. Bare git push is deliberately prevented on experimental branches until changes are reviewed and verified.";
79
+
80
+ question = "Where do persistent background daemons and time-series metrics belong?";
81
+
82
+ print("=== Document Ingestion & Vector RAG Pipeline (Shape 4) ===");
83
+ print("Target: " + teamfile + ":" + alias);
84
+ print("Question: \"" + question + "\"");
85
+ print("");
86
+
87
+ # Step 1: Document Chunking
88
+ print("[Step 1: Chunking] Splitting document into semantic chunks...");
89
+ chunks = chunk_text_by_paragraphs(sample_doc);
90
+ print(format(" Generated {0} text chunks.", len(chunks)));
91
+ print("");
92
+
93
+ # Step 2: Vector Embedding Generation via external curl wrapper
94
+ print("[Step 2: Vector Embeddings] Attempting to compute embeddings via curl_get_openai_embedding()...");
95
+ emb_res = curl_get_openai_embedding(chunks[0], api_key);
96
+
97
+ retrieved_context = "";
98
+
99
+ if (emb_res.error != null) {
100
+ print(" External embedding call result: " + emb_res.error);
101
+ if (emb_res.error == "MISSING_API_KEY") {
102
+ print(" Notice: OPENAI_API_KEY is not set in environment.");
103
+ }
104
+ print(" [Fallback] Demonstrating lexical retrieval fallback because vector embeddings failed...");
105
+ # Fallback lexical similarity
106
+ best_match = "";
107
+ for (c_idx = 0; c_idx < len(chunks); c_idx = c_idx + 1) {
108
+ chk = chunks[c_idx];
109
+ if (contains(chk, "daemon") || contains(chk, "metrics")) {
110
+ best_match = chk;
111
+ break;
112
+ }
113
+ }
114
+ retrieved_context = best_match;
115
+ } else {
116
+ print(" Vector embedding computed successfully. Vector dimension: " + str(len(emb_res.vector)));
117
+ # Vector retrieval path
118
+ q_emb = curl_get_openai_embedding(question, api_key);
119
+ best_score = -1.0;
120
+ best_chunk = chunks[0];
121
+ for (c_idx = 0; c_idx < len(chunks); c_idx = c_idx + 1) {
122
+ c_emb = curl_get_openai_embedding(chunks[c_idx], api_key);
123
+ score = cosine_similarity(q_emb.vector, c_emb.vector);
124
+ if (score > best_score) {
125
+ best_score = score;
126
+ best_chunk = chunks[c_idx];
127
+ }
128
+ }
129
+ print(format(" Top vector similarity score: {0}", best_score));
130
+ retrieved_context = best_chunk;
131
+ }
132
+
133
+ print("");
134
+ print("--- Retrieved Context Chunk ---");
135
+ print(retrieved_context);
136
+ print("");
137
+
138
+ # Step 3: Grounded Generation (Augmented Prompt)
139
+ print("[Step 3: Grounded Generation] Calling agent with retrieved context...");
140
+ rag_prompt = "You are a factual documentation assistant. Answer the user question strictly using the provided context.\n\n" +
141
+ "Context:\n\"" + retrieved_context + "\"\n\n" +
142
+ "Question: \"" + question + "\"\n\n" +
143
+ "Answer concisely and cite the context. End your turn with DONE on its own last line.";
144
+
145
+ res = run_stage(teamfile, alias, "grounded_qa", rag_prompt);
146
+ st = res[0];
147
+ reply_obj = res[1];
148
+
149
+ if (needs_human(st)) {
150
+ print("Grounded QA needs human assistance.");
151
+ lm_exit(1);
152
+ }
153
+
154
+ reply_text = reply_obj;
155
+ if (type(reply_obj) == "object" && has_key(reply_obj, "reply")) {
156
+ reply_text = reply_obj.reply;
157
+ }
158
+
159
+ print("");
160
+ print("--- Agent Response ---");
161
+ print(reply_text);
162
+ print("");
163
+ print("RAG workflow complete.");
@@ -0,0 +1,88 @@
1
+ # support-agent.lms -- n8n Conversion: Tool-Using Support Agent Loop
2
+ # Represents Shape 2: Conversational Trigger -> ReAct Agent Loop (Memory + Dynamic Tools) -> Response
3
+ #
4
+ # Usage:
5
+ # node dist/cli/index.js script examples/n8n/support-agent.lms [teamfile] [alias]
6
+
7
+ import "./agent-lib.lms";
8
+
9
+ # --- External Tool Wrappers over system() ---
10
+
11
+ fn tool_sqlite_query(db_path, sql) {
12
+ cmd = format("sqlite3 -batch -json \"{0}\" \"{1}\" 2>&1", db_path, sql);
13
+ out = system(cmd);
14
+ if (out[2] != 0) {
15
+ return "Error executing query: " + trim(out[1]);
16
+ }
17
+ return trim(out[0]);
18
+ }
19
+
20
+ fn tool_search_kb(keyword, doc_dir) {
21
+ cmd = format("grep -rn -i -m 5 \"{0}\" \"{1}\" 2>/dev/null", keyword, doc_dir);
22
+ out = system(cmd);
23
+ return trim(out[0]);
24
+ }
25
+
26
+ fn tool_http_ping(host) {
27
+ cmd = format("curl -s -o /dev/null -w \"%{http_code}\" --connect-timeout 2 \"{0}\"", host);
28
+ out = system(cmd);
29
+ return trim(out[0]);
30
+ }
31
+
32
+ # --- Setup Mock Environment for the Agent's Tools ---
33
+
34
+ mock_db = "examples/n8n/mock-support.db";
35
+ # Ensure DB exists with sample schema
36
+ init_sql = "CREATE TABLE IF NOT EXISTS orders (order_id TEXT PRIMARY KEY, customer_id TEXT, status TEXT, total REAL, item TEXT);" +
37
+ "INSERT OR REPLACE INTO orders VALUES ('ORD-9021', 'CUST-104', 'Shipped - In Transit', 85.00, 'Mechanical Keyboard');" +
38
+ "INSERT OR REPLACE INTO orders VALUES ('ORD-9022', 'CUST-208', 'Pending Fulfillment', 24.50, 'USB-C Cable Pack');";
39
+ system(format("sqlite3 \"{0}\" \"{1}\"", mock_db, init_sql));
40
+
41
+ # --- Main Script ---
42
+
43
+ teamfile = "examples/n8n/n8n-team.lmctl";
44
+ alias = "SupportAgent";
45
+ if (len(args) > 0) { teamfile = args[0]; }
46
+ if (len(args) > 1) { alias = args[1]; }
47
+
48
+ customer_inquiry = "Customer CUST-104: Hi, can you check the status of my order ORD-9021? Also verify what item I ordered and the amount billed.";
49
+
50
+ print("=== Conversational Support Agent with Dynamic Tools (Shape 2) ===");
51
+ print("Target: " + teamfile + ":" + alias);
52
+ print("Inquiry: " + customer_inquiry);
53
+ print("");
54
+
55
+ # Step 1: Execute tool lookup using external wrapper
56
+ print("[Tool Action] Executing local database lookup via tool_sqlite_query()...");
57
+ db_result = tool_sqlite_query(mock_db, "SELECT * FROM orders WHERE customer_id='CUST-104' OR order_id='ORD-9021';");
58
+ print(" Tool Observation: " + db_result);
59
+ print("");
60
+
61
+ # Step 2: Dispatch turn to agent with customer inquiry and injected tool observation
62
+ agent_prompt = "You are a Tier-1 Customer Support Specialist with access to internal database tools.\n" +
63
+ "Customer Inquiry:\n\"" + customer_inquiry + "\"\n\n" +
64
+ "Internal Database Tool Lookup Result:\n" + db_result + "\n\n" +
65
+ "Instructions:\n" +
66
+ "1. Provide a polite, professional, and accurate response to the customer using the tool observation.\n" +
67
+ "2. State the exact order status, item purchased, and total billed.\n" +
68
+ "3. End your turn with DONE on its own last line.";
69
+
70
+ res = run_stage(teamfile, alias, "support_resolution", agent_prompt);
71
+ st = res[0];
72
+ reply_obj = res[1];
73
+
74
+ if (needs_human(st)) {
75
+ print("Support turn needs human attention. Handing off.");
76
+ lm_exit(1);
77
+ }
78
+
79
+ reply_text = reply_obj;
80
+ if (type(reply_obj) == "object" && has_key(reply_obj, "reply")) {
81
+ reply_text = reply_obj.reply;
82
+ }
83
+
84
+ print("");
85
+ print("--- Final Customer Resolution ---");
86
+ print(reply_text);
87
+ print("");
88
+ print("Support agent workflow complete.");
@@ -0,0 +1,156 @@
1
+ # ticket-triage.lms -- n8n Conversion: Inbound Ticket / Email Triager & Router
2
+ # Represents Shape 1: Event Trigger -> LLM Classify & Extract -> Branch -> Action
3
+ #
4
+ # Usage:
5
+ # node dist/cli/index.js script examples/n8n/ticket-triage.lms [teamfile] [alias] [ticket_file] [--dry-run]
6
+
7
+ import "./agent-lib.lms";
8
+
9
+ # --- External Service Wrappers over system() ---
10
+
11
+ fn gh_create_issue(repo, title, body, label) {
12
+ cmd = format("gh issue create -R \"{0}\" --title \"{1}\" --body \"{2}\" --label \"{3}\" 2>&1", repo, title, body, label);
13
+ out = system(cmd);
14
+ return [out[2], trim(out[0])];
15
+ }
16
+
17
+ fn post_webhook(url, payload_json) {
18
+ cmd = format("curl -s -o /dev/null -w \"%{http_code}\" -X POST -H \"Content-Type: application/json\" -d '{0}' \"{1}\"", payload_json, url);
19
+ out = system(cmd);
20
+ return trim(out[0]);
21
+ }
22
+
23
+ fn append_triage_log(log_path, record_json) {
24
+ return append_file(log_path, record_json + "\n");
25
+ }
26
+
27
+ # --- Main Script ---
28
+
29
+ teamfile = "examples/n8n/n8n-team.lmctl";
30
+ alias = "TriageAgent";
31
+ ticket_file = "";
32
+ dry_run = false;
33
+
34
+ if (len(args) > 0) { teamfile = args[0]; }
35
+ if (len(args) > 1) { alias = args[1]; }
36
+ if (len(args) > 2) { ticket_file = args[2]; }
37
+ if (contains(args, "--dry-run")) { dry_run = true; }
38
+
39
+ # Sample payload if no file provided
40
+ ticket_text = "Subject: Urgent: Database connection pool exhausted in production\n" +
41
+ "From: ops@example.com\n" +
42
+ "Body: Starting at 02:15 UTC, the main PostgreSQL cluster reached 100% max_connections. Web app is throwing 500 errors on checkout flow. Please investigate immediately.";
43
+
44
+ if (len(ticket_file) > 0 && file_exists(ticket_file)) {
45
+ ticket_text = read_file(ticket_file);
46
+ }
47
+
48
+ print("=== Inbound Ticket Triage & Router (Shape 1) ===");
49
+ print("Target: " + teamfile + ":" + alias);
50
+ print("Ticket preview: " + trim(substring(ticket_text, 0, min(80, len(ticket_text)))) + "...");
51
+ print("");
52
+
53
+ triage_prompt = "You are an automated customer support & issue triage router.\n" +
54
+ "Analyze the following incoming ticket and produce structured JSON classification.\n\n" +
55
+ "Incoming Ticket:\n" + ticket_text + "\n\n" +
56
+ "Respond with ONLY a valid JSON object matching this schema (no markdown fences, no extra text):\n" +
57
+ "{\n" +
58
+ " \"category\": \"bug\" | \"security\" | \"billing\" | \"feature\" | \"ops\",\n" +
59
+ " \"urgency\": 1 to 5,\n" +
60
+ " \"summary\": \"one-sentence summary\",\n" +
61
+ " \"recommended_action\": \"action description\"\n" +
62
+ "}\n\n" +
63
+ "End your turn with DONE on its own last line.";
64
+
65
+ # Reusing agent-lib's run_stage
66
+ res = run_stage(teamfile, alias, "triage_classification", triage_prompt);
67
+ st = res[0];
68
+ reply_obj = res[1];
69
+
70
+ if (needs_human(st)) {
71
+ print("Triage requires human intervention. Halting.");
72
+ lm_exit(1);
73
+ }
74
+
75
+ reply_text = reply_obj;
76
+ if (type(reply_obj) == "object" && has_key(reply_obj, "reply")) {
77
+ reply_text = reply_obj.reply;
78
+ }
79
+
80
+ # Extract JSON from reply (strip state line and optional markdown fences)
81
+ reply_lines = lines(trim(reply_text));
82
+ clean_json_lines = [];
83
+ i = 0;
84
+ while (i < len(reply_lines)) {
85
+ l = trim(reply_lines[i]); i = i + 1;
86
+ if (l == "DONE" || l == "NOTHING_TO_DO" || l == "BLOCKED" || l == "OTHER") { continue; }
87
+ if (starts_with(l, "```")) { continue; }
88
+ push(clean_json_lines, l);
89
+ }
90
+ clean_json_text = join(clean_json_lines, "\n");
91
+
92
+ triage = json_parse(clean_json_text);
93
+ if (triage == null) {
94
+ print("Failed to parse LLM structured triage output. Raw output:");
95
+ print(clean_json_text);
96
+ lm_exit(1);
97
+ }
98
+
99
+ category = triage.category;
100
+ urgency = num(triage.urgency);
101
+ summary = triage.summary;
102
+ action = triage.recommended_action;
103
+
104
+ print("");
105
+ print("--- Triage Decision Matrix ---");
106
+ print(" Category: " + category);
107
+ print(" Urgency: " + str(urgency) + "/5");
108
+ print(" Summary: " + summary);
109
+ print(" Action: " + action);
110
+ print("");
111
+
112
+ # Branch 1: High Urgency (>= 4) -> Trigger Webhook Alert
113
+ if (urgency >= 4) {
114
+ print("[Route: High Urgency] Disagreeable or critical issue detected -> Dispatching Alert Webhook...");
115
+ alert_payload = json_stringify({
116
+ "event": "incident_alert",
117
+ "urgency": urgency,
118
+ "summary": summary,
119
+ "ticket": ticket_text
120
+ });
121
+ if (dry_run) {
122
+ print(" [dry-run] Would post alert payload to https://alert.example.com/webhook");
123
+ } else {
124
+ code = post_webhook("https://alert.example.com/webhook", alert_payload);
125
+ print(" Webhook dispatch returned HTTP status: " + code);
126
+ }
127
+ }
128
+
129
+ # Branch 2: Bug or Ops or Security -> File Issue via gh wrapper
130
+ if (category == "bug" || category == "ops" || category == "security") {
131
+ print("[Route: Engineering Ticket] Opening tracking issue via `gh` wrapper...");
132
+ issue_title = "[" + category + "] " + summary;
133
+ issue_body = "Automated Triage from Ticket\n\nUrgency: " + str(urgency) + "\n\n" + ticket_text;
134
+ issue_label = category;
135
+
136
+ if (dry_run) {
137
+ print(" [dry-run] Would execute: gh issue create -R \"example/repo\" --title \"" + issue_title + "\" --label \"" + issue_label + "\"");
138
+ } else {
139
+ gh_res = gh_create_issue("example/repo", issue_title, issue_body, issue_label);
140
+ print(" gh command exit code: " + str(gh_res[0]) + ", output: " + gh_res[1]);
141
+ }
142
+ } else {
143
+ # Branch 3: Billing / Feature -> Append to business queue ledger
144
+ print("[Route: Business Queue] Appending to internal triage ledger...");
145
+ log_entry = json_stringify({
146
+ "timestamp": clock(),
147
+ "category": category,
148
+ "urgency": urgency,
149
+ "summary": summary
150
+ });
151
+ append_triage_log("examples/n8n/triage-ledger.jsonl", log_entry);
152
+ print(" Appended to examples/n8n/triage-ledger.jsonl");
153
+ }
154
+
155
+ print("");
156
+ print("Triage workflow execution complete.");