@muxoai/platform 1.2.3 → 1.3.0
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 +21 -12
- package/dist/cli.js +328 -10
- package/dist/engine.d.ts +28 -0
- package/dist/engine.js +169 -12
- package/dist/mcp.js +14 -6
- package/dist/nl.d.ts +34 -0
- package/dist/nl.js +577 -0
- package/dist/providers/stripe-billing.d.ts +13 -3
- package/dist/providers/stripe-billing.js +240 -36
- package/dist/sdk.d.ts +77 -1
- package/dist/sdk.js +46 -0
- package/dist/server.js +120 -5
- package/dist/store.d.ts +18 -2
- package/dist/store.js +197 -8
- package/dist/types.d.ts +14 -2
- package/dist/ui/console-html.js +216 -26
- package/package.json +1 -1
package/dist/engine.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveNaturalLanguageIntent, } from "./nl.js";
|
|
1
2
|
import { ComposioInstantAdapter } from "./providers/composio-instant.js";
|
|
2
3
|
import { ComposioSdkAdapter } from "./providers/composio-sdk.js";
|
|
3
4
|
import { MicrosoftGovernanceAdapter } from "./providers/microsoft-governance.js";
|
|
@@ -79,6 +80,14 @@ export class MuxoEngine {
|
|
|
79
80
|
}
|
|
80
81
|
if (lane === "all" || lane === "stripe_projects") {
|
|
81
82
|
results.push(...this.stripeProjects.searchTools(query, limit));
|
|
83
|
+
const billingTools = this.stripeBilling.listTools().filter((t) => {
|
|
84
|
+
if (!query)
|
|
85
|
+
return true;
|
|
86
|
+
const q = query.toLowerCase();
|
|
87
|
+
const hay = `${t.slug} ${t.name} ${t.description} ${t.categories.join(" ")}`.toLowerCase();
|
|
88
|
+
return q.split(/\s+/).some((tok) => hay.includes(tok));
|
|
89
|
+
});
|
|
90
|
+
results.push(...billingTools);
|
|
82
91
|
}
|
|
83
92
|
const filtered = params.riskLevel
|
|
84
93
|
? results.filter((t) => t.riskLevel === params.riskLevel)
|
|
@@ -88,9 +97,22 @@ export class MuxoEngine {
|
|
|
88
97
|
total: filtered.length,
|
|
89
98
|
};
|
|
90
99
|
}
|
|
100
|
+
async listAllCatalogTools() {
|
|
101
|
+
const instant = this.composioInstant.searchTools(undefined, 100);
|
|
102
|
+
const sdk = await this.composioSdk.searchTools(undefined, 100);
|
|
103
|
+
const proj = this.stripeProjects.searchTools(undefined, 100);
|
|
104
|
+
const billing = this.stripeBilling.listTools();
|
|
105
|
+
return [...instant, ...billing, ...sdk, ...proj];
|
|
106
|
+
}
|
|
91
107
|
// 4. inspect_tool
|
|
92
108
|
async inspectTool(slug) {
|
|
93
109
|
const normalized = slug.trim();
|
|
110
|
+
const billing = this.stripeBilling
|
|
111
|
+
.listTools()
|
|
112
|
+
.find((t) => t.slug.toLowerCase() === normalized.toLowerCase() ||
|
|
113
|
+
t.upstreamSlug.toLowerCase() === normalized.toLowerCase());
|
|
114
|
+
if (billing)
|
|
115
|
+
return billing;
|
|
94
116
|
const instant = this.composioInstant.inspectTool(normalized);
|
|
95
117
|
if (instant)
|
|
96
118
|
return instant;
|
|
@@ -346,15 +368,40 @@ export class MuxoEngine {
|
|
|
346
368
|
// 7. plan_action
|
|
347
369
|
async planAction(ctx, params) {
|
|
348
370
|
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
349
|
-
|
|
371
|
+
let tool;
|
|
372
|
+
let resolvedInput = { ...(params.input || {}) };
|
|
373
|
+
let resolvedReason = params.reason || `Planned execution of ${params.toolSlug}`;
|
|
374
|
+
try {
|
|
375
|
+
tool = await this.inspectTool(params.toolSlug);
|
|
376
|
+
}
|
|
377
|
+
catch (inspectErr) {
|
|
378
|
+
// Natural-language fallback: if an agent or human passed plain English as toolSlug/instruction, resolve it!
|
|
379
|
+
const nlSource = `${params.toolSlug} ${params.reason || ""}`.trim();
|
|
380
|
+
const allTools = await this.listAllCatalogTools();
|
|
381
|
+
const byokEnv = this.store.getDecryptedWorkspaceEnv(ws.id);
|
|
382
|
+
const nl = await resolveNaturalLanguageIntent({
|
|
383
|
+
prompt: nlSource,
|
|
384
|
+
tools: allTools,
|
|
385
|
+
explicitInput: resolvedInput,
|
|
386
|
+
byokKeys: byokEnv,
|
|
387
|
+
});
|
|
388
|
+
if (!nl.resolved || !nl.tool) {
|
|
389
|
+
throw inspectErr;
|
|
390
|
+
}
|
|
391
|
+
tool = nl.tool;
|
|
392
|
+
resolvedInput = nl.input;
|
|
393
|
+
resolvedReason = params.reason || nl.reason || nlSource;
|
|
394
|
+
}
|
|
395
|
+
const byokActive = this.store.hasByokForLane(ws.id, tool.lane, tool.slug);
|
|
396
|
+
const effectiveCreditCost = byokActive ? 0 : tool.creditCost;
|
|
350
397
|
if (ws.monthlyActionsUsed >= ws.monthlyActionsLimit) {
|
|
351
398
|
throw new Error(`Monthly action limit reached (${ws.monthlyActionsUsed}/${ws.monthlyActionsLimit}). Upgrade to Starter ($29/mo) to unlock 5,000 actions/mo.`);
|
|
352
399
|
}
|
|
353
|
-
if (
|
|
354
|
-
throw new Error(`Insufficient workspace credits for ${tool.slug} (requires ${
|
|
400
|
+
if (effectiveCreditCost > ws.creditsBalance) {
|
|
401
|
+
throw new Error(`Insufficient workspace credits for ${tool.slug} (requires ${effectiveCreditCost}, available ${ws.creditsBalance}). Top up credits or configure a BYOK key.`);
|
|
355
402
|
}
|
|
356
|
-
if (
|
|
357
|
-
throw new Error(`Tool credit cost (${
|
|
403
|
+
if (effectiveCreditCost > ws.policy.maxCreditsPerRun) {
|
|
404
|
+
throw new Error(`Tool credit cost (${effectiveCreditCost}) exceeds workspace policy maxCreditsPerRun (${ws.policy.maxCreditsPerRun}).`);
|
|
358
405
|
}
|
|
359
406
|
// 1. Evaluate Microsoft Agent Governance Pipeline:
|
|
360
407
|
// Agent -> McpSecurityScanner -> PolicyEngine -> AgentIdentity (Ed25519 DID) -> AuditLogger -> DecisionRecord
|
|
@@ -362,14 +409,14 @@ export class MuxoEngine {
|
|
|
362
409
|
workspace: ws,
|
|
363
410
|
actorId: ctx.actorId,
|
|
364
411
|
tool,
|
|
365
|
-
input:
|
|
366
|
-
reason:
|
|
412
|
+
input: resolvedInput,
|
|
413
|
+
reason: resolvedReason,
|
|
367
414
|
});
|
|
368
415
|
if (decisionRecord.verdict === "deny") {
|
|
369
416
|
throw new Error(`Microsoft Agent Governance denied plan for ${tool.slug} (rule: ${decisionRecord.matchedRule}): ${decisionRecord.reason}`);
|
|
370
417
|
}
|
|
371
418
|
// 2. Recall Supermemory v5 contextual brain for this workspace + tool intent
|
|
372
|
-
const memoryQuery = `${tool.slug} ${tool.name} ${
|
|
419
|
+
const memoryQuery = `${tool.slug} ${tool.name} ${resolvedReason}`.trim();
|
|
373
420
|
const memoryContext = await this.supermemory.getContextForWorkspace(ws.id, memoryQuery);
|
|
374
421
|
const requiresHumanApproval = decisionRecord.verdict === "escalate" ||
|
|
375
422
|
(ws.policy.mode === "enforce" &&
|
|
@@ -384,9 +431,9 @@ export class MuxoEngine {
|
|
|
384
431
|
upstreamSlug: tool.upstreamSlug,
|
|
385
432
|
lane: tool.lane,
|
|
386
433
|
riskLevel: tool.riskLevel,
|
|
387
|
-
input:
|
|
388
|
-
reason:
|
|
389
|
-
creditCost:
|
|
434
|
+
input: resolvedInput,
|
|
435
|
+
reason: resolvedReason,
|
|
436
|
+
creditCost: effectiveCreditCost,
|
|
390
437
|
approvalStatus,
|
|
391
438
|
decisionRecord,
|
|
392
439
|
memoryContext,
|
|
@@ -583,7 +630,15 @@ export class MuxoEngine {
|
|
|
583
630
|
const startedMs = Date.now();
|
|
584
631
|
try {
|
|
585
632
|
let output;
|
|
586
|
-
if (plan.
|
|
633
|
+
if (plan.toolSlug.startsWith("billing.")) {
|
|
634
|
+
output = await this.stripeBilling.executeTool({
|
|
635
|
+
workspace: ws,
|
|
636
|
+
customerEmail: ctx.user.email,
|
|
637
|
+
toolSlug: plan.toolSlug,
|
|
638
|
+
input: plan.input,
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
else if (plan.lane === "composio_instant") {
|
|
587
642
|
output = await this.composioInstant.executeTool({
|
|
588
643
|
workspaceId: ctx.workspace.id,
|
|
589
644
|
tool,
|
|
@@ -716,4 +771,106 @@ export class MuxoEngine {
|
|
|
716
771
|
: true;
|
|
717
772
|
return { receipt, signatureValid, governanceSignatureValid };
|
|
718
773
|
}
|
|
774
|
+
// 19. Natural Language Router & End-to-End Executor (`muxo do` / `POST /api/v1/do`)
|
|
775
|
+
async doNaturalLanguage(ctx, params) {
|
|
776
|
+
const allTools = await this.listAllCatalogTools();
|
|
777
|
+
const byokEnv = this.store.getDecryptedWorkspaceEnv(ctx.workspace.id);
|
|
778
|
+
const activeConns = new Set(this.store
|
|
779
|
+
.listConnections(ctx.workspace.id)
|
|
780
|
+
.filter((c) => c.status === "active")
|
|
781
|
+
.map((c) => c.providerSlug.toLowerCase()));
|
|
782
|
+
const resolution = await resolveNaturalLanguageIntent({
|
|
783
|
+
prompt: params.prompt,
|
|
784
|
+
tools: allTools,
|
|
785
|
+
explicitInput: params.input,
|
|
786
|
+
byokKeys: byokEnv,
|
|
787
|
+
activeConnectionProviders: activeConns,
|
|
788
|
+
});
|
|
789
|
+
if (!resolution.resolved || !resolution.tool) {
|
|
790
|
+
return {
|
|
791
|
+
ok: false,
|
|
792
|
+
executed: false,
|
|
793
|
+
status: "unresolved",
|
|
794
|
+
intent: resolution,
|
|
795
|
+
resolution,
|
|
796
|
+
byokPrompt: {
|
|
797
|
+
needed: !byokEnv.OPENAI_API_KEY && !byokEnv.ANTHROPIC_API_KEY && !byokEnv.OPENROUTER_API_KEY,
|
|
798
|
+
provider: "openai",
|
|
799
|
+
envVarName: "OPENAI_API_KEY",
|
|
800
|
+
cliCommand: "muxo byok set openai <sk-...>",
|
|
801
|
+
message: "Tip: Add an OpenAI, Anthropic, or OpenRouter BYOK key (`muxo byok set openai <key>`) for unrestricted natural-language LLM routing.",
|
|
802
|
+
},
|
|
803
|
+
humanMessage: resolution.humanSummary,
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
if (resolution.missingInputs.length > 0) {
|
|
807
|
+
return {
|
|
808
|
+
ok: false,
|
|
809
|
+
executed: false,
|
|
810
|
+
status: "missing_inputs",
|
|
811
|
+
intent: resolution,
|
|
812
|
+
resolution,
|
|
813
|
+
humanMessage: `Matched ${resolution.tool.name} (${resolution.tool.slug}), but missing required parameter(s): ${resolution.missingInputs.join(", ")}. Please include them in your request.`,
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
const planned = await this.planAction(ctx, {
|
|
817
|
+
toolSlug: resolution.tool.slug,
|
|
818
|
+
input: resolution.input,
|
|
819
|
+
reason: params.prompt,
|
|
820
|
+
});
|
|
821
|
+
if (planned.authHandoff?.required) {
|
|
822
|
+
return {
|
|
823
|
+
ok: false,
|
|
824
|
+
executed: false,
|
|
825
|
+
status: "awaiting_oauth_connection",
|
|
826
|
+
intent: resolution,
|
|
827
|
+
resolution,
|
|
828
|
+
plan: planned.plan,
|
|
829
|
+
authHandoff: planned.authHandoff,
|
|
830
|
+
humanMessage: planned.authHandoff.instructions,
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
if (params.dryRun || params.planOnly) {
|
|
834
|
+
return {
|
|
835
|
+
ok: true,
|
|
836
|
+
executed: false,
|
|
837
|
+
status: "planned_dry_run",
|
|
838
|
+
intent: resolution,
|
|
839
|
+
resolution,
|
|
840
|
+
plan: planned.plan,
|
|
841
|
+
humanMessage: `Planned ${planned.tool.name} (${planned.plan.id}) with risk=${planned.plan.riskLevel} and cost=${planned.plan.creditCost} credits.`,
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
let currentPlan = planned.plan;
|
|
845
|
+
if (currentPlan.approvalStatus === "pending_approval" &&
|
|
846
|
+
params.autoApprove !== false) {
|
|
847
|
+
currentPlan = this.approvePlan(ctx, currentPlan.id, "approved");
|
|
848
|
+
}
|
|
849
|
+
if (currentPlan.approvalStatus === "pending_approval") {
|
|
850
|
+
return {
|
|
851
|
+
ok: true,
|
|
852
|
+
executed: false,
|
|
853
|
+
status: "awaiting_approval",
|
|
854
|
+
intent: resolution,
|
|
855
|
+
resolution,
|
|
856
|
+
plan: currentPlan,
|
|
857
|
+
humanMessage: `Plan ${currentPlan.id} (${currentPlan.toolSlug}, risk=${currentPlan.riskLevel}) requires owner approval. Run 'muxo approve ${currentPlan.id}' or pass --yes to auto-approve.`,
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
const executed = await this.executePlanForRisk(ctx, currentPlan.id, currentPlan.riskLevel);
|
|
861
|
+
const isSuccess = executed.run.status === "succeeded";
|
|
862
|
+
return {
|
|
863
|
+
ok: isSuccess,
|
|
864
|
+
executed: isSuccess,
|
|
865
|
+
status: "executed",
|
|
866
|
+
intent: resolution,
|
|
867
|
+
resolution,
|
|
868
|
+
plan: currentPlan,
|
|
869
|
+
run: executed.run,
|
|
870
|
+
receipt: executed.receipt,
|
|
871
|
+
humanMessage: isSuccess
|
|
872
|
+
? `Completed ${resolution.tool.name} (${resolution.tool.slug}) in ${executed.run.durationMs ?? 0}ms [receipt: ${executed.receipt.id}, funding: ${executed.receipt.supplierSettlement?.fundingMode || "muxo_funded"}].`
|
|
873
|
+
: `Execution of ${resolution.tool.slug} failed: ${executed.run.error || "Unknown error"}`,
|
|
874
|
+
};
|
|
875
|
+
}
|
|
719
876
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -195,15 +195,18 @@ export const MUXO_MCP_TOOLS = [
|
|
|
195
195
|
{
|
|
196
196
|
name: "plan_action",
|
|
197
197
|
title: "Create Governed Action Plan",
|
|
198
|
-
description: "Create a governed execution plan (plan_*) for any tool or infrastructure provisioning operation. Evaluates workspace policy, risk level, Supermemory v5 recall, Ed25519 signature, and credit balance.",
|
|
198
|
+
description: "Create a governed execution plan (plan_*) for any tool, billing operation, or infrastructure provisioning operation. Accepts either an exact tool_slug (e.g. 'instant.seo.audit', 'billing.credits.topup', 'resource.turso.database') or a natural-language instruction (e.g. 'audit seo for https://muxo.ai'). Evaluates workspace policy, risk level, Supermemory v5 recall, Ed25519 signature, BYOK vs Muxo-funded mode, and credit balance.",
|
|
199
199
|
inputSchema: {
|
|
200
200
|
type: "object",
|
|
201
201
|
required: ["tool_slug"],
|
|
202
202
|
properties: {
|
|
203
|
-
tool_slug: {
|
|
203
|
+
tool_slug: {
|
|
204
|
+
type: "string",
|
|
205
|
+
description: "Muxo tool slug (e.g. 'instant.seo.audit', 'billing.credits.topup') or natural-language request",
|
|
206
|
+
},
|
|
204
207
|
input: {
|
|
205
208
|
type: "object",
|
|
206
|
-
description: "Arguments matching the tool's inputSchema",
|
|
209
|
+
description: "Arguments matching the tool's inputSchema (auto-extracted when tool_slug is natural language)",
|
|
207
210
|
},
|
|
208
211
|
reason: {
|
|
209
212
|
type: "string",
|
|
@@ -627,8 +630,13 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
|
|
|
627
630
|
});
|
|
628
631
|
case "plan_action":
|
|
629
632
|
return engine.planAction(ctx, {
|
|
630
|
-
toolSlug: String(args.tool_slug ||
|
|
631
|
-
|
|
633
|
+
toolSlug: String(args.tool_slug ||
|
|
634
|
+
args.slug ||
|
|
635
|
+
args.tool_id ||
|
|
636
|
+
args.prompt ||
|
|
637
|
+
args.instruction ||
|
|
638
|
+
""),
|
|
639
|
+
input: (args.input || args.arguments) || {},
|
|
632
640
|
reason: args.reason ? String(args.reason) : undefined,
|
|
633
641
|
});
|
|
634
642
|
case "get_plan":
|
|
@@ -738,7 +746,7 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
|
|
|
738
746
|
instructions: MUXO_MCP_SERVER_INSTRUCTIONS,
|
|
739
747
|
serverInfo: {
|
|
740
748
|
name: "muxo-mcp-server",
|
|
741
|
-
version: "1.
|
|
749
|
+
version: "1.3.0",
|
|
742
750
|
},
|
|
743
751
|
capabilities: {
|
|
744
752
|
tools: { listChanged: false },
|
package/dist/nl.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ToolDescriptor } from "./types.js";
|
|
2
|
+
export interface NaturalLanguageResolution {
|
|
3
|
+
resolved: boolean;
|
|
4
|
+
tool: ToolDescriptor | null;
|
|
5
|
+
toolSlug: string | null;
|
|
6
|
+
input: Record<string, unknown>;
|
|
7
|
+
extractedInput: Record<string, unknown>;
|
|
8
|
+
reason: string;
|
|
9
|
+
confidence: number;
|
|
10
|
+
resolutionMethod: "exact_slug" | "byok_llm" | "semantic_router";
|
|
11
|
+
byokUsed: string | null;
|
|
12
|
+
humanSummary: string;
|
|
13
|
+
missingInputs: string[];
|
|
14
|
+
needsConnection: boolean;
|
|
15
|
+
suggestedByokProvider: string | null;
|
|
16
|
+
alternatives: Array<{
|
|
17
|
+
slug: string;
|
|
18
|
+
name: string;
|
|
19
|
+
riskLevel: string;
|
|
20
|
+
creditCost: number;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export declare function extractParametersFromNaturalLanguage(prompt: string, tool: ToolDescriptor, explicitInput?: Record<string, unknown>): {
|
|
24
|
+
input: Record<string, unknown>;
|
|
25
|
+
missingInputs: string[];
|
|
26
|
+
};
|
|
27
|
+
export declare function resolveNaturalLanguageIntent(params: {
|
|
28
|
+
prompt: string;
|
|
29
|
+
tools: ToolDescriptor[];
|
|
30
|
+
explicitInput?: Record<string, unknown>;
|
|
31
|
+
byokKeys?: Record<string, string>;
|
|
32
|
+
activeConnectionProviders?: Set<string>;
|
|
33
|
+
preferByokLlm?: boolean;
|
|
34
|
+
}): Promise<NaturalLanguageResolution>;
|