@muxoai/platform 1.4.1 → 1.4.3
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/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +2 -2
- package/README.md +1 -1
- package/dist/cli.js +94 -3
- package/dist/composio-catalog.d.ts +177 -1
- package/dist/composio-catalog.js +1427 -7
- package/dist/config.d.ts +6 -0
- package/dist/config.js +11 -1
- package/dist/durable-workflow.d.ts +71 -4
- package/dist/durable-workflow.js +199 -5
- package/dist/engine.d.ts +82 -3
- package/dist/engine.js +406 -41
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mcp-schema.d.ts +162 -1
- package/dist/mcp-schema.js +1544 -40
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +474 -26
- package/dist/memory-graph.d.ts +26 -2
- package/dist/memory-graph.js +127 -7
- package/dist/oss-suite.d.ts +217 -0
- package/dist/oss-suite.js +836 -0
- package/dist/policy.d.ts +108 -1
- package/dist/policy.js +406 -1
- package/dist/providers/composio-instant.js +38 -3
- package/dist/providers/composio-sdk.d.ts +59 -2
- package/dist/providers/composio-sdk.js +273 -59
- package/dist/providers/stripe-projects.d.ts +4 -0
- package/dist/providers/stripe-projects.js +548 -126
- package/dist/sdk.d.ts +24 -1
- package/dist/sdk.js +53 -2
- package/dist/server.js +659 -64
- package/dist/store.js +2 -0
- package/dist/types.d.ts +34 -1
- package/dist/ui/console-html.d.ts +31 -1
- package/dist/ui/console-html.js +922 -368
- package/dist/ui/design-tokens.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/plugins/muxo/.claude-plugin/plugin.json +2 -2
- package/plugins/muxo/.codex-plugin/plugin.json +15 -8
- package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
- package/plugins/muxo/hooks/session-start.sh +15 -3
- package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
- package/plugins/muxo/mcp.json +0 -10
- package/plugins/muxo/plugin.json +4 -4
- package/plugins/muxo/skills/muxo/SKILL.md +25 -16
- package/plugins/muxo/skills/muxo/references/cli.md +5 -1
- package/plugins/muxo/skills/muxo/references/mcp.md +11 -6
- package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
- package/plugins/muxo/skills/setup/SKILL.md +1 -1
- package/src/catalogues/stripe-projects-catalog.json +140 -0
package/dist/policy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GovernancePolicy, HumanFriendlyExplanation, LanguageMode, ParameterPolicyRule } from "./types.js";
|
|
1
|
+
import type { GovernancePolicy, HumanFriendlyExplanation, LanguageMode, ParameterPolicyRule, RiskLevel } from "./types.js";
|
|
2
2
|
export declare function sanitizeParameterPolicyRule(r: Record<string, unknown>, idx?: number): ParameterPolicyRule;
|
|
3
3
|
export declare class PolicyValidationError extends Error {
|
|
4
4
|
}
|
|
@@ -81,3 +81,110 @@ export declare function evaluateParameterPolicyRules(paramsOrToolSlug: {
|
|
|
81
81
|
violatedRule: ParameterPolicyRule | null;
|
|
82
82
|
reason: string | null;
|
|
83
83
|
};
|
|
84
|
+
export declare function describeParameterRuleCompliance(rule: ParameterPolicyRule): string;
|
|
85
|
+
export interface LlmRiskLaneRule {
|
|
86
|
+
riskLevel: RiskLevel;
|
|
87
|
+
status: "auto_approved" | "requires_approval" | "blocked";
|
|
88
|
+
executeTool: string;
|
|
89
|
+
reason: string;
|
|
90
|
+
}
|
|
91
|
+
export interface LlmPolicyAndGovernanceBrief {
|
|
92
|
+
workspaceId?: string;
|
|
93
|
+
posture: "paused" | "read_only_sandbox" | "ask_every_time" | "safe_default" | "hands_off" | "monitor";
|
|
94
|
+
mode: "enforce" | "monitor";
|
|
95
|
+
executionRing: 0 | 1 | 2 | 3;
|
|
96
|
+
headline: string;
|
|
97
|
+
preferredExplanation: string;
|
|
98
|
+
plainEnglish: ReturnType<typeof describePolicyInPlainEnglish>;
|
|
99
|
+
languageMode: LanguageMode;
|
|
100
|
+
customInstructions: string[];
|
|
101
|
+
killSwitch: {
|
|
102
|
+
active: boolean;
|
|
103
|
+
reason: string | null;
|
|
104
|
+
howToToggleMcp: {
|
|
105
|
+
pause: {
|
|
106
|
+
tool: "get_run_context";
|
|
107
|
+
arguments: Record<string, unknown>;
|
|
108
|
+
};
|
|
109
|
+
resume: {
|
|
110
|
+
tool: "get_run_context";
|
|
111
|
+
arguments: Record<string, unknown>;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
budgetGuardrail: {
|
|
116
|
+
maxCreditsPerRun: number;
|
|
117
|
+
maxUsdPerRun: number;
|
|
118
|
+
allowInstantWallet: boolean;
|
|
119
|
+
allowProvisioning: boolean;
|
|
120
|
+
blockDestructiveSql: boolean;
|
|
121
|
+
};
|
|
122
|
+
riskLaneMatrix: Record<RiskLevel, LlmRiskLaneRule>;
|
|
123
|
+
autoApproveRiskLevels: RiskLevel[];
|
|
124
|
+
requireApprovalRiskLevels: RiskLevel[];
|
|
125
|
+
blockedRiskLevels: RiskLevel[];
|
|
126
|
+
blockedToolSlugs: string[];
|
|
127
|
+
parameterRules: Array<ParameterPolicyRule & {
|
|
128
|
+
howToComply: string;
|
|
129
|
+
}>;
|
|
130
|
+
naturalLanguageRules: string[];
|
|
131
|
+
activeDefaults: Record<string, unknown>;
|
|
132
|
+
trustScore?: {
|
|
133
|
+
overall: number;
|
|
134
|
+
tier: string;
|
|
135
|
+
};
|
|
136
|
+
agentDid?: string;
|
|
137
|
+
llmSystemDirective: string;
|
|
138
|
+
agentControlCheatsheet: Array<{
|
|
139
|
+
intent: string;
|
|
140
|
+
mcpTool: string;
|
|
141
|
+
arguments: Record<string, unknown>;
|
|
142
|
+
}>;
|
|
143
|
+
}
|
|
144
|
+
export declare function buildLlmPolicyAndGovernanceBrief(policy?: GovernancePolicy, options?: {
|
|
145
|
+
workspaceId?: string;
|
|
146
|
+
workspaceName?: string;
|
|
147
|
+
workspaceSlug?: string;
|
|
148
|
+
activeDefaults?: Record<string, unknown>;
|
|
149
|
+
trustScore?: {
|
|
150
|
+
overall: number;
|
|
151
|
+
tier: string;
|
|
152
|
+
};
|
|
153
|
+
agentDid?: string;
|
|
154
|
+
}): LlmPolicyAndGovernanceBrief;
|
|
155
|
+
export interface PolicySimulationResult {
|
|
156
|
+
ok: true;
|
|
157
|
+
action: "check_policy";
|
|
158
|
+
toolSlug: string;
|
|
159
|
+
toolName?: string;
|
|
160
|
+
riskLevel: RiskLevel;
|
|
161
|
+
creditCost: number;
|
|
162
|
+
decision: "auto_approved" | "pending_approval" | "blocked";
|
|
163
|
+
approvalStatus: "auto_approved" | "pending_approval" | "blocked";
|
|
164
|
+
allowed: boolean;
|
|
165
|
+
requiresApproval: boolean;
|
|
166
|
+
blocked: boolean;
|
|
167
|
+
executeTool: string;
|
|
168
|
+
effectiveInput: Record<string, unknown>;
|
|
169
|
+
autoFilledInput: Record<string, unknown>;
|
|
170
|
+
reasons: string[];
|
|
171
|
+
matchedParameterRule: ParameterPolicyRule | null;
|
|
172
|
+
violatedParameterRule: ParameterPolicyRule | null;
|
|
173
|
+
remediationForLlm: string;
|
|
174
|
+
nextToolCalls: Array<{
|
|
175
|
+
tool: string;
|
|
176
|
+
input: Record<string, unknown>;
|
|
177
|
+
when: string;
|
|
178
|
+
}>;
|
|
179
|
+
}
|
|
180
|
+
export declare function simulatePolicyEvaluation(params: {
|
|
181
|
+
policy?: GovernancePolicy | null;
|
|
182
|
+
toolSlug: string;
|
|
183
|
+
toolName?: string;
|
|
184
|
+
riskLevel?: RiskLevel;
|
|
185
|
+
creditCost?: number;
|
|
186
|
+
creditsBalance?: number;
|
|
187
|
+
lane?: string;
|
|
188
|
+
input?: Record<string, unknown>;
|
|
189
|
+
activeDefaults?: Record<string, unknown>;
|
|
190
|
+
}): PolicySimulationResult;
|
package/dist/policy.js
CHANGED
|
@@ -239,6 +239,7 @@ export const DEFAULT_WORKSPACE_POLICY = {
|
|
|
239
239
|
killSwitchReason: null,
|
|
240
240
|
blockDestructiveSql: true,
|
|
241
241
|
naturalLanguageRules: [],
|
|
242
|
+
parameterRules: [],
|
|
242
243
|
languageMode: "hybrid",
|
|
243
244
|
customInstructions: [],
|
|
244
245
|
};
|
|
@@ -267,7 +268,22 @@ export function parseNaturalLanguageGuardrail(prompt, currentPolicy = DEFAULT_WO
|
|
|
267
268
|
// Ignore invalid partial fields in optional patch
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
|
-
const hasGuardrailIntent = /\b(don'?t\s+(?:go\s+over|spend|exceed|use|run|call|allow|provision|delete|drop|send|post)|never\s+(?:go\s+over|spend|exceed|use|run|call|allow|provision|delete|drop|send|post)|do\s+not\s+(?:go\s+over|spend|exceed|use|run|call|allow|provision|delete|drop|send|post)|cap\s+(?:budget|spend|credits)|budget\s+(?:cap|limit|under|below)|max(?:imum)?\s+\d+\s*credits|limit\s+(?:spend|budget|credits)|block\s+(?:tool|destructive|sql|provisioning|app\.|resource\.|instant\.|billing\.|refunds?|payments?|transfers?|emails?|messages?)|unblock\s+(?:all\s+)?tools|disable\s+(?:tool|provisioning|instant)|enable\s+provisioning|ask\s+(?:me\s+)?before|require\s+approval|auto[- ]?approve|only\s+(?:allow|send|post|permit)|restrict\s+(?:emails?|messages?|slack|github|refunds?)|read[- ]only\s+mode|sandbox\s+mode|strict\s+manual|hands[- ]off\s+mode|safe\s+default|monitor\s+mode|observation\s+mode|enforce\s+mode|execution\s+ring|ring\s+[0123]|non[- ]technical\s+(?:mode|language|explanations?)|technical\s+(?:mode|language|explanations?|detail)|plain\s+english|hybrid\s+(?:mode|language)|custom\s+instruction\s*:|always\s+(?:explain|show|include|format)|guardrail\s*:|rule\s*:|policy\s
|
|
271
|
+
const hasGuardrailIntent = /\b(don'?t\s+(?:go\s+over|spend|exceed|use|run|call|allow|provision|delete|drop|send|post)|never\s+(?:go\s+over|spend|exceed|use|run|call|allow|provision|delete|drop|send|post)|do\s+not\s+(?:go\s+over|spend|exceed|use|run|call|allow|provision|delete|drop|send|post)|cap\s+(?:budget|spend|credits)|budget\s+(?:cap|limit|under|below)|max(?:imum)?\s+\d+\s*credits|limit\s+(?:spend|budget|credits)|block\s+(?:tool|destructive|sql|provisioning|app\.|resource\.|instant\.|billing\.|refunds?|payments?|transfers?|emails?|messages?)|unblock\s+(?:all\s+)?tools|disable\s+(?:tool|provisioning|instant)|enable\s+provisioning|ask\s+(?:me\s+)?before|require\s+approval|auto[- ]?approve|only\s+(?:allow|send|post|permit)|restrict\s+(?:emails?|messages?|slack|github|refunds?)|read[- ]only\s+mode|sandbox\s+mode|strict\s+manual|hands[- ]off\s+mode|safe\s+default|monitor\s+mode|observation\s+mode|enforce\s+mode|execution\s+ring|ring\s+[0123]|non[- ]technical\s+(?:mode|language|explanations?)|technical\s+(?:mode|language|explanations?|detail)|plain\s+english|hybrid\s+(?:mode|language)|custom\s+instruction\s*:|always\s+(?:explain|show|include|format)|guardrail\s*:|rule\s*:|policy\s*:|(?:reset|clear|restore)\s+(?:all\s+)?(?:guardrails?|policy|safety\s+rules?))/i.test(cleanPrompt);
|
|
272
|
+
// 0. Full policy / guardrail reset ("reset guardrails", "clear all guardrails", "restore default policy")
|
|
273
|
+
if (/\b(reset|clear|restore)\s+(?:all\s+)?(?:custom\s+)?(?:guardrails?|policy|safety\s+rules?)(?:\s+to\s+defaults?)?\b/i.test(lower) &&
|
|
274
|
+
!/\bparameter\s+rules\b/i.test(lower)) {
|
|
275
|
+
patch.mode = DEFAULT_WORKSPACE_POLICY.mode;
|
|
276
|
+
patch.requireApprovalFor = [...DEFAULT_WORKSPACE_POLICY.requireApprovalFor];
|
|
277
|
+
patch.allowInstantWallet = DEFAULT_WORKSPACE_POLICY.allowInstantWallet;
|
|
278
|
+
patch.allowProvisioning = DEFAULT_WORKSPACE_POLICY.allowProvisioning;
|
|
279
|
+
patch.maxCreditsPerRun = DEFAULT_WORKSPACE_POLICY.maxCreditsPerRun;
|
|
280
|
+
patch.blockedToolSlugs = [];
|
|
281
|
+
patch.parameterRules = [];
|
|
282
|
+
patch.executionRing = DEFAULT_WORKSPACE_POLICY.executionRing;
|
|
283
|
+
patch.blockDestructiveSql = DEFAULT_WORKSPACE_POLICY.blockDestructiveSql;
|
|
284
|
+
patch.naturalLanguageRules = [];
|
|
285
|
+
appliedSummaries.push("Reset all workspace guardrails, parameter rules, and approval thresholds to Safe Default");
|
|
286
|
+
}
|
|
271
287
|
// Detect whether a dollar amount in the sentence refers to a tool-specific transaction
|
|
272
288
|
// (e.g. "Stripe refunds over $50", "payments over $100", "transfers above $250")
|
|
273
289
|
// rather than the workspace's Muxo credit budget per run.
|
|
@@ -1190,3 +1206,392 @@ export function evaluateParameterPolicyRules(paramsOrToolSlug, maybeInput, maybe
|
|
|
1190
1206
|
: null,
|
|
1191
1207
|
};
|
|
1192
1208
|
}
|
|
1209
|
+
export function describeParameterRuleCompliance(rule) {
|
|
1210
|
+
const paramLabel = rule.parameter.split(",")[0] || rule.parameter;
|
|
1211
|
+
const valStr = Array.isArray(rule.value)
|
|
1212
|
+
? rule.value.join(", ")
|
|
1213
|
+
: String(rule.value);
|
|
1214
|
+
const unitSuffix = rule.unit && rule.unit !== "raw" ? ` ${rule.unit.toUpperCase()}` : "";
|
|
1215
|
+
const elseNote = rule.elseAction
|
|
1216
|
+
? `; otherwise action is '${rule.elseAction}'`
|
|
1217
|
+
: "";
|
|
1218
|
+
switch (rule.operator) {
|
|
1219
|
+
case "must_end_with":
|
|
1220
|
+
case "ends_with":
|
|
1221
|
+
return `For tools matching '${rule.toolPattern}', parameter '${paramLabel}' must end with '${valStr}' (violation -> ${rule.action}${elseNote}).`;
|
|
1222
|
+
case "domain_in":
|
|
1223
|
+
return `For tools matching '${rule.toolPattern}', recipient domain in '${paramLabel}' must be in [${valStr}] (violation -> ${rule.action}${elseNote}).`;
|
|
1224
|
+
case "domain_not_in":
|
|
1225
|
+
return `For tools matching '${rule.toolPattern}', recipient domain in '${paramLabel}' must NOT be in [${valStr}] (violation -> ${rule.action}${elseNote}).`;
|
|
1226
|
+
case "max_number":
|
|
1227
|
+
case "gt":
|
|
1228
|
+
case "gte":
|
|
1229
|
+
return `For tools matching '${rule.toolPattern}', keep '${paramLabel}' <= ${valStr}${unitSuffix} (exceeding ${valStr}${unitSuffix} triggers '${rule.action}'${elseNote}).`;
|
|
1230
|
+
case "min_number":
|
|
1231
|
+
case "lt":
|
|
1232
|
+
case "lte":
|
|
1233
|
+
return `For tools matching '${rule.toolPattern}', keep '${paramLabel}' >= ${valStr}${unitSuffix} (below ${valStr}${unitSuffix} triggers '${rule.action}'${elseNote}).`;
|
|
1234
|
+
case "must_equal":
|
|
1235
|
+
case "equals":
|
|
1236
|
+
return `For tools matching '${rule.toolPattern}', parameter '${paramLabel}' must equal '${valStr}' (violation -> ${rule.action}${elseNote}).`;
|
|
1237
|
+
case "not_equals":
|
|
1238
|
+
return `For tools matching '${rule.toolPattern}', parameter '${paramLabel}' must NOT equal '${valStr}' (violation -> ${rule.action}${elseNote}).`;
|
|
1239
|
+
case "in":
|
|
1240
|
+
return `For tools matching '${rule.toolPattern}', parameter '${paramLabel}' must be one of [${valStr}] (violation -> ${rule.action}${elseNote}).`;
|
|
1241
|
+
case "not_in":
|
|
1242
|
+
return `For tools matching '${rule.toolPattern}', parameter '${paramLabel}' must NOT be in [${valStr}] (violation -> ${rule.action}${elseNote}).`;
|
|
1243
|
+
default:
|
|
1244
|
+
return `${rule.description} (toolPattern='${rule.toolPattern}', parameter='${rule.parameter}', operator='${rule.operator}', value=${JSON.stringify(rule.value)}, action='${rule.action}'${elseNote}).`;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
export function buildLlmPolicyAndGovernanceBrief(policy = DEFAULT_WORKSPACE_POLICY, options) {
|
|
1248
|
+
const plain = describePolicyInPlainEnglish(policy);
|
|
1249
|
+
const reqSet = new Set(policy.requireApprovalFor || []);
|
|
1250
|
+
const ring = (policy.executionRing ?? 1);
|
|
1251
|
+
const isPaused = Boolean(policy.killSwitchActive);
|
|
1252
|
+
const isReadOnly = ring === 3;
|
|
1253
|
+
const isMonitor = policy.mode === "monitor";
|
|
1254
|
+
const posture = isPaused
|
|
1255
|
+
? "paused"
|
|
1256
|
+
: isReadOnly
|
|
1257
|
+
? "read_only_sandbox"
|
|
1258
|
+
: isMonitor
|
|
1259
|
+
? "monitor"
|
|
1260
|
+
: reqSet.has("read")
|
|
1261
|
+
? "ask_every_time"
|
|
1262
|
+
: !reqSet.has("write")
|
|
1263
|
+
? "hands_off"
|
|
1264
|
+
: "safe_default";
|
|
1265
|
+
const riskLaneMatrix = {};
|
|
1266
|
+
for (const risk of RISK_LEVELS) {
|
|
1267
|
+
const executeTool = `execute_${risk}`;
|
|
1268
|
+
if (isPaused && !isMonitor) {
|
|
1269
|
+
riskLaneMatrix[risk] = {
|
|
1270
|
+
riskLevel: risk,
|
|
1271
|
+
status: "blocked",
|
|
1272
|
+
executeTool,
|
|
1273
|
+
reason: `Blocked while workspace kill switch is active (${policy.killSwitchReason || "emergency pause"}).`,
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
else if (isReadOnly && risk !== "read" && !isMonitor) {
|
|
1277
|
+
riskLaneMatrix[risk] = {
|
|
1278
|
+
riskLevel: risk,
|
|
1279
|
+
status: "blocked",
|
|
1280
|
+
executeTool,
|
|
1281
|
+
reason: "Blocked by Ring 3 Read-Only Sandbox mode (only 'read' tools are permitted).",
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
else if (risk === "provisioning" && policy.allowProvisioning === false && !isMonitor) {
|
|
1285
|
+
riskLaneMatrix[risk] = {
|
|
1286
|
+
riskLevel: risk,
|
|
1287
|
+
status: "blocked",
|
|
1288
|
+
executeTool,
|
|
1289
|
+
reason: "Blocked because cloud infrastructure provisioning (allowProvisioning=false) is disabled.",
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
else if (reqSet.has(risk) && !isMonitor) {
|
|
1293
|
+
riskLaneMatrix[risk] = {
|
|
1294
|
+
riskLevel: risk,
|
|
1295
|
+
status: "requires_approval",
|
|
1296
|
+
executeTool,
|
|
1297
|
+
reason: `Requires human owner approval before ${executeTool} can run (unless a conditional parameterRule explicitly sets elseAction='auto_approve').`,
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
else {
|
|
1301
|
+
riskLaneMatrix[risk] = {
|
|
1302
|
+
riskLevel: risk,
|
|
1303
|
+
status: "auto_approved",
|
|
1304
|
+
executeTool,
|
|
1305
|
+
reason: isMonitor
|
|
1306
|
+
? `Auto-approved in monitor mode; call ${executeTool} immediately after plan_action.`
|
|
1307
|
+
: `Auto-approved by workspace policy; call ${executeTool} immediately after plan_action.`,
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
const parameterRules = (policy.parameterRules || []).map((r) => ({
|
|
1312
|
+
...r,
|
|
1313
|
+
howToComply: describeParameterRuleCompliance(r),
|
|
1314
|
+
}));
|
|
1315
|
+
const maxCredits = Number(policy.maxCreditsPerRun ?? 50);
|
|
1316
|
+
const maxUsd = Number((maxCredits * 0.01).toFixed(2));
|
|
1317
|
+
const activeDefaults = options?.activeDefaults || {};
|
|
1318
|
+
const defaultsPairs = Object.entries(activeDefaults).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
1319
|
+
const autoApproveRiskLevels = RISK_LEVELS.filter((r) => riskLaneMatrix[r].status === "auto_approved");
|
|
1320
|
+
const requireApprovalRiskLevels = RISK_LEVELS.filter((r) => riskLaneMatrix[r].status === "requires_approval");
|
|
1321
|
+
const blockedLanes = RISK_LEVELS.filter((r) => riskLaneMatrix[r].status === "blocked");
|
|
1322
|
+
const directiveLines = [
|
|
1323
|
+
`## Muxo Policy & Governance Contract${options?.workspaceName ? ` (${options.workspaceName})` : ""}`,
|
|
1324
|
+
`- **Posture**: \`${posture}\` (mode=\`${policy.mode || "enforce"}\`, ring=\`Ring ${ring}\`, languageMode=\`${plain.languageMode}\`)`,
|
|
1325
|
+
`- **Summary**: ${plain.preferred}`,
|
|
1326
|
+
`- **Per-Run Budget Cap**: ${maxCredits} credits ($${maxUsd.toFixed(2)}) max per run`,
|
|
1327
|
+
`- **Auto-Approved Risk Lanes**: ${autoApproveRiskLevels.join(", ") || "none"}`,
|
|
1328
|
+
`- **Human-Approval Risk Lanes**: ${requireApprovalRiskLevels.join(", ") || "none"}`,
|
|
1329
|
+
];
|
|
1330
|
+
if (blockedLanes.length > 0) {
|
|
1331
|
+
directiveLines.push(`- **Blocked Risk Lanes**: ${blockedLanes.join(", ")}`);
|
|
1332
|
+
}
|
|
1333
|
+
if (policy.blockedToolSlugs && policy.blockedToolSlugs.length > 0) {
|
|
1334
|
+
directiveLines.push(`- **Blocked Tools (Never Call)**: ${policy.blockedToolSlugs.join(", ")}`);
|
|
1335
|
+
}
|
|
1336
|
+
if (parameterRules.length > 0) {
|
|
1337
|
+
directiveLines.push(`- **Conditional Parameter Guardrails (${parameterRules.length})**:`);
|
|
1338
|
+
for (const pr of parameterRules) {
|
|
1339
|
+
directiveLines.push(` - \`${pr.id}\`: ${pr.howToComply}`);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
if (defaultsPairs.length > 0) {
|
|
1343
|
+
directiveLines.push(`- **Learned Memory Defaults (Auto-Filled on plan_action)**: ${defaultsPairs.join(", ")}`);
|
|
1344
|
+
}
|
|
1345
|
+
if (plain.customInstructions.length > 0) {
|
|
1346
|
+
directiveLines.push(`- **Operator Custom Instructions**: ${plain.customInstructions.join(" | ")}`);
|
|
1347
|
+
}
|
|
1348
|
+
return {
|
|
1349
|
+
...(options?.workspaceId ? { workspaceId: options.workspaceId } : {}),
|
|
1350
|
+
posture,
|
|
1351
|
+
mode: (policy.mode || "enforce"),
|
|
1352
|
+
executionRing: ring,
|
|
1353
|
+
headline: plain.headline,
|
|
1354
|
+
preferredExplanation: plain.preferred,
|
|
1355
|
+
plainEnglish: plain,
|
|
1356
|
+
languageMode: plain.languageMode,
|
|
1357
|
+
customInstructions: plain.customInstructions,
|
|
1358
|
+
killSwitch: {
|
|
1359
|
+
active: isPaused,
|
|
1360
|
+
reason: policy.killSwitchReason || null,
|
|
1361
|
+
howToToggleMcp: {
|
|
1362
|
+
pause: {
|
|
1363
|
+
tool: "get_run_context",
|
|
1364
|
+
arguments: {
|
|
1365
|
+
action: "kill_switch",
|
|
1366
|
+
enabled: true,
|
|
1367
|
+
prompt: "Pause all agent executions",
|
|
1368
|
+
},
|
|
1369
|
+
},
|
|
1370
|
+
resume: {
|
|
1371
|
+
tool: "get_run_context",
|
|
1372
|
+
arguments: {
|
|
1373
|
+
action: "kill_switch",
|
|
1374
|
+
enabled: false,
|
|
1375
|
+
prompt: "Resume agent executions",
|
|
1376
|
+
},
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
budgetGuardrail: {
|
|
1381
|
+
maxCreditsPerRun: maxCredits,
|
|
1382
|
+
maxUsdPerRun: maxUsd,
|
|
1383
|
+
allowInstantWallet: policy.allowInstantWallet !== false,
|
|
1384
|
+
allowProvisioning: policy.allowProvisioning !== false,
|
|
1385
|
+
blockDestructiveSql: policy.blockDestructiveSql !== false,
|
|
1386
|
+
},
|
|
1387
|
+
riskLaneMatrix,
|
|
1388
|
+
autoApproveRiskLevels,
|
|
1389
|
+
requireApprovalRiskLevels,
|
|
1390
|
+
blockedRiskLevels: blockedLanes,
|
|
1391
|
+
blockedToolSlugs: policy.blockedToolSlugs || [],
|
|
1392
|
+
parameterRules,
|
|
1393
|
+
naturalLanguageRules: policy.naturalLanguageRules || [],
|
|
1394
|
+
activeDefaults,
|
|
1395
|
+
...(options?.trustScore ? { trustScore: options.trustScore } : {}),
|
|
1396
|
+
...(options?.agentDid ? { agentDid: options.agentDid } : {}),
|
|
1397
|
+
llmSystemDirective: directiveLines.join("\n"),
|
|
1398
|
+
agentControlCheatsheet: [
|
|
1399
|
+
{
|
|
1400
|
+
intent: "Inspect active policy, guardrails, and learned memory defaults",
|
|
1401
|
+
mcpTool: "get_run_context",
|
|
1402
|
+
arguments: { action: "governance_status" },
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
intent: "Add or update a guardrail in plain English or structured parameter_rules",
|
|
1406
|
+
mcpTool: "get_run_context",
|
|
1407
|
+
arguments: {
|
|
1408
|
+
action: "set_guardrail",
|
|
1409
|
+
prompt: "Require approval for Stripe refunds over $50, auto-approve under $50",
|
|
1410
|
+
},
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
intent: "Dry-run test if a tool + input will pass policy before creating a plan",
|
|
1414
|
+
mcpTool: "get_run_context",
|
|
1415
|
+
arguments: {
|
|
1416
|
+
action: "check_policy",
|
|
1417
|
+
tool_slug: "app.gmail.send_email",
|
|
1418
|
+
input: { to: "team@muxo.ai", subject: "Status" },
|
|
1419
|
+
},
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
intent: "Reset custom guardrails and parameter rules back to Safe Default",
|
|
1423
|
+
mcpTool: "get_run_context",
|
|
1424
|
+
arguments: { action: "reset_guardrails" },
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
intent: "Pause or resume workspace execution via the emergency kill switch",
|
|
1428
|
+
mcpTool: "get_run_context",
|
|
1429
|
+
arguments: { action: "kill_switch", enabled: false },
|
|
1430
|
+
},
|
|
1431
|
+
{
|
|
1432
|
+
intent: "Save a workspace fact or default parameter for automatic recall",
|
|
1433
|
+
mcpTool: "get_run_context",
|
|
1434
|
+
arguments: {
|
|
1435
|
+
action: "remember",
|
|
1436
|
+
prompt: "Remember our default GitHub repo is muxo-ai/muxo",
|
|
1437
|
+
},
|
|
1438
|
+
},
|
|
1439
|
+
],
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
export function simulatePolicyEvaluation(params) {
|
|
1443
|
+
const policy = {
|
|
1444
|
+
...DEFAULT_WORKSPACE_POLICY,
|
|
1445
|
+
...(params.policy || {}),
|
|
1446
|
+
};
|
|
1447
|
+
const toolSlug = String(params.toolSlug || "instant.web.search").trim();
|
|
1448
|
+
const riskLevel = params.riskLevel ||
|
|
1449
|
+
(toolSlug.startsWith("instant.")
|
|
1450
|
+
? "read"
|
|
1451
|
+
: toolSlug.startsWith("resource.")
|
|
1452
|
+
? "provisioning"
|
|
1453
|
+
: toolSlug.startsWith("billing.")
|
|
1454
|
+
? "financial"
|
|
1455
|
+
: "write");
|
|
1456
|
+
const creditCost = Number(params.creditCost ?? (riskLevel === "read" ? 2 : 5));
|
|
1457
|
+
const rawInput = { ...(params.input || {}) };
|
|
1458
|
+
const defaults = params.activeDefaults || {};
|
|
1459
|
+
const effectiveInput = { ...rawInput };
|
|
1460
|
+
const autoFilledInput = {};
|
|
1461
|
+
for (const [k, v] of Object.entries(defaults)) {
|
|
1462
|
+
if (effectiveInput[k] === undefined && v !== undefined) {
|
|
1463
|
+
effectiveInput[k] = v;
|
|
1464
|
+
autoFilledInput[k] = v;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
const reasons = [];
|
|
1468
|
+
let decision = "auto_approved";
|
|
1469
|
+
const isMonitor = policy.mode === "monitor";
|
|
1470
|
+
if (policy.killSwitchActive && !isMonitor) {
|
|
1471
|
+
decision = "blocked";
|
|
1472
|
+
reasons.push(`Workspace kill switch is active (${policy.killSwitchReason || "emergency pause"}).`);
|
|
1473
|
+
}
|
|
1474
|
+
if (decision !== "blocked" &&
|
|
1475
|
+
(policy.blockedToolSlugs || []).some((s) => s.toLowerCase() === toolSlug.toLowerCase()) &&
|
|
1476
|
+
!isMonitor) {
|
|
1477
|
+
decision = "blocked";
|
|
1478
|
+
reasons.push(`Tool '${toolSlug}' is on the workspace blockedToolSlugs list.`);
|
|
1479
|
+
}
|
|
1480
|
+
if (decision !== "blocked" &&
|
|
1481
|
+
policy.executionRing === 3 &&
|
|
1482
|
+
riskLevel !== "read" &&
|
|
1483
|
+
!isMonitor) {
|
|
1484
|
+
decision = "blocked";
|
|
1485
|
+
reasons.push(`Workspace is in Ring 3 (Read-Only Sandbox mode), which blocks '${riskLevel}' tools.`);
|
|
1486
|
+
}
|
|
1487
|
+
if (decision !== "blocked" &&
|
|
1488
|
+
riskLevel === "provisioning" &&
|
|
1489
|
+
policy.allowProvisioning === false &&
|
|
1490
|
+
!isMonitor) {
|
|
1491
|
+
decision = "blocked";
|
|
1492
|
+
reasons.push("Cloud infrastructure provisioning is disabled (allowProvisioning=false).");
|
|
1493
|
+
}
|
|
1494
|
+
const maxCredits = Number(policy.maxCreditsPerRun ?? 50);
|
|
1495
|
+
if (decision !== "blocked" && creditCost > maxCredits && !isMonitor) {
|
|
1496
|
+
decision = "blocked";
|
|
1497
|
+
reasons.push(`Tool credit cost (${creditCost} cr) exceeds policy maxCreditsPerRun (${maxCredits} cr).`);
|
|
1498
|
+
}
|
|
1499
|
+
if (decision !== "blocked" &&
|
|
1500
|
+
typeof params.creditsBalance === "number" &&
|
|
1501
|
+
creditCost > params.creditsBalance) {
|
|
1502
|
+
decision = "blocked";
|
|
1503
|
+
reasons.push(`Insufficient workspace credits: tool requires ${creditCost} cr, balance is ${params.creditsBalance} cr.`);
|
|
1504
|
+
}
|
|
1505
|
+
const paramEval = evaluateParameterPolicyRules({
|
|
1506
|
+
policy,
|
|
1507
|
+
toolSlug,
|
|
1508
|
+
input: effectiveInput,
|
|
1509
|
+
});
|
|
1510
|
+
if (decision !== "blocked") {
|
|
1511
|
+
if (paramEval.violated && paramEval.action === "block" && !isMonitor) {
|
|
1512
|
+
decision = "blocked";
|
|
1513
|
+
reasons.push(paramEval.reason || "Blocked by conditional parameter guardrail.");
|
|
1514
|
+
}
|
|
1515
|
+
else if (paramEval.violated &&
|
|
1516
|
+
paramEval.action === "require_approval" &&
|
|
1517
|
+
!isMonitor) {
|
|
1518
|
+
decision = "pending_approval";
|
|
1519
|
+
reasons.push(paramEval.reason || "Parameter guardrail requires human owner approval.");
|
|
1520
|
+
}
|
|
1521
|
+
else if (paramEval.explicitAllow && paramEval.action === "auto_approve") {
|
|
1522
|
+
decision = "auto_approved";
|
|
1523
|
+
reasons.push(paramEval.reason ||
|
|
1524
|
+
"Auto-approved by conditional parameter guardrail (elseAction='auto_approve').");
|
|
1525
|
+
}
|
|
1526
|
+
else if ((policy.requireApprovalFor || []).includes(riskLevel) &&
|
|
1527
|
+
!isMonitor) {
|
|
1528
|
+
decision = "pending_approval";
|
|
1529
|
+
reasons.push(`Risk level '${riskLevel}' requires human owner approval under active workspace policy.`);
|
|
1530
|
+
}
|
|
1531
|
+
else {
|
|
1532
|
+
decision = "auto_approved";
|
|
1533
|
+
reasons.push(`Allowed and auto-approved under workspace policy (riskLevel='${riskLevel}', cost=${creditCost} cr <= ${maxCredits} cr).`);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
const executeTool = `execute_${riskLevel}`;
|
|
1537
|
+
let remediationForLlm = "";
|
|
1538
|
+
const nextToolCalls = [];
|
|
1539
|
+
if (decision === "auto_approved") {
|
|
1540
|
+
remediationForLlm = `Action will be auto_approved. Call plan_action({ tool_slug: '${toolSlug}', input: ${JSON.stringify(effectiveInput)} }) and then ${executeTool}.`;
|
|
1541
|
+
nextToolCalls.push({
|
|
1542
|
+
tool: "plan_action",
|
|
1543
|
+
input: {
|
|
1544
|
+
tool_slug: toolSlug,
|
|
1545
|
+
input: effectiveInput,
|
|
1546
|
+
reason: `Execute ${toolSlug}`,
|
|
1547
|
+
},
|
|
1548
|
+
when: "Ready to create an auto-approved plan",
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
else if (decision === "pending_approval") {
|
|
1552
|
+
remediationForLlm = `Action is allowed to be planned but will enter 'pending_approval' (${reasons.join("; ")}). Call plan_action, share humanHandoff.url with the user, and call get_plan({ plan_id, wait_for_approval: true }).`;
|
|
1553
|
+
nextToolCalls.push({
|
|
1554
|
+
tool: "plan_action",
|
|
1555
|
+
input: {
|
|
1556
|
+
tool_slug: toolSlug,
|
|
1557
|
+
input: effectiveInput,
|
|
1558
|
+
reason: `Request approval for ${toolSlug}`,
|
|
1559
|
+
},
|
|
1560
|
+
when: "To generate the plan and human approval URL",
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
else {
|
|
1564
|
+
const ruleHint = paramEval.violatedRule
|
|
1565
|
+
? ` Adjust arguments to satisfy: ${describeParameterRuleCompliance(paramEval.violatedRule)}`
|
|
1566
|
+
: "";
|
|
1567
|
+
remediationForLlm = `Action is currently BLOCKED (${reasons.join("; ")}).${ruleHint} Or ask the user if they want to update the guardrail via get_run_context({ action: 'set_guardrail', prompt: '...' }).`;
|
|
1568
|
+
nextToolCalls.push({
|
|
1569
|
+
tool: "get_run_context",
|
|
1570
|
+
input: {
|
|
1571
|
+
action: "governance_status",
|
|
1572
|
+
},
|
|
1573
|
+
when: "To inspect active guardrails or adjust workspace policy with the user's permission",
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
return {
|
|
1577
|
+
ok: true,
|
|
1578
|
+
action: "check_policy",
|
|
1579
|
+
toolSlug,
|
|
1580
|
+
...(params.toolName ? { toolName: params.toolName } : {}),
|
|
1581
|
+
riskLevel,
|
|
1582
|
+
creditCost,
|
|
1583
|
+
decision,
|
|
1584
|
+
approvalStatus: decision,
|
|
1585
|
+
allowed: decision !== "blocked",
|
|
1586
|
+
requiresApproval: decision === "pending_approval",
|
|
1587
|
+
blocked: decision === "blocked",
|
|
1588
|
+
executeTool,
|
|
1589
|
+
effectiveInput,
|
|
1590
|
+
autoFilledInput,
|
|
1591
|
+
reasons,
|
|
1592
|
+
matchedParameterRule: paramEval.matchedRule,
|
|
1593
|
+
violatedParameterRule: paramEval.violatedRule,
|
|
1594
|
+
remediationForLlm,
|
|
1595
|
+
nextToolCalls,
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
@@ -265,7 +265,8 @@ export class ComposioInstantAdapter {
|
|
|
265
265
|
const hasCustomerByok = Boolean((params.composioApiKey && params.composioApiKey.trim()) ||
|
|
266
266
|
(params.exaApiKey && params.exaApiKey.trim()) ||
|
|
267
267
|
(params.firecrawlApiKey && params.firecrawlApiKey.trim()));
|
|
268
|
-
const activeComposioKey = params.composioApiKey ||
|
|
268
|
+
const activeComposioKey = params.composioApiKey ||
|
|
269
|
+
(isMasterWalletEmpty ? null : this.config.composioInstantApiKey || this.config.composioApiKey);
|
|
269
270
|
const finalizeInstantResult = (res) => {
|
|
270
271
|
if (isMasterWalletEmpty && !hasCustomerByok) {
|
|
271
272
|
return {
|
|
@@ -377,12 +378,29 @@ export class ComposioInstantAdapter {
|
|
|
377
378
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Composio SDK instant timeout")), 8000)),
|
|
378
379
|
]);
|
|
379
380
|
if (sdkRes && !sdkRes.error && sdkRes.successful !== false) {
|
|
381
|
+
const rawData = (sdkRes.data ?? sdkRes);
|
|
382
|
+
const citations = Array.isArray(rawData?.citations)
|
|
383
|
+
? rawData.citations
|
|
384
|
+
: null;
|
|
385
|
+
const mappedResults = Array.isArray(rawData?.results)
|
|
386
|
+
? rawData.results
|
|
387
|
+
: citations
|
|
388
|
+
? citations.map((c) => ({
|
|
389
|
+
title: String(c.title || c.url || c.id || ""),
|
|
390
|
+
url: String(c.url || c.id || ""),
|
|
391
|
+
snippet: String(c.author || rawData.answer || ""),
|
|
392
|
+
source: "composio_instant",
|
|
393
|
+
}))
|
|
394
|
+
: undefined;
|
|
380
395
|
return finalizeInstantResult({
|
|
381
396
|
provider: "composio_instant",
|
|
382
397
|
sdk: "@composio/core",
|
|
383
398
|
billingMode: "provider_wallet",
|
|
384
399
|
tool: tool.slug,
|
|
385
|
-
|
|
400
|
+
...(input.query ? { query: String(input.query) } : {}),
|
|
401
|
+
...(typeof rawData?.answer === "string" ? { answer: rawData.answer } : {}),
|
|
402
|
+
...(mappedResults ? { results: mappedResults } : {}),
|
|
403
|
+
data: rawData,
|
|
386
404
|
});
|
|
387
405
|
}
|
|
388
406
|
}
|
|
@@ -405,11 +423,28 @@ export class ComposioInstantAdapter {
|
|
|
405
423
|
if (res.ok) {
|
|
406
424
|
const payload = (await res.json());
|
|
407
425
|
if (!payload.error) {
|
|
426
|
+
const rawData = (payload.data ?? payload);
|
|
427
|
+
const citations = Array.isArray(rawData?.citations)
|
|
428
|
+
? rawData.citations
|
|
429
|
+
: null;
|
|
430
|
+
const mappedResults = Array.isArray(rawData?.results)
|
|
431
|
+
? rawData.results
|
|
432
|
+
: citations
|
|
433
|
+
? citations.map((c) => ({
|
|
434
|
+
title: String(c.title || c.url || c.id || ""),
|
|
435
|
+
url: String(c.url || c.id || ""),
|
|
436
|
+
snippet: String(c.author || rawData.answer || ""),
|
|
437
|
+
source: "composio_instant",
|
|
438
|
+
}))
|
|
439
|
+
: undefined;
|
|
408
440
|
return finalizeInstantResult({
|
|
409
441
|
provider: "composio_instant",
|
|
410
442
|
billingMode: "provider_wallet",
|
|
411
443
|
tool: tool.slug,
|
|
412
|
-
|
|
444
|
+
...(input.query ? { query: String(input.query) } : {}),
|
|
445
|
+
...(typeof rawData?.answer === "string" ? { answer: rawData.answer } : {}),
|
|
446
|
+
...(mappedResults ? { results: mappedResults } : {}),
|
|
447
|
+
data: rawData,
|
|
413
448
|
});
|
|
414
449
|
}
|
|
415
450
|
}
|