@muxoai/sdk 1.2.3 → 1.4.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 (208) hide show
  1. package/.agents/plugins/marketplace.json +22 -0
  2. package/.claude-plugin/marketplace.json +32 -0
  3. package/.codex/config.toml +12 -0
  4. package/ARCHITECTURE.md +121 -0
  5. package/README.md +85 -31
  6. package/dist/clerk.d.ts +35 -0
  7. package/dist/clerk.js +201 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +2380 -0
  10. package/dist/composio-catalog.d.ts +234 -0
  11. package/dist/composio-catalog.js +1894 -0
  12. package/dist/config.d.ts +36 -0
  13. package/dist/config.js +115 -0
  14. package/dist/durable-workflow.d.ts +45 -0
  15. package/dist/durable-workflow.js +90 -0
  16. package/dist/engine.d.ts +465 -0
  17. package/dist/engine.js +2560 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.js +7 -0
  20. package/dist/mcp-schema.d.ts +286 -0
  21. package/dist/mcp-schema.js +2559 -0
  22. package/dist/mcp.d.ts +22 -0
  23. package/dist/mcp.js +1356 -0
  24. package/dist/memory-graph.d.ts +21 -0
  25. package/dist/memory-graph.js +173 -0
  26. package/dist/nl.d.ts +34 -0
  27. package/dist/nl.js +756 -0
  28. package/dist/oauth.d.ts +32 -0
  29. package/dist/oauth.js +134 -0
  30. package/dist/policy.d.ts +190 -0
  31. package/dist/policy.js +1597 -0
  32. package/dist/providers/composio-instant.d.ts +18 -0
  33. package/dist/providers/composio-instant.js +1169 -0
  34. package/dist/providers/composio-sdk.d.ts +162 -0
  35. package/dist/providers/composio-sdk.js +1395 -0
  36. package/dist/providers/microsoft-governance.d.ts +152 -0
  37. package/dist/providers/microsoft-governance.js +1062 -0
  38. package/dist/providers/stripe-billing.d.ts +83 -0
  39. package/dist/providers/stripe-billing.js +611 -0
  40. package/dist/providers/stripe-projects.d.ts +508 -0
  41. package/dist/providers/stripe-projects.js +3188 -0
  42. package/dist/providers/supermemory.d.ts +160 -0
  43. package/dist/providers/supermemory.js +778 -0
  44. package/dist/provisioning-managed.d.ts +50 -0
  45. package/dist/provisioning-managed.js +155 -0
  46. package/dist/sdk.d.ts +951 -0
  47. package/dist/sdk.js +748 -0
  48. package/dist/server.d.ts +10 -0
  49. package/dist/server.js +3575 -0
  50. package/dist/store.d.ts +348 -0
  51. package/dist/store.js +2323 -0
  52. package/dist/types.d.ts +593 -0
  53. package/dist/types.js +1 -0
  54. package/dist/ui/console-html.d.ts +64 -0
  55. package/dist/ui/console-html.js +3857 -0
  56. package/dist/ui/design-tokens.d.ts +177 -0
  57. package/dist/ui/design-tokens.js +210 -0
  58. package/dist/version.d.ts +1 -0
  59. package/dist/version.js +1 -0
  60. package/package.json +68 -7
  61. package/plugins/muxo/.app.json +8 -0
  62. package/plugins/muxo/.claude-plugin/plugin.json +16 -0
  63. package/plugins/muxo/.codex-plugin/plugin.json +64 -0
  64. package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
  65. package/plugins/muxo/.mcp.json +8 -0
  66. package/plugins/muxo/assets/logo.png +0 -0
  67. package/plugins/muxo/assets/logo.svg +6 -0
  68. package/plugins/muxo/hooks/hooks.json +27 -0
  69. package/plugins/muxo/hooks/session-start.sh +97 -0
  70. package/plugins/muxo/hooks/user-prompt-submit.sh +58 -0
  71. package/plugins/muxo/mcp.json +28 -0
  72. package/plugins/muxo/plugin.json +116 -0
  73. package/plugins/muxo/skills/muxo/SKILL.md +153 -0
  74. package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
  75. package/plugins/muxo/skills/muxo/references/cli.md +63 -0
  76. package/plugins/muxo/skills/muxo/references/mcp.md +37 -0
  77. package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
  78. package/plugins/muxo/skills/setup/SKILL.md +42 -0
  79. package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
  80. package/src/catalogues/stripe-projects-catalog.json +9972 -0
  81. package/vendor/microsoft-governance/README.md +363 -0
  82. package/vendor/microsoft-governance/dist/audit.d.ts +26 -0
  83. package/vendor/microsoft-governance/dist/audit.d.ts.map +1 -0
  84. package/vendor/microsoft-governance/dist/audit.js +107 -0
  85. package/vendor/microsoft-governance/dist/audit.js.map +1 -0
  86. package/vendor/microsoft-governance/dist/cascade-containment.d.ts +84 -0
  87. package/vendor/microsoft-governance/dist/cascade-containment.d.ts.map +1 -0
  88. package/vendor/microsoft-governance/dist/cascade-containment.js +387 -0
  89. package/vendor/microsoft-governance/dist/cascade-containment.js.map +1 -0
  90. package/vendor/microsoft-governance/dist/client.d.ts +34 -0
  91. package/vendor/microsoft-governance/dist/client.d.ts.map +1 -0
  92. package/vendor/microsoft-governance/dist/client.js +112 -0
  93. package/vendor/microsoft-governance/dist/client.js.map +1 -0
  94. package/vendor/microsoft-governance/dist/context-poisoning.d.ts +58 -0
  95. package/vendor/microsoft-governance/dist/context-poisoning.d.ts.map +1 -0
  96. package/vendor/microsoft-governance/dist/context-poisoning.js +410 -0
  97. package/vendor/microsoft-governance/dist/context-poisoning.js.map +1 -0
  98. package/vendor/microsoft-governance/dist/credential-vault.d.ts +213 -0
  99. package/vendor/microsoft-governance/dist/credential-vault.d.ts.map +1 -0
  100. package/vendor/microsoft-governance/dist/credential-vault.js +567 -0
  101. package/vendor/microsoft-governance/dist/credential-vault.js.map +1 -0
  102. package/vendor/microsoft-governance/dist/discovery.d.ts +80 -0
  103. package/vendor/microsoft-governance/dist/discovery.d.ts.map +1 -0
  104. package/vendor/microsoft-governance/dist/discovery.js +404 -0
  105. package/vendor/microsoft-governance/dist/discovery.js.map +1 -0
  106. package/vendor/microsoft-governance/dist/encryption/channel.d.ts +29 -0
  107. package/vendor/microsoft-governance/dist/encryption/channel.d.ts.map +1 -0
  108. package/vendor/microsoft-governance/dist/encryption/channel.js +78 -0
  109. package/vendor/microsoft-governance/dist/encryption/channel.js.map +1 -0
  110. package/vendor/microsoft-governance/dist/encryption/index.d.ts +9 -0
  111. package/vendor/microsoft-governance/dist/encryption/index.d.ts.map +1 -0
  112. package/vendor/microsoft-governance/dist/encryption/index.js +23 -0
  113. package/vendor/microsoft-governance/dist/encryption/index.js.map +1 -0
  114. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts +267 -0
  115. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts.map +1 -0
  116. package/vendor/microsoft-governance/dist/encryption/mesh-client.js +1001 -0
  117. package/vendor/microsoft-governance/dist/encryption/mesh-client.js.map +1 -0
  118. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts +38 -0
  119. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts.map +1 -0
  120. package/vendor/microsoft-governance/dist/encryption/ratchet.js +223 -0
  121. package/vendor/microsoft-governance/dist/encryption/ratchet.js.map +1 -0
  122. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts +136 -0
  123. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts.map +1 -0
  124. package/vendor/microsoft-governance/dist/encryption/registry-client.js +369 -0
  125. package/vendor/microsoft-governance/dist/encryption/registry-client.js.map +1 -0
  126. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts +80 -0
  127. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts.map +1 -0
  128. package/vendor/microsoft-governance/dist/encryption/x3dh.js +238 -0
  129. package/vendor/microsoft-governance/dist/encryption/x3dh.js.map +1 -0
  130. package/vendor/microsoft-governance/dist/framework-adapter.d.ts +63 -0
  131. package/vendor/microsoft-governance/dist/framework-adapter.d.ts.map +1 -0
  132. package/vendor/microsoft-governance/dist/framework-adapter.js +253 -0
  133. package/vendor/microsoft-governance/dist/framework-adapter.js.map +1 -0
  134. package/vendor/microsoft-governance/dist/identity.d.ts +124 -0
  135. package/vendor/microsoft-governance/dist/identity.d.ts.map +1 -0
  136. package/vendor/microsoft-governance/dist/identity.js +446 -0
  137. package/vendor/microsoft-governance/dist/identity.js.map +1 -0
  138. package/vendor/microsoft-governance/dist/index.d.ts +39 -0
  139. package/vendor/microsoft-governance/dist/index.d.ts.map +1 -0
  140. package/vendor/microsoft-governance/dist/index.js +95 -0
  141. package/vendor/microsoft-governance/dist/index.js.map +1 -0
  142. package/vendor/microsoft-governance/dist/kill-switch.d.ts +22 -0
  143. package/vendor/microsoft-governance/dist/kill-switch.d.ts.map +1 -0
  144. package/vendor/microsoft-governance/dist/kill-switch.js +60 -0
  145. package/vendor/microsoft-governance/dist/kill-switch.js.map +1 -0
  146. package/vendor/microsoft-governance/dist/lifecycle.d.ts +50 -0
  147. package/vendor/microsoft-governance/dist/lifecycle.d.ts.map +1 -0
  148. package/vendor/microsoft-governance/dist/lifecycle.js +113 -0
  149. package/vendor/microsoft-governance/dist/lifecycle.js.map +1 -0
  150. package/vendor/microsoft-governance/dist/mcp.d.ts +41 -0
  151. package/vendor/microsoft-governance/dist/mcp.d.ts.map +1 -0
  152. package/vendor/microsoft-governance/dist/mcp.js +233 -0
  153. package/vendor/microsoft-governance/dist/mcp.js.map +1 -0
  154. package/vendor/microsoft-governance/dist/metrics.d.ts +123 -0
  155. package/vendor/microsoft-governance/dist/metrics.d.ts.map +1 -0
  156. package/vendor/microsoft-governance/dist/metrics.js +289 -0
  157. package/vendor/microsoft-governance/dist/metrics.js.map +1 -0
  158. package/vendor/microsoft-governance/dist/oci-manifest.d.ts +49 -0
  159. package/vendor/microsoft-governance/dist/oci-manifest.d.ts.map +1 -0
  160. package/vendor/microsoft-governance/dist/oci-manifest.js +182 -0
  161. package/vendor/microsoft-governance/dist/oci-manifest.js.map +1 -0
  162. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts +15 -0
  163. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts.map +1 -0
  164. package/vendor/microsoft-governance/dist/policy-backends/cedar.js +88 -0
  165. package/vendor/microsoft-governance/dist/policy-backends/cedar.js.map +1 -0
  166. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts +17 -0
  167. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts.map +1 -0
  168. package/vendor/microsoft-governance/dist/policy-backends/opa.js +74 -0
  169. package/vendor/microsoft-governance/dist/policy-backends/opa.js.map +1 -0
  170. package/vendor/microsoft-governance/dist/policy.d.ts +77 -0
  171. package/vendor/microsoft-governance/dist/policy.d.ts.map +1 -0
  172. package/vendor/microsoft-governance/dist/policy.js +760 -0
  173. package/vendor/microsoft-governance/dist/policy.js.map +1 -0
  174. package/vendor/microsoft-governance/dist/prompt-defense.d.ts +37 -0
  175. package/vendor/microsoft-governance/dist/prompt-defense.d.ts.map +1 -0
  176. package/vendor/microsoft-governance/dist/prompt-defense.js +229 -0
  177. package/vendor/microsoft-governance/dist/prompt-defense.js.map +1 -0
  178. package/vendor/microsoft-governance/dist/protocol-facets.d.ts +87 -0
  179. package/vendor/microsoft-governance/dist/protocol-facets.d.ts.map +1 -0
  180. package/vendor/microsoft-governance/dist/protocol-facets.js +728 -0
  181. package/vendor/microsoft-governance/dist/protocol-facets.js.map +1 -0
  182. package/vendor/microsoft-governance/dist/rings.d.ts +17 -0
  183. package/vendor/microsoft-governance/dist/rings.d.ts.map +1 -0
  184. package/vendor/microsoft-governance/dist/rings.js +61 -0
  185. package/vendor/microsoft-governance/dist/rings.js.map +1 -0
  186. package/vendor/microsoft-governance/dist/sandbox.d.ts +61 -0
  187. package/vendor/microsoft-governance/dist/sandbox.d.ts.map +1 -0
  188. package/vendor/microsoft-governance/dist/sandbox.js +199 -0
  189. package/vendor/microsoft-governance/dist/sandbox.js.map +1 -0
  190. package/vendor/microsoft-governance/dist/surface-parity.d.ts +45 -0
  191. package/vendor/microsoft-governance/dist/surface-parity.d.ts.map +1 -0
  192. package/vendor/microsoft-governance/dist/surface-parity.js +216 -0
  193. package/vendor/microsoft-governance/dist/surface-parity.js.map +1 -0
  194. package/vendor/microsoft-governance/dist/trust.d.ts +28 -0
  195. package/vendor/microsoft-governance/dist/trust.d.ts.map +1 -0
  196. package/vendor/microsoft-governance/dist/trust.js +209 -0
  197. package/vendor/microsoft-governance/dist/trust.js.map +1 -0
  198. package/vendor/microsoft-governance/dist/types.d.ts +422 -0
  199. package/vendor/microsoft-governance/dist/types.d.ts.map +1 -0
  200. package/vendor/microsoft-governance/dist/types.js +29 -0
  201. package/vendor/microsoft-governance/dist/types.js.map +1 -0
  202. package/vendor/microsoft-governance/dist/verify.d.ts +135 -0
  203. package/vendor/microsoft-governance/dist/verify.d.ts.map +1 -0
  204. package/vendor/microsoft-governance/dist/verify.js +356 -0
  205. package/vendor/microsoft-governance/dist/verify.js.map +1 -0
  206. package/vendor/microsoft-governance/package.json +64 -0
  207. package/index.d.ts +0 -177
  208. package/index.js +0 -1
package/dist/nl.js ADDED
@@ -0,0 +1,756 @@
1
+ function extractUrlFromText(text) {
2
+ const fullMatch = text.match(/https?:\/\/[^\s"'<>]+/i);
3
+ if (fullMatch) {
4
+ return fullMatch[0].replace(/[.,;!?)]+$/, "");
5
+ }
6
+ const domainMatch = text.match(/\b((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:ai|com|io|dev|org|net|app|co|xyz)(?:\/[^\s"'<>]*)?)\b/i);
7
+ if (domainMatch && !text.includes(`@${domainMatch[1]}`)) {
8
+ return `https://${domainMatch[1].replace(/[.,;!?)]+$/, "")}`;
9
+ }
10
+ return null;
11
+ }
12
+ function extractEmailFromText(text) {
13
+ const m = text.match(/\b([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})\b/);
14
+ return m ? m[1] : null;
15
+ }
16
+ function extractNumberAfterKeyword(text, keywords, fallback) {
17
+ for (const kw of keywords) {
18
+ const reAfter = new RegExp(`\\b${kw}\\s+(?:of\\s+|to\\s+|=\\s*)?(\\d[\\d,]*)`, "i");
19
+ const m1 = text.match(reAfter);
20
+ if (m1) {
21
+ const n = Number(m1[1].replace(/,/g, ""));
22
+ if (!Number.isNaN(n) && n > 0)
23
+ return n;
24
+ }
25
+ const reBefore = new RegExp(`(\\d[\\d,]*)\\s+${kw}\\b`, "i");
26
+ const m2 = text.match(reBefore);
27
+ if (m2) {
28
+ const n = Number(m2[1].replace(/,/g, ""));
29
+ if (!Number.isNaN(n) && n > 0)
30
+ return n;
31
+ }
32
+ }
33
+ return fallback;
34
+ }
35
+ export function extractParametersFromNaturalLanguage(prompt, tool, explicitInput) {
36
+ const input = { ...(explicitInput || {}) };
37
+ const slug = tool.slug;
38
+ const text = prompt.trim();
39
+ if (slug === "instant.seo.audit") {
40
+ if (!input.url) {
41
+ const url = extractUrlFromText(text);
42
+ if (url)
43
+ input.url = url;
44
+ }
45
+ if (input.checkBrokenLinks === undefined) {
46
+ input.checkBrokenLinks = !/\b(skip|no)\s+broken\s+links\b/i.test(text);
47
+ }
48
+ }
49
+ else if (slug === "instant.web.crawl") {
50
+ if (!input.url) {
51
+ const url = extractUrlFromText(text);
52
+ if (url)
53
+ input.url = url;
54
+ }
55
+ if (input.maxPages === undefined) {
56
+ input.maxPages = extractNumberAfterKeyword(text, ["maxPages", "pages", "limit"], 5);
57
+ }
58
+ if (input.maxDepth === undefined) {
59
+ input.maxDepth = extractNumberAfterKeyword(text, ["maxDepth", "depth"], 2);
60
+ }
61
+ }
62
+ else if (slug === "instant.web.scrape") {
63
+ if (!input.url) {
64
+ const url = extractUrlFromText(text);
65
+ if (url)
66
+ input.url = url;
67
+ }
68
+ if (!input.formats) {
69
+ input.formats = ["markdown"];
70
+ }
71
+ }
72
+ else if (slug === "instant.web.search") {
73
+ if (!input.query) {
74
+ const cleaned = text
75
+ .replace(/^(?:please\s+)?(?:can\s+you\s+)?(?:search\s+(?:the\s+)?web\s+(?:for|about)|search\s+(?:for|about)|find\s+(?:info|information|articles)\s+(?:on|about|for)|google|lookup|look\s+up)\s+/i, "")
76
+ .trim();
77
+ input.query = cleaned || text;
78
+ }
79
+ if (input.numResults === undefined) {
80
+ input.numResults = extractNumberAfterKeyword(text, ["results", "limit", "top"], 5);
81
+ }
82
+ }
83
+ else if (slug === "instant.code.execute" || slug === "instant.composio.workbench") {
84
+ if (!input.language && slug === "instant.code.execute") {
85
+ input.language = /\b(javascript|js|node|typescript|ts)\b/i.test(text)
86
+ ? "javascript"
87
+ : "python";
88
+ }
89
+ const codeBlock = text.match(/```(?:\w+)?\n([\s\S]*?)```/);
90
+ const inlineCode = text.match(/`([^`]+)`/);
91
+ const extractedCode = codeBlock
92
+ ? codeBlock[1].trim()
93
+ : inlineCode
94
+ ? inlineCode[1].trim()
95
+ : text;
96
+ if (slug === "instant.composio.workbench") {
97
+ if (!input.code_to_execute) {
98
+ input.code_to_execute = String(input.code || extractedCode);
99
+ }
100
+ if (!input.thought) {
101
+ input.thought = `Natural language workbench execution: ${text.slice(0, 80)}`;
102
+ }
103
+ }
104
+ else if (!input.code) {
105
+ input.code = extractedCode;
106
+ }
107
+ }
108
+ else if (slug === "instant.github.repo_intel") {
109
+ const repoMatch = text.match(/\b([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)\b/);
110
+ if (repoMatch && !repoMatch[0].includes(".ai") && !repoMatch[0].includes(".com")) {
111
+ if (!input.owner)
112
+ input.owner = repoMatch[1];
113
+ if (!input.repo)
114
+ input.repo = repoMatch[2];
115
+ }
116
+ }
117
+ else if (slug.startsWith("resource.")) {
118
+ if (!input.resource_name && !input.name) {
119
+ const namedMatch = text.match(/\b(?:named|called|name|resource)\s+["']?([a-zA-Z0-9_-]+)["']?/i);
120
+ const defaultPrefix = slug.split(".")[1] || "app";
121
+ const resolvedName = namedMatch ? namedMatch[1] : `${defaultPrefix}-main`;
122
+ input.resource_name = resolvedName;
123
+ }
124
+ else if (input.name && !input.resource_name) {
125
+ input.resource_name = input.name;
126
+ }
127
+ }
128
+ else if (slug === "billing.credits.topup") {
129
+ if (input.credits === undefined) {
130
+ input.credits = extractNumberAfterKeyword(text, ["credits", "credit", "pack", "topup", "top-up", "add"], 1000);
131
+ }
132
+ if (!input.description) {
133
+ input.description = `Natural language top-up: ${text.slice(0, 80)}`;
134
+ }
135
+ }
136
+ else if (slug === "billing.subscription.upgrade") {
137
+ if (!input.tier) {
138
+ input.tier = "starter";
139
+ }
140
+ }
141
+ else if (slug === "billing.checkout.create") {
142
+ if (!input.kind) {
143
+ input.kind = /\b(starter|subscription|upgrade|monthly|plan)\b/i.test(text)
144
+ ? "starter_subscription"
145
+ : "credit_topup";
146
+ }
147
+ }
148
+ else if (slug === "app.gmail.send_email") {
149
+ if (!input.recipient_email) {
150
+ const email = extractEmailFromText(text);
151
+ if (email)
152
+ input.recipient_email = email;
153
+ }
154
+ if (!input.subject) {
155
+ const subjMatch = text.match(/\bsubject\s*[:=]?\s*["']([^"']+)["']|\bsubject\s+([^\n]+?)(?:\s+body\b|\s+saying\b|$)/i);
156
+ input.subject = subjMatch
157
+ ? (subjMatch[1] || subjMatch[2]).trim()
158
+ : "Message from Muxo Agent";
159
+ }
160
+ if (!input.body) {
161
+ const bodyMatch = text.match(/\b(?:body|saying|message)\s*[:=]?\s*["']?([\s\S]+?)["']?$/i);
162
+ input.body = bodyMatch ? bodyMatch[1].trim() : text;
163
+ }
164
+ }
165
+ else if (slug === "app.gmail.fetch_emails" || slug === "app.gmail.list_messages") {
166
+ if (!input.query) {
167
+ const qMatch = text.match(/\b(?:matching|query|from|about)\s+["']?([^"'\n]+)["']?/i);
168
+ if (qMatch)
169
+ input.query = qMatch[1].trim();
170
+ }
171
+ if (input.max_results === undefined) {
172
+ input.max_results = extractNumberAfterKeyword(text, ["emails", "messages", "limit", "last"], 10);
173
+ }
174
+ }
175
+ else if (slug === "app.slack.send_message" || slug === "app.slack.post_message") {
176
+ if (!input.channel) {
177
+ const chMatch = text.match(/#([a-zA-Z0-9_-]+)|\bchannel\s+([a-zA-Z0-9_-]+)/i);
178
+ input.channel = chMatch ? chMatch[1] || chMatch[2] : "general";
179
+ }
180
+ if (!input.text) {
181
+ const msgMatch = text.match(/\b(?:saying|message|text)\s*[:=]?\s*["']?([\s\S]+?)["']?$/i);
182
+ input.text = msgMatch ? msgMatch[1].trim() : text;
183
+ }
184
+ }
185
+ else if (slug === "app.github.create_issue" || slug === "app.github.list_pull_requests" || slug === "app.github.list_issues") {
186
+ const repoMatch = text.match(/\b([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)\b/);
187
+ if (repoMatch && !repoMatch[0].includes(".ai") && !repoMatch[0].includes(".com")) {
188
+ if (!input.owner)
189
+ input.owner = repoMatch[1];
190
+ if (!input.repo)
191
+ input.repo = repoMatch[2];
192
+ }
193
+ if (slug === "app.github.create_issue" && !input.title) {
194
+ const titleMatch = text.match(/\b(?:titled|title)\s*[:=]?\s*["']?([^"'\n]+)["']?/i);
195
+ input.title = titleMatch ? titleMatch[1].trim() : text.slice(0, 80);
196
+ }
197
+ }
198
+ else if (slug === "app.notion.search_pages") {
199
+ if (!input.query) {
200
+ const cleaned = text
201
+ .replace(/^(?:search\s+notion\s+(?:pages\s+)?(?:for)?|find\s+in\s+notion)\s*/i, "")
202
+ .trim();
203
+ input.query = cleaned || text;
204
+ }
205
+ }
206
+ else if (slug === "instant.dns.lookup") {
207
+ if (!input.domain) {
208
+ const domainMatch = text.match(/\b((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:ai|com|io|dev|org|net|app|co|xyz))\b/i);
209
+ if (domainMatch) {
210
+ input.domain = domainMatch[1].toLowerCase();
211
+ }
212
+ else if (typeof input.hostname === "string") {
213
+ input.domain = input.hostname;
214
+ }
215
+ }
216
+ if (!input.type) {
217
+ const typeMatch = text.match(/\b(AAAA|CNAME|TXT|MX|NS|A)\b/i);
218
+ input.type = typeMatch ? typeMatch[1].toUpperCase() : "A";
219
+ }
220
+ }
221
+ else if (slug === "instant.hackernews.top_stories") {
222
+ if (input.limit === undefined) {
223
+ input.limit = extractNumberAfterKeyword(text, ["top", "stories", "items", "limit", "posts"], 5);
224
+ }
225
+ }
226
+ else if (slug === "app.jira.create_issue") {
227
+ if (!input.project_key) {
228
+ const projMatch = text.match(/\bproject\s+([A-Z][A-Z0-9]{1,9})\b|\b([A-Z]{2,8})-\d+\b/);
229
+ input.project_key = projMatch ? projMatch[1] || projMatch[2] : "ENG";
230
+ }
231
+ if (!input.summary) {
232
+ const sumMatch = text.match(/\b(?:summary|titled|title)\s*[:=]?\s*["']?([^"'\n]+)["']?/i);
233
+ input.summary = sumMatch ? sumMatch[1].trim() : text.slice(0, 80);
234
+ }
235
+ if (!input.issue_type)
236
+ input.issue_type = "Task";
237
+ }
238
+ else if (slug === "app.linear.create_issue") {
239
+ if (!input.team_id) {
240
+ const teamMatch = text.match(/\bteam\s+["']?([a-zA-Z0-9_-]+)["']?/i);
241
+ input.team_id = teamMatch ? teamMatch[1] : "ENG";
242
+ }
243
+ if (!input.title) {
244
+ const titleMatch = text.match(/\b(?:titled|title)\s*[:=]?\s*["']?([^"'\n]+)["']?/i);
245
+ input.title = titleMatch ? titleMatch[1].trim() : text.slice(0, 80);
246
+ }
247
+ }
248
+ else if (slug === "app.googlecalendar.list_events") {
249
+ if (!input.calendarId)
250
+ input.calendarId = "primary";
251
+ if (input.maxResults === undefined) {
252
+ input.maxResults = extractNumberAfterKeyword(text, ["events", "meetings", "limit", "next"], 10);
253
+ }
254
+ }
255
+ else if (slug === "app.hubspot.search_contacts") {
256
+ if (!input.query) {
257
+ const cleaned = text.replace(/^(?:search\s+hubspot\s+(?:contacts\s+)?(?:for)?|find\s+contact)\s*/i, "").trim();
258
+ input.query = cleaned || text;
259
+ }
260
+ if (input.limit === undefined)
261
+ input.limit = 10;
262
+ }
263
+ else if (slug === "app.discord.send_message") {
264
+ if (!input.channel_id) {
265
+ const chMatch = text.match(/#([a-zA-Z0-9_-]+)|\bchannel\s+([a-zA-Z0-9_-]+)/i);
266
+ input.channel_id = chMatch ? chMatch[1] || chMatch[2] : "general";
267
+ }
268
+ if (!input.content) {
269
+ const msgMatch = text.match(/\b(?:saying|message|text|content)\s*[:=]?\s*["']?([\s\S]+?)["']?$/i);
270
+ input.content = msgMatch ? msgMatch[1].trim() : text;
271
+ }
272
+ }
273
+ else if (slug === "app.googledrive.search_files") {
274
+ if (!input.query) {
275
+ const cleaned = text.replace(/^(?:search\s+(?:google\s+)?drive\s+(?:files\s+)?(?:for)?)\s*/i, "").trim();
276
+ input.query = cleaned || text;
277
+ }
278
+ }
279
+ else if (slug === "app.airtable.list_records") {
280
+ if (!input.base_id) {
281
+ const baseMatch = text.match(/\b(app[a-zA-Z0-9]{10,})\b/);
282
+ input.base_id = baseMatch ? baseMatch[1] : "appDefaultBase";
283
+ }
284
+ if (!input.table_name) {
285
+ const tblMatch = text.match(/\btable\s+["']?([a-zA-Z0-9_-]+)["']?/i);
286
+ input.table_name = tblMatch ? tblMatch[1] : "Tasks";
287
+ }
288
+ }
289
+ else if (slug === "app.salesforce.query_records" || slug === "app.salesforce.soql_query") {
290
+ if (!input.query) {
291
+ const soqlMatch = text.match(/\b(SELECT\s+[\s\S]+)$/i);
292
+ input.query = soqlMatch ? soqlMatch[1].trim() : "SELECT Id, Name, Email FROM Contact LIMIT 10";
293
+ }
294
+ }
295
+ else if (slug === "app.pagerduty.create_incident") {
296
+ if (!input.title)
297
+ input.title = text.slice(0, 80);
298
+ if (!input.service_id)
299
+ input.service_id = "PDEFAULT";
300
+ }
301
+ else if (slug === "billing.stripe.refund") {
302
+ if (!input.paymentIntentId) {
303
+ const piMatch = text.match(/\b(pi_[a-zA-Z0-9_]+|ch_[a-zA-Z0-9_]+)\b/);
304
+ if (piMatch)
305
+ input.paymentIntentId = piMatch[1];
306
+ }
307
+ if (input.amountCents === undefined) {
308
+ const dollarMatch = text.match(/\$(\d+(?:\.\d{1,2})?)/);
309
+ if (dollarMatch)
310
+ input.amountCents = Math.round(parseFloat(dollarMatch[1]) * 100);
311
+ }
312
+ }
313
+ const schemaReq = Array.isArray(tool.inputSchema?.required)
314
+ ? tool.inputSchema.required
315
+ : [];
316
+ const missingInputs = schemaReq.filter((k) => input[k] === undefined || input[k] === null || input[k] === "");
317
+ return { input, missingInputs };
318
+ }
319
+ function scoreToolForPrompt(prompt, tool) {
320
+ const q = prompt.trim().toLowerCase();
321
+ if (!q)
322
+ return 0;
323
+ if (q === tool.slug.toLowerCase() || q === tool.upstreamSlug.toLowerCase()) {
324
+ return 1000;
325
+ }
326
+ let score = 0;
327
+ const slug = tool.slug.toLowerCase();
328
+ // High-signal intent rules
329
+ if (/\b(seo|meta\s+tag|open\s*graph|json-ld|jsonld|canonical|heading\s+hierarchy|audit\s+site|audit\s+page|seo\s+audit)\b/i.test(q)) {
330
+ if (slug === "instant.seo.audit")
331
+ score += 120;
332
+ }
333
+ if (/\b(crawl|spider|multi-page|sitemap|discover\s+links|all\s+pages)\b/i.test(q)) {
334
+ if (slug === "instant.web.crawl")
335
+ score += 110;
336
+ }
337
+ if (/\b(scrape|extract\s+markdown|fetch\s+page|read\s+url|read\s+webpage|scrape\s+url)\b/i.test(q)) {
338
+ if (slug === "instant.web.scrape")
339
+ score += 110;
340
+ }
341
+ const isExplicitWebSearch = /\b(search\s+(?:the\s+)?web|web\s+search|search\s+online|search\s+(?:for|about)|look\s+up|find\s+(?:news|info|information|articles)|exa|google)\b/i.test(q);
342
+ const hasProvisionVerb = /\b(provision|create|deploy|spin\s+up|setup|set\s+up|add\s+resource|new\s+db|new\s+database|database|db)\b/i.test(q);
343
+ if (isExplicitWebSearch) {
344
+ if (slug === "instant.web.search")
345
+ score += 155;
346
+ }
347
+ if (/\b(run\s+python|execute\s+code|run\s+script|sandbox|workbench|calculate|e2b)\b/i.test(q)) {
348
+ if (slug === "instant.code.execute" || slug === "instant.composio.workbench")
349
+ score += 125;
350
+ }
351
+ if (/\b(repo\s+intel|github\s+repo|inspect\s+repo|repository\s+intel|stars\s+and\s+forks)\b/i.test(q)) {
352
+ if (slug === "instant.github.repo_intel")
353
+ score += 135;
354
+ }
355
+ if (/\b(top\s*up|add\s+credits|buy\s+credits|refill\s+credits|more\s+credits|\d+\s+credits)\b/i.test(q)) {
356
+ if (slug === "billing.credits.topup")
357
+ score += 130;
358
+ }
359
+ if (/\b(upgrade\s+to\s+starter|upgrade\s+plan|starter\s+plan|starter\s+tier|upgrade\s+subscription|upgrade\s+workspace)\b/i.test(q)) {
360
+ if (slug === "billing.subscription.upgrade")
361
+ score += 130;
362
+ }
363
+ if (/\b(stripe\s+checkout|checkout\s+session|payment\s+link|billing\s+link)\b/i.test(q)) {
364
+ if (slug === "billing.checkout.create")
365
+ score += 125;
366
+ }
367
+ if (/\b(refund|chargeback|pi_[a-z0-9_]+)\b/i.test(q)) {
368
+ if (slug === "billing.stripe.refund" || slug === "app.shopify.create_refund")
369
+ score += 130;
370
+ }
371
+ if (!isExplicitWebSearch || hasProvisionVerb) {
372
+ if (/\b(turso|libsql|sqlite\s+database|sqlite\s+db)\b/i.test(q)) {
373
+ if (slug.startsWith("resource.turso."))
374
+ score += 120;
375
+ if (slug.includes("database"))
376
+ score += 15;
377
+ }
378
+ if (/\b(neon|postgres|postgresql|pg\s+database)\b/i.test(q)) {
379
+ if (slug.startsWith("resource.neon."))
380
+ score += 120;
381
+ }
382
+ if (/\b(upstash|redis|cache\s+store|kv\s+store)\b/i.test(q)) {
383
+ if (slug.startsWith("resource.upstash."))
384
+ score += 120;
385
+ }
386
+ if (/\b(supabase)\b/i.test(q)) {
387
+ if (slug.startsWith("resource.supabase."))
388
+ score += 120;
389
+ }
390
+ if (/\b(mongodb|mongo)\b/i.test(q)) {
391
+ if (slug.startsWith("resource.mongodb."))
392
+ score += 120;
393
+ }
394
+ if (/\b(cloudflare\s+worker|d1\s+database|r2\s+storage)\b/i.test(q)) {
395
+ if (slug.startsWith("resource.cloudflare."))
396
+ score += 120;
397
+ }
398
+ if (/\b(vercel\s+project|deploy\s+vercel)\b/i.test(q)) {
399
+ if (slug.startsWith("resource.vercel."))
400
+ score += 120;
401
+ }
402
+ if (/\b(resend\s+email|transactional\s+email\s+api)\b/i.test(q)) {
403
+ if (slug.startsWith("resource.resend."))
404
+ score += 120;
405
+ }
406
+ if (/\b(clerk\s+auth)\b/i.test(q)) {
407
+ if (slug.startsWith("resource.clerk."))
408
+ score += 120;
409
+ }
410
+ if (/\b(workos|enterprise\s+sso|scim)\b/i.test(q)) {
411
+ if (slug.startsWith("resource.workos."))
412
+ score += 120;
413
+ }
414
+ }
415
+ if (/\b(hacker\s*news|hn\s+stories|top\s+stories)\b/i.test(q)) {
416
+ if (slug === "instant.hackernews.top_stories")
417
+ score += 125;
418
+ }
419
+ if (/\b(dns|doh|txt\s+records?|mx\s+records?|a\s+records?|cname|nameserver|lookup\s+dns|check\s+dns)\b/i.test(q)) {
420
+ if (slug === "instant.dns.lookup")
421
+ score += 135;
422
+ }
423
+ if (/\b(send\s+an?\s+email|send\s+email|email\s+to|compose\s+email)\b/i.test(q)) {
424
+ if (slug === "app.gmail.send_email")
425
+ score += 120;
426
+ }
427
+ if (/\b(list\s+emails|read\s+emails|check\s+inbox|recent\s+emails|list\s+messages|fetch\s+emails|gmail\s+inbox)\b/i.test(q)) {
428
+ if (slug === "app.gmail.fetch_emails" || slug === "app.gmail.list_messages")
429
+ score += 115;
430
+ }
431
+ if (/\b(post\s+to\s+slack|send\s+slack|slack\s+message|message\s+#)\b/i.test(q)) {
432
+ if (slug === "app.slack.send_message" || slug === "app.slack.post_message")
433
+ score += 120;
434
+ }
435
+ if (/\b(create\s+(?:a\s+)?github\s+issue|open\s+(?:a\s+)?github\s+issue|file\s+an?\s+issue)\b/i.test(q)) {
436
+ if (slug === "app.github.create_issue")
437
+ score += 120;
438
+ }
439
+ if (/\b(list\s+github\s+(?:issues|prs|pull\s+requests)|check\s+github|pull\s+requests)\b/i.test(q)) {
440
+ if (slug === "app.github.list_pull_requests" || slug === "app.github.list_issues")
441
+ score += 110;
442
+ }
443
+ if (/\b(list\s+github\s+repos|github\s+repositories|my\s+repos)\b/i.test(q)) {
444
+ if (slug === "app.github.list_repos")
445
+ score += 120;
446
+ }
447
+ if (/\b(notion\s+page|search\s+notion)\b/i.test(q)) {
448
+ if (slug === "app.notion.search_pages")
449
+ score += 115;
450
+ }
451
+ if (/\b(linear\s+issue|create\s+linear)\b/i.test(q)) {
452
+ if (slug === "app.linear.create_issue")
453
+ score += 115;
454
+ }
455
+ if (/\b(jira\s+issue|create\s+jira|atlassian|jql)\b/i.test(q)) {
456
+ if (slug.startsWith("app.jira."))
457
+ score += 120;
458
+ }
459
+ if (/\b(hubspot|crm\s+contacts?|search\s+contacts?)\b/i.test(q)) {
460
+ if (slug.startsWith("app.hubspot."))
461
+ score += 120;
462
+ }
463
+ if (/\b(discord\s+message|send\s+discord|post\s+to\s+discord)\b/i.test(q)) {
464
+ if (slug.startsWith("app.discord."))
465
+ score += 120;
466
+ }
467
+ if (/\b(google\s+drive|gdrive|drive\s+files?)\b/i.test(q)) {
468
+ if (slug.startsWith("app.googledrive."))
469
+ score += 120;
470
+ }
471
+ if (/\b(airtable|base\s+records?)\b/i.test(q)) {
472
+ if (slug.startsWith("app.airtable."))
473
+ score += 120;
474
+ }
475
+ if (/\b(salesforce|soql|crm\s+records?)\b/i.test(q)) {
476
+ if (slug.startsWith("app.salesforce."))
477
+ score += 120;
478
+ }
479
+ if (/\b(zendesk|support\s+tickets?)\b/i.test(q)) {
480
+ if (slug.startsWith("app.zendesk."))
481
+ score += 120;
482
+ }
483
+ if (/\b(shopify|store\s+orders?)\b/i.test(q)) {
484
+ if (slug.startsWith("app.shopify."))
485
+ score += 120;
486
+ }
487
+ if (/\b(pagerduty|on-call|trigger\s+incident)\b/i.test(q)) {
488
+ if (slug.startsWith("app.pagerduty."))
489
+ score += 120;
490
+ }
491
+ if (/\b(sentry|error\s+issues?|stack\s+traces?)\b/i.test(q)) {
492
+ if (slug.startsWith("app.sentry."))
493
+ score += 120;
494
+ }
495
+ if (/\b(google\s+calendar|schedule\s+meeting|list\s+events|calendar\s+events)\b/i.test(q)) {
496
+ if (slug.includes("calendar") || slug.includes("gcal"))
497
+ score += 110;
498
+ }
499
+ // Generic token overlap fallback
500
+ const haystack = `${tool.slug} ${tool.name} ${tool.description} ${tool.providerSlug} ${(tool.categories || []).join(" ")}`.toLowerCase();
501
+ const tokens = q.split(/[^a-z0-9_.-]+/).filter((t) => t.length >= 2);
502
+ for (const token of tokens) {
503
+ if (slug.includes(token))
504
+ score += 18;
505
+ else if (tool.providerSlug.toLowerCase().includes(token))
506
+ score += 14;
507
+ else if (haystack.includes(token))
508
+ score += 6;
509
+ }
510
+ // If prompt contains a URL and no specific verb was matched, default toward scrape/audit
511
+ if (extractUrlFromText(prompt) && score < 40) {
512
+ if (slug === "instant.web.scrape")
513
+ score += 45;
514
+ if (slug === "instant.seo.audit")
515
+ score += 40;
516
+ if (slug === "instant.web.crawl")
517
+ score += 38;
518
+ }
519
+ return score;
520
+ }
521
+ async function tryByokLlmClassification(params) {
522
+ const openaiKey = params.byokKeys.OPENAI_API_KEY || "";
523
+ const openrouterKey = params.byokKeys.OPENROUTER_API_KEY || "";
524
+ const anthropicKey = params.byokKeys.ANTHROPIC_API_KEY || "";
525
+ if (!openaiKey && !openrouterKey && !anthropicKey) {
526
+ return null;
527
+ }
528
+ const catalogBrief = params.tools
529
+ .slice(0, 35)
530
+ .map((t) => `- ${t.slug} (${t.riskLevel}, ${t.creditCost}cr): ${t.description} | schema keys: ${Object.keys(t.inputSchema?.properties || {}).join(", ")}`)
531
+ .join("\n");
532
+ const systemPrompt = [
533
+ "You are the Muxo Natural Language Intent Router.",
534
+ "Map the user's natural language request to the single best toolSlug from the catalog below and extract its JSON arguments.",
535
+ "Return ONLY valid JSON with shape: {\"toolSlug\": string, \"input\": object, \"reason\": string}.",
536
+ "Catalog:",
537
+ catalogBrief,
538
+ ].join("\n");
539
+ try {
540
+ if (openaiKey || openrouterKey) {
541
+ const isOpenRouter = !openaiKey && Boolean(openrouterKey);
542
+ const endpoint = isOpenRouter
543
+ ? "https://openrouter.ai/api/v1/chat/completions"
544
+ : "https://api.openai.com/v1/chat/completions";
545
+ const res = await fetch(endpoint, {
546
+ method: "POST",
547
+ headers: {
548
+ Authorization: `Bearer ${openaiKey || openrouterKey}`,
549
+ "Content-Type": "application/json",
550
+ },
551
+ body: JSON.stringify({
552
+ model: isOpenRouter ? "openai/gpt-4o-mini" : "gpt-4o-mini",
553
+ temperature: 0,
554
+ response_format: { type: "json_object" },
555
+ messages: [
556
+ { role: "system", content: systemPrompt },
557
+ { role: "user", content: params.prompt },
558
+ ],
559
+ }),
560
+ signal: AbortSignal.timeout(4500),
561
+ });
562
+ if (res.ok) {
563
+ const data = (await res.json());
564
+ const content = data?.choices?.[0]?.message?.content;
565
+ if (typeof content === "string") {
566
+ const parsed = JSON.parse(content);
567
+ if (parsed && typeof parsed.toolSlug === "string") {
568
+ return {
569
+ toolSlug: parsed.toolSlug,
570
+ input: parsed.input && typeof parsed.input === "object"
571
+ ? parsed.input
572
+ : {},
573
+ reason: String(parsed.reason || params.prompt),
574
+ providerUsed: isOpenRouter ? "openrouter" : "openai",
575
+ };
576
+ }
577
+ }
578
+ }
579
+ }
580
+ else if (anthropicKey) {
581
+ const res = await fetch("https://api.anthropic.com/v1/messages", {
582
+ method: "POST",
583
+ headers: {
584
+ "x-api-key": anthropicKey,
585
+ "anthropic-version": "2023-06-01",
586
+ "Content-Type": "application/json",
587
+ },
588
+ body: JSON.stringify({
589
+ model: "claude-3-5-haiku-latest",
590
+ max_tokens: 400,
591
+ system: systemPrompt,
592
+ messages: [{ role: "user", content: params.prompt }],
593
+ }),
594
+ signal: AbortSignal.timeout(4500),
595
+ });
596
+ if (res.ok) {
597
+ const data = (await res.json());
598
+ const text = data?.content?.[0]?.text;
599
+ if (typeof text === "string") {
600
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
601
+ if (jsonMatch) {
602
+ const parsed = JSON.parse(jsonMatch[0]);
603
+ if (parsed && typeof parsed.toolSlug === "string") {
604
+ return {
605
+ toolSlug: parsed.toolSlug,
606
+ input: parsed.input && typeof parsed.input === "object"
607
+ ? parsed.input
608
+ : {},
609
+ reason: String(parsed.reason || params.prompt),
610
+ providerUsed: "anthropic",
611
+ };
612
+ }
613
+ }
614
+ }
615
+ }
616
+ }
617
+ }
618
+ catch {
619
+ // Fall back to deterministic semantic router
620
+ }
621
+ return null;
622
+ }
623
+ export async function resolveNaturalLanguageIntent(params) {
624
+ const prompt = params.prompt.trim();
625
+ const tools = params.tools;
626
+ // 1. Check exact slug match first
627
+ const exactTool = tools.find((t) => t.slug.toLowerCase() === prompt.toLowerCase() ||
628
+ t.upstreamSlug.toLowerCase() === prompt.toLowerCase());
629
+ if (exactTool) {
630
+ const { input, missingInputs } = extractParametersFromNaturalLanguage(prompt, exactTool, params.explicitInput);
631
+ const needsConnection = exactTool.requiresAuth &&
632
+ !(params.activeConnectionProviders?.has(exactTool.providerSlug) ?? false);
633
+ return {
634
+ resolved: true,
635
+ tool: exactTool,
636
+ toolSlug: exactTool.slug,
637
+ input,
638
+ extractedInput: input,
639
+ reason: `Direct execution of ${exactTool.slug}`,
640
+ confidence: 1.0,
641
+ resolutionMethod: "exact_slug",
642
+ byokUsed: null,
643
+ humanSummary: `${exactTool.name} (${exactTool.slug})`,
644
+ missingInputs,
645
+ needsConnection,
646
+ suggestedByokProvider: suggestByokProviderForTool(exactTool),
647
+ alternatives: [],
648
+ };
649
+ }
650
+ // 2. Try BYOK LLM router if a user LLM key is configured in the workspace vault
651
+ if (params.preferByokLlm !== false && params.byokKeys) {
652
+ const llmRes = await tryByokLlmClassification({
653
+ prompt,
654
+ tools,
655
+ byokKeys: params.byokKeys,
656
+ });
657
+ if (llmRes) {
658
+ const matchedTool = tools.find((t) => t.slug.toLowerCase() === llmRes.toolSlug.toLowerCase());
659
+ if (matchedTool) {
660
+ const mergedExplicit = {
661
+ ...llmRes.input,
662
+ ...(params.explicitInput || {}),
663
+ };
664
+ const { input, missingInputs } = extractParametersFromNaturalLanguage(prompt, matchedTool, mergedExplicit);
665
+ const needsConnection = matchedTool.requiresAuth &&
666
+ !(params.activeConnectionProviders?.has(matchedTool.providerSlug) ?? false);
667
+ return {
668
+ resolved: true,
669
+ tool: matchedTool,
670
+ toolSlug: matchedTool.slug,
671
+ input,
672
+ extractedInput: input,
673
+ reason: llmRes.reason || prompt,
674
+ confidence: 0.96,
675
+ resolutionMethod: "byok_llm",
676
+ byokUsed: llmRes.providerUsed,
677
+ humanSummary: `${matchedTool.name} via ${matchedTool.slug}`,
678
+ missingInputs,
679
+ needsConnection,
680
+ suggestedByokProvider: suggestByokProviderForTool(matchedTool),
681
+ alternatives: [],
682
+ };
683
+ }
684
+ }
685
+ }
686
+ // 3. Deterministic Semantic + Regex Router (0 latency, works without LLM API keys)
687
+ const scored = tools
688
+ .map((tool) => ({ tool, score: scoreToolForPrompt(prompt, tool) }))
689
+ .filter((item) => item.score > 0)
690
+ .sort((a, b) => b.score - a.score);
691
+ const best = scored[0]?.tool || null;
692
+ const bestScore = scored[0]?.score || 0;
693
+ const alternatives = scored.slice(1, 5).map((s) => ({
694
+ slug: s.tool.slug,
695
+ name: s.tool.name,
696
+ riskLevel: s.tool.riskLevel,
697
+ creditCost: s.tool.creditCost,
698
+ }));
699
+ if (!best || bestScore < 12) {
700
+ return {
701
+ resolved: false,
702
+ tool: null,
703
+ toolSlug: null,
704
+ input: params.explicitInput || {},
705
+ extractedInput: params.explicitInput || {},
706
+ reason: prompt,
707
+ confidence: 0,
708
+ resolutionMethod: "semantic_router",
709
+ byokUsed: null,
710
+ humanSummary: `Could not confidently match "${prompt}" to a Muxo tool. Try specifying a tool keyword (e.g. "audit seo https://muxo.ai", "search web for AI agents", "top up 1000 credits", "create turso database").`,
711
+ missingInputs: [],
712
+ needsConnection: false,
713
+ suggestedByokProvider: "openai",
714
+ alternatives: tools.slice(0, 5).map((t) => ({
715
+ slug: t.slug,
716
+ name: t.name,
717
+ riskLevel: t.riskLevel,
718
+ creditCost: t.creditCost,
719
+ })),
720
+ };
721
+ }
722
+ const { input, missingInputs } = extractParametersFromNaturalLanguage(prompt, best, params.explicitInput);
723
+ const needsConnection = best.requiresAuth &&
724
+ !(params.activeConnectionProviders?.has(best.providerSlug) ?? false);
725
+ const confidence = Math.min(0.95, Math.round((bestScore / 130) * 100) / 100);
726
+ return {
727
+ resolved: true,
728
+ tool: best,
729
+ toolSlug: best.slug,
730
+ input,
731
+ extractedInput: input,
732
+ reason: prompt,
733
+ confidence,
734
+ resolutionMethod: "semantic_router",
735
+ byokUsed: null,
736
+ humanSummary: `${best.name} (${best.slug})`,
737
+ missingInputs,
738
+ needsConnection,
739
+ suggestedByokProvider: suggestByokProviderForTool(best),
740
+ alternatives,
741
+ };
742
+ }
743
+ function suggestByokProviderForTool(tool) {
744
+ if (tool.slug.startsWith("billing."))
745
+ return "stripe";
746
+ if (tool.lane === "composio_sdk")
747
+ return "composio";
748
+ if (tool.lane === "stripe_projects")
749
+ return "stripe";
750
+ if (tool.slug.includes("scrape") || tool.slug.includes("crawl") || tool.slug.includes("seo")) {
751
+ return "firecrawl";
752
+ }
753
+ if (tool.slug.includes("search"))
754
+ return "exa";
755
+ return "composio";
756
+ }