@muxoai/platform 1.3.1 → 1.3.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.
- package/README.md +10 -2
- package/dist/clerk.d.ts +33 -0
- package/dist/clerk.js +198 -0
- package/dist/cli.js +422 -26
- package/dist/engine.d.ts +21 -1
- package/dist/engine.js +245 -23
- package/dist/mcp.js +2 -1
- package/dist/policy.d.ts +9 -0
- package/dist/policy.js +73 -0
- package/dist/providers/composio-instant.d.ts +3 -0
- package/dist/providers/composio-instant.js +629 -530
- package/dist/providers/microsoft-governance.d.ts +61 -2
- package/dist/providers/microsoft-governance.js +458 -24
- package/dist/providers/stripe-projects.d.ts +4 -1
- package/dist/providers/stripe-projects.js +64 -10
- package/dist/providers/supermemory.d.ts +26 -5
- package/dist/providers/supermemory.js +136 -26
- package/dist/sdk.d.ts +167 -1
- package/dist/sdk.js +113 -2
- package/dist/server.js +176 -16
- package/dist/store.d.ts +25 -1
- package/dist/store.js +236 -3
- package/dist/types.d.ts +86 -0
- package/dist/ui/console-html.d.ts +16 -0
- package/dist/ui/console-html.js +2427 -2226
- package/dist/ui/design-tokens.d.ts +177 -0
- package/dist/ui/design-tokens.js +210 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +2 -2
|
@@ -4,6 +4,22 @@ import path from "node:path";
|
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { ROOT_DIR } from "../config.js";
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
|
+
export function isPaidCloudProvisioning(tool, input) {
|
|
8
|
+
if (tool.lane !== "stripe_projects")
|
|
9
|
+
return false;
|
|
10
|
+
if (Boolean(tool.metadata?.isPaidService) || tool.creditCost >= 15) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
const requestedPlan = String(input?.plan || "")
|
|
14
|
+
.trim()
|
|
15
|
+
.toLowerCase();
|
|
16
|
+
if (!requestedPlan)
|
|
17
|
+
return false;
|
|
18
|
+
const planLeaf = requestedPlan.includes("/")
|
|
19
|
+
? requestedPlan.split("/").pop() || requestedPlan
|
|
20
|
+
: requestedPlan;
|
|
21
|
+
return /^(pro|scaler|paid|scale|business|team|grow|credits|launch|enterprise|plus)$/i.test(planLeaf);
|
|
22
|
+
}
|
|
7
23
|
export class StripeProjectsAdapter {
|
|
8
24
|
config;
|
|
9
25
|
tools = new Map();
|
|
@@ -152,6 +168,13 @@ export class StripeProjectsAdapter {
|
|
|
152
168
|
const hasConfigProps = svc.configuration_schema &&
|
|
153
169
|
typeof svc.configuration_schema === "object" &&
|
|
154
170
|
Object.keys(svc.configuration_schema.properties || {}).length > 0;
|
|
171
|
+
const pricingType = String(svc.pricing?.type || "")
|
|
172
|
+
.trim()
|
|
173
|
+
.toLowerCase();
|
|
174
|
+
const isPaidService = (svc.kind === "plan" &&
|
|
175
|
+
((pricingType.length > 0 && pricingType !== "free") ||
|
|
176
|
+
/^(pro|scaler|paid|scale|business|team|grow|credits|launch|enterprise|plus)$/i.test(svc.service_id))) ||
|
|
177
|
+
/^(credits|workers_paid)$/i.test(svc.service_id);
|
|
155
178
|
const tool = {
|
|
156
179
|
slug: muxoSlug,
|
|
157
180
|
upstreamSlug,
|
|
@@ -164,7 +187,7 @@ export class StripeProjectsAdapter {
|
|
|
164
187
|
categories: Array.from(new Set([...(svc.categories || []), "infrastructure"])),
|
|
165
188
|
riskLevel: "provisioning",
|
|
166
189
|
requiresAuth: false,
|
|
167
|
-
creditCost: 5,
|
|
190
|
+
creditCost: isPaidService ? 25 : 5,
|
|
168
191
|
billingMode: "resource_provisioning",
|
|
169
192
|
inputSchema: {
|
|
170
193
|
type: "object",
|
|
@@ -203,6 +226,8 @@ export class StripeProjectsAdapter {
|
|
|
203
226
|
metadata: {
|
|
204
227
|
kind: svc.kind,
|
|
205
228
|
serviceId: svc.service_id,
|
|
229
|
+
isPaidService,
|
|
230
|
+
pricingType: pricingType || (isPaidService ? "paid" : "free"),
|
|
206
231
|
parentPlans,
|
|
207
232
|
configurationSchema: svc.configuration_schema || null,
|
|
208
233
|
providerUrl: matchedProvider?.url || null,
|
|
@@ -375,9 +400,13 @@ export class StripeProjectsAdapter {
|
|
|
375
400
|
: `Provider ${slug} is linked and ready in Stripe Projects.`,
|
|
376
401
|
};
|
|
377
402
|
}
|
|
378
|
-
async pullEnvVarsFromWorkdir() {
|
|
379
|
-
|
|
403
|
+
async pullEnvVarsFromWorkdir(syncFromCli = false) {
|
|
404
|
+
if (!this.hasLocalProjectsWorkdir)
|
|
405
|
+
return {};
|
|
380
406
|
const envPath = path.join(this.config.stripeProjectsWorkdir, ".env");
|
|
407
|
+
if (syncFromCli || !fs.existsSync(envPath)) {
|
|
408
|
+
await this.runStripeProjectsCli(["env", "--pull"], 10000).catch(() => null);
|
|
409
|
+
}
|
|
381
410
|
if (!fs.existsSync(envPath))
|
|
382
411
|
return {};
|
|
383
412
|
const raw = fs.readFileSync(envPath, "utf8");
|
|
@@ -403,6 +432,15 @@ export class StripeProjectsAdapter {
|
|
|
403
432
|
}
|
|
404
433
|
async executeTool(params) {
|
|
405
434
|
const { tool, input } = params;
|
|
435
|
+
const isPaidPlan = isPaidCloudProvisioning(tool, input);
|
|
436
|
+
const requestedPlanRaw = input.plan ? String(input.plan).trim() : "";
|
|
437
|
+
const hasCustomerStripeByok = Boolean(params.stripeApiKey && params.stripeApiKey.trim());
|
|
438
|
+
const isMasterWalletEmpty = Boolean(params.masterWalletDepleted) ||
|
|
439
|
+
process.env.MUXO_MASTER_WALLET_DEPLETED === "true" ||
|
|
440
|
+
input._simulateMasterWalletEmpty === true;
|
|
441
|
+
if (isPaidPlan && !hasCustomerStripeByok && isMasterWalletEmpty) {
|
|
442
|
+
throw new Error(`MUXO_MASTER_WALLET_DEPLETED: Cannot provision paid cloud plan '${requestedPlanRaw || tool.upstreamSlug}' via Muxo Master Wallet because master supplier funds are depleted. 0 credits were charged to your workspace. Configure your own Stripe key via 'muxo byok set stripe <rk_live_...>' to provision paid plans at 0 Muxo credits, or select a 'free' plan.`);
|
|
443
|
+
}
|
|
406
444
|
if (tool.slug === "resource.projects.status") {
|
|
407
445
|
const status = await this.getLiveStatus();
|
|
408
446
|
return {
|
|
@@ -440,7 +478,7 @@ export class StripeProjectsAdapter {
|
|
|
440
478
|
};
|
|
441
479
|
}
|
|
442
480
|
const res = await this.runStripeProjectsCli(["rotate", resourceName, "--yes"], 45000);
|
|
443
|
-
const secrets = await this.pullEnvVarsFromWorkdir();
|
|
481
|
+
const secrets = await this.pullEnvVarsFromWorkdir(true);
|
|
444
482
|
return {
|
|
445
483
|
output: {
|
|
446
484
|
provider: "stripe_projects",
|
|
@@ -523,6 +561,8 @@ export class StripeProjectsAdapter {
|
|
|
523
561
|
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
524
562
|
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
525
563
|
};
|
|
564
|
+
const resolvedPlanSlug = requestedPlanRaw ||
|
|
565
|
+
(isPaidPlan ? serviceId : tool.metadata?.parentPlans?.[0] || "free");
|
|
526
566
|
return {
|
|
527
567
|
output: {
|
|
528
568
|
provider: "stripe_projects",
|
|
@@ -530,7 +570,9 @@ export class StripeProjectsAdapter {
|
|
|
530
570
|
tool: tool.slug,
|
|
531
571
|
upstreamService: tool.upstreamSlug,
|
|
532
572
|
resourceName,
|
|
533
|
-
provisionedPlan:
|
|
573
|
+
provisionedPlan: resolvedPlanSlug,
|
|
574
|
+
billingTier: isPaidPlan ? "paid" : "free",
|
|
575
|
+
fundingSource: hasCustomerStripeByok ? "customer_byok_stripe" : "muxo_master_wallet",
|
|
534
576
|
envVarKeys: Object.keys(secrets),
|
|
535
577
|
details: {
|
|
536
578
|
id: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
@@ -543,7 +585,7 @@ export class StripeProjectsAdapter {
|
|
|
543
585
|
providerSlug: tool.providerSlug,
|
|
544
586
|
providerName: tool.providerName,
|
|
545
587
|
serviceSlug: serviceId,
|
|
546
|
-
planSlug:
|
|
588
|
+
planSlug: resolvedPlanSlug,
|
|
547
589
|
status: "active",
|
|
548
590
|
secrets,
|
|
549
591
|
externalResourceId: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
@@ -552,7 +594,7 @@ export class StripeProjectsAdapter {
|
|
|
552
594
|
}
|
|
553
595
|
// Check if a parent plan is required first
|
|
554
596
|
const parentPlans = tool.metadata?.parentPlans || [];
|
|
555
|
-
let provisionedPlan = null;
|
|
597
|
+
let provisionedPlan = requestedPlanRaw || null;
|
|
556
598
|
// Auto-fill required config fields (e.g. name, location/region) from configurationSchema if omitted
|
|
557
599
|
const configSchema = (tool.metadata?.configurationSchema || {});
|
|
558
600
|
const mergedConfig = input.config && typeof input.config === "object"
|
|
@@ -608,6 +650,11 @@ export class StripeProjectsAdapter {
|
|
|
608
650
|
const existingSvc = liveAfter?.services?.find((s) => String(s.name || "").toLowerCase() === resourceName.toLowerCase());
|
|
609
651
|
if (!existingSvc &&
|
|
610
652
|
!/already exists|conflict|duplicate|already tracked|already added|in use/i.test(msg)) {
|
|
653
|
+
if (isPaidPlan &&
|
|
654
|
+
!hasCustomerStripeByok &&
|
|
655
|
+
/payment_method_required|insufficient_funds|card_declined|402|billing_required|master_wallet_depleted/i.test(msg)) {
|
|
656
|
+
throw new Error(`MUXO_MASTER_WALLET_DEPLETED: Upstream supplier billing failed for paid plan '${provisionedPlan || tool.upstreamSlug}' (${msg}). 0 credits were charged to your workspace. Configure your own Stripe key via 'muxo byok set stripe <rk_live_...>' to provision paid plans at 0 Muxo credits.`);
|
|
657
|
+
}
|
|
611
658
|
// Fallback to Muxo Cloud Infrastructure managed provisioning when local CLI requires browser auth or provider account linking
|
|
612
659
|
const prefix = tool.providerSlug.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
613
660
|
const fallbackSecrets = tool.providerSlug === "turso"
|
|
@@ -623,6 +670,7 @@ export class StripeProjectsAdapter {
|
|
|
623
670
|
};
|
|
624
671
|
const authUrlMatch = msg.match(/https?:\/\/[^\s"'<>]+/i);
|
|
625
672
|
const fallbackKeys = Object.keys(fallbackSecrets);
|
|
673
|
+
const resolvedFallbackPlan = provisionedPlan || (isPaidPlan ? serviceId : parentPlans[0] || "free");
|
|
626
674
|
return {
|
|
627
675
|
output: {
|
|
628
676
|
provider: "stripe_projects",
|
|
@@ -630,7 +678,11 @@ export class StripeProjectsAdapter {
|
|
|
630
678
|
tool: tool.slug,
|
|
631
679
|
upstreamService: tool.upstreamSlug,
|
|
632
680
|
resourceName,
|
|
633
|
-
provisionedPlan:
|
|
681
|
+
provisionedPlan: resolvedFallbackPlan,
|
|
682
|
+
billingTier: isPaidPlan ? "paid" : "free",
|
|
683
|
+
fundingSource: hasCustomerStripeByok
|
|
684
|
+
? "customer_byok_stripe"
|
|
685
|
+
: "muxo_master_wallet",
|
|
634
686
|
envVarKeys: fallbackKeys,
|
|
635
687
|
vaultSavedKeys: fallbackKeys,
|
|
636
688
|
secretKeysSaved: fallbackKeys,
|
|
@@ -646,7 +698,7 @@ export class StripeProjectsAdapter {
|
|
|
646
698
|
providerSlug: tool.providerSlug,
|
|
647
699
|
providerName: tool.providerName,
|
|
648
700
|
serviceSlug: serviceId,
|
|
649
|
-
planSlug:
|
|
701
|
+
planSlug: resolvedFallbackPlan,
|
|
650
702
|
status: "active",
|
|
651
703
|
secrets: fallbackSecrets,
|
|
652
704
|
externalResourceId: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
@@ -672,7 +724,9 @@ export class StripeProjectsAdapter {
|
|
|
672
724
|
tool: tool.slug,
|
|
673
725
|
upstreamService: tool.upstreamSlug,
|
|
674
726
|
resourceName,
|
|
675
|
-
provisionedPlan,
|
|
727
|
+
provisionedPlan: provisionedPlan || (isPaidPlan ? serviceId : parentPlans[0] || "free"),
|
|
728
|
+
billingTier: isPaidPlan ? "paid" : "free",
|
|
729
|
+
fundingSource: hasCustomerStripeByok ? "customer_byok_stripe" : "muxo_master_wallet",
|
|
676
730
|
envVarKeys,
|
|
677
731
|
vaultSavedKeys: envVarKeys,
|
|
678
732
|
secretKeysSaved: envVarKeys,
|
|
@@ -8,10 +8,12 @@ import type { MemoryContextSummary, MemoryRecordKind } from "../types.js";
|
|
|
8
8
|
export declare class SupermemoryAdapter {
|
|
9
9
|
private readonly config;
|
|
10
10
|
private readonly client;
|
|
11
|
+
private readonly byokClients;
|
|
11
12
|
private unavailableUntil;
|
|
12
13
|
constructor(config: MuxoConfig);
|
|
14
|
+
private resolveClient;
|
|
13
15
|
private withTimeout;
|
|
14
|
-
isEnabled(): boolean;
|
|
16
|
+
isEnabled(apiKeyOverride?: string | null): boolean;
|
|
15
17
|
/**
|
|
16
18
|
* Derives a strict Supermemory v5 namespace (`^[a-zA-Z0-9_:-]+$`) scoped to a workspace.
|
|
17
19
|
*/
|
|
@@ -24,15 +26,17 @@ export declare class SupermemoryAdapter {
|
|
|
24
26
|
sanitizeContent(raw: string): string;
|
|
25
27
|
/**
|
|
26
28
|
* Fetches the workspace's static + dynamic profile and optionally semantic search results
|
|
27
|
-
* in a single fail-open call.
|
|
29
|
+
* in a single fail-open call. Supports customer BYOK `supermemory` keys via `apiKeyOverride`.
|
|
28
30
|
*/
|
|
29
31
|
getContextForWorkspace(workspaceIdOrParams: string | {
|
|
30
32
|
workspaceId: string;
|
|
31
33
|
query?: string;
|
|
32
34
|
limit?: number;
|
|
33
|
-
|
|
35
|
+
apiKeyOverride?: string | null;
|
|
36
|
+
}, optionalQuery?: string, optionalApiKeyOverride?: string | null): Promise<MemoryContextSummary>;
|
|
34
37
|
/**
|
|
35
|
-
* Stores a governed, secret-sanitized document/memory in the workspace's Supermemory v5 namespace
|
|
38
|
+
* Stores a governed, secret-sanitized document/memory in the workspace's Supermemory v5 namespace
|
|
39
|
+
* with `dreaming: "instant"` so profile facts are synthesized immediately.
|
|
36
40
|
*/
|
|
37
41
|
addMemory(params: {
|
|
38
42
|
workspaceId: string;
|
|
@@ -41,11 +45,14 @@ export declare class SupermemoryAdapter {
|
|
|
41
45
|
content: string;
|
|
42
46
|
kind: MemoryRecordKind;
|
|
43
47
|
metadata?: Record<string, unknown>;
|
|
48
|
+
apiKeyOverride?: string | null;
|
|
49
|
+
dreaming?: "auto" | "instant";
|
|
44
50
|
}): Promise<{
|
|
45
51
|
documentId: string;
|
|
46
52
|
namespace: string;
|
|
47
53
|
status: string;
|
|
48
54
|
sanitizedContent: string;
|
|
55
|
+
fundingSource: "muxo_funded" | "customer_byok_supermemory" | "local_fallback";
|
|
49
56
|
}>;
|
|
50
57
|
recordExecutionMemory(params: {
|
|
51
58
|
workspaceId: string;
|
|
@@ -55,12 +62,26 @@ export declare class SupermemoryAdapter {
|
|
|
55
62
|
reason: string;
|
|
56
63
|
status: string;
|
|
57
64
|
summary: string;
|
|
65
|
+
apiKeyOverride?: string | null;
|
|
58
66
|
}): Promise<string | null>;
|
|
59
67
|
/**
|
|
60
68
|
* Deletes/forgets a memory document from the workspace's Supermemory v5 namespace.
|
|
61
69
|
*/
|
|
62
|
-
deleteMemory(workspaceId: string, documentId: string): Promise<{
|
|
70
|
+
deleteMemory(workspaceId: string, documentId: string, apiKeyOverride?: string | null): Promise<{
|
|
63
71
|
deleted: boolean;
|
|
64
72
|
namespace: string;
|
|
65
73
|
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Semantically searches and forgets/prunes outdated memories in Supermemory v5 matching a query.
|
|
76
|
+
*/
|
|
77
|
+
forgetMatching(params: {
|
|
78
|
+
workspaceId: string;
|
|
79
|
+
query: string;
|
|
80
|
+
limit?: number;
|
|
81
|
+
apiKeyOverride?: string | null;
|
|
82
|
+
}): Promise<{
|
|
83
|
+
namespace: string;
|
|
84
|
+
deletedRemoteIds: string[];
|
|
85
|
+
fundingSource: "muxo_funded" | "customer_byok_supermemory" | "local_fallback";
|
|
86
|
+
}>;
|
|
66
87
|
}
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import Supermemory from "supermemory";
|
|
3
|
+
// Profile buckets can hold plain strings or memory objects depending on API version.
|
|
4
|
+
function toFactTexts(items) {
|
|
5
|
+
if (!Array.isArray(items))
|
|
6
|
+
return [];
|
|
7
|
+
return items
|
|
8
|
+
.map((item) => {
|
|
9
|
+
if (item == null)
|
|
10
|
+
return "";
|
|
11
|
+
if (typeof item !== "object")
|
|
12
|
+
return String(item);
|
|
13
|
+
const o = item;
|
|
14
|
+
const text = o.memory ?? o.content ?? o.text ?? o.fact ?? o.value ?? o.summary ?? o.title;
|
|
15
|
+
return typeof text === "string" ? text : JSON.stringify(item);
|
|
16
|
+
})
|
|
17
|
+
.map((s) => s.trim())
|
|
18
|
+
.filter(Boolean);
|
|
19
|
+
}
|
|
3
20
|
/**
|
|
4
21
|
* Supermemory v5 Contextual Brain & Context-Aware Tool Call Adapter.
|
|
5
22
|
* Uses deterministic per-workspace namespaces (`/ns/muxo-v5-<hash>/...`)
|
|
@@ -8,6 +25,7 @@ import Supermemory from "supermemory";
|
|
|
8
25
|
export class SupermemoryAdapter {
|
|
9
26
|
config;
|
|
10
27
|
client;
|
|
28
|
+
byokClients = new Map();
|
|
11
29
|
unavailableUntil = 0;
|
|
12
30
|
constructor(config) {
|
|
13
31
|
this.config = config;
|
|
@@ -16,19 +34,48 @@ export class SupermemoryAdapter {
|
|
|
16
34
|
apiKey: config.supermemoryApiKey,
|
|
17
35
|
baseUrl: config.supermemoryBaseUrl,
|
|
18
36
|
maxRetries: 0,
|
|
37
|
+
timeoutInSeconds: 2,
|
|
19
38
|
});
|
|
20
39
|
}
|
|
21
40
|
else {
|
|
22
41
|
this.client = null;
|
|
23
42
|
}
|
|
24
43
|
}
|
|
25
|
-
|
|
44
|
+
resolveClient(apiKeyOverride) {
|
|
45
|
+
const trimmedByok = String(apiKeyOverride || "").trim();
|
|
46
|
+
if (trimmedByok) {
|
|
47
|
+
let byokClient = this.byokClients.get(trimmedByok);
|
|
48
|
+
if (!byokClient) {
|
|
49
|
+
byokClient = new Supermemory({
|
|
50
|
+
apiKey: trimmedByok,
|
|
51
|
+
baseUrl: this.config.supermemoryBaseUrl,
|
|
52
|
+
maxRetries: 0,
|
|
53
|
+
timeoutInSeconds: 2,
|
|
54
|
+
});
|
|
55
|
+
this.byokClients.set(trimmedByok, byokClient);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
client: byokClient,
|
|
59
|
+
fundingSource: "customer_byok_supermemory",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (this.client) {
|
|
63
|
+
return {
|
|
64
|
+
client: this.client,
|
|
65
|
+
fundingSource: "muxo_funded",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
client: null,
|
|
70
|
+
fundingSource: "local_fallback",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
withTimeout(fn, ms = 1000) {
|
|
26
74
|
if (Date.now() < this.unavailableUntil) {
|
|
27
|
-
p.catch(() => { });
|
|
28
75
|
return Promise.resolve(null);
|
|
29
76
|
}
|
|
30
77
|
return Promise.race([
|
|
31
|
-
|
|
78
|
+
fn(),
|
|
32
79
|
new Promise((resolve) => {
|
|
33
80
|
const t = setTimeout(() => {
|
|
34
81
|
this.unavailableUntil = Date.now() + 30_000;
|
|
@@ -41,8 +88,8 @@ export class SupermemoryAdapter {
|
|
|
41
88
|
return null;
|
|
42
89
|
});
|
|
43
90
|
}
|
|
44
|
-
isEnabled() {
|
|
45
|
-
return Boolean(this.client);
|
|
91
|
+
isEnabled(apiKeyOverride) {
|
|
92
|
+
return Boolean(this.resolveClient(apiKeyOverride).client);
|
|
46
93
|
}
|
|
47
94
|
/**
|
|
48
95
|
* Derives a strict Supermemory v5 namespace (`^[a-zA-Z0-9_:-]+$`) scoped to a workspace.
|
|
@@ -70,21 +117,29 @@ export class SupermemoryAdapter {
|
|
|
70
117
|
}
|
|
71
118
|
/**
|
|
72
119
|
* Fetches the workspace's static + dynamic profile and optionally semantic search results
|
|
73
|
-
* in a single fail-open call.
|
|
120
|
+
* in a single fail-open call. Supports customer BYOK `supermemory` keys via `apiKeyOverride`.
|
|
74
121
|
*/
|
|
75
|
-
async getContextForWorkspace(workspaceIdOrParams, optionalQuery) {
|
|
122
|
+
async getContextForWorkspace(workspaceIdOrParams, optionalQuery, optionalApiKeyOverride) {
|
|
76
123
|
const params = typeof workspaceIdOrParams === "string"
|
|
77
|
-
? {
|
|
124
|
+
? {
|
|
125
|
+
workspaceId: workspaceIdOrParams,
|
|
126
|
+
query: optionalQuery,
|
|
127
|
+
limit: 5,
|
|
128
|
+
apiKeyOverride: optionalApiKeyOverride,
|
|
129
|
+
}
|
|
78
130
|
: workspaceIdOrParams;
|
|
79
131
|
const namespace = this.namespaceForWorkspace(params.workspaceId);
|
|
80
|
-
|
|
132
|
+
const { client, fundingSource } = this.resolveClient(params.apiKeyOverride);
|
|
133
|
+
if (!client) {
|
|
81
134
|
return {
|
|
82
135
|
enabled: false,
|
|
83
136
|
namespace,
|
|
137
|
+
fundingSource,
|
|
84
138
|
staticFacts: [],
|
|
85
139
|
dynamicContext: [],
|
|
86
140
|
recalledMemories: [],
|
|
87
141
|
formattedPromptContext: "Supermemory v5 disabled (no API key configured).",
|
|
142
|
+
profileMarkdown: "",
|
|
88
143
|
profile: { static: [], dynamic: [], preferences: [] },
|
|
89
144
|
relevantMemories: [],
|
|
90
145
|
};
|
|
@@ -95,11 +150,11 @@ export class SupermemoryAdapter {
|
|
|
95
150
|
let preferences = [];
|
|
96
151
|
const relevantMemories = [];
|
|
97
152
|
const [profileOutcome, searchOutcome] = await Promise.allSettled([
|
|
98
|
-
this.withTimeout(
|
|
153
|
+
this.withTimeout(() => client.profile(namespace, {
|
|
99
154
|
...(params.query ? { q: params.query } : {}),
|
|
100
155
|
}), 1000),
|
|
101
156
|
params.query && params.query.trim().length > 0
|
|
102
|
-
? this.withTimeout(
|
|
157
|
+
? this.withTimeout(() => client.search(namespace, {
|
|
103
158
|
query: params.query.trim(),
|
|
104
159
|
limit,
|
|
105
160
|
searchMode: "hybrid",
|
|
@@ -110,15 +165,9 @@ export class SupermemoryAdapter {
|
|
|
110
165
|
]);
|
|
111
166
|
if (profileOutcome.status === "fulfilled" && profileOutcome.value) {
|
|
112
167
|
const profileRes = profileOutcome.value;
|
|
113
|
-
staticFacts =
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
dynamicFacts = Array.isArray(profileRes?.profile?.dynamic)
|
|
117
|
-
? profileRes.profile.dynamic.map(String)
|
|
118
|
-
: [];
|
|
119
|
-
preferences = Array.isArray(profileRes?.profile?.buckets?.preferences)
|
|
120
|
-
? profileRes.profile.buckets.preferences.map(String)
|
|
121
|
-
: [];
|
|
168
|
+
staticFacts = toFactTexts(profileRes?.profile?.static);
|
|
169
|
+
dynamicFacts = toFactTexts(profileRes?.profile?.dynamic);
|
|
170
|
+
preferences = toFactTexts(profileRes?.profile?.buckets?.preferences);
|
|
122
171
|
}
|
|
123
172
|
if (searchOutcome.status === "fulfilled" && searchOutcome.value) {
|
|
124
173
|
const searchRes = searchOutcome.value;
|
|
@@ -150,13 +199,25 @@ export class SupermemoryAdapter {
|
|
|
150
199
|
if (relevantMemories.length > 0) {
|
|
151
200
|
promptLines.push(`Recalled Memories: ${relevantMemories.map((m) => `${m.title}: ${m.snippet}`).join(" | ")}`);
|
|
152
201
|
}
|
|
202
|
+
const mdLines = [`## Workspace Profile (${namespace})`];
|
|
203
|
+
if (staticFacts.length > 0) {
|
|
204
|
+
mdLines.push("### Static Facts", ...staticFacts.map((f) => `- ${f}`));
|
|
205
|
+
}
|
|
206
|
+
if (dynamicFacts.length > 0) {
|
|
207
|
+
mdLines.push("### Dynamic Context", ...dynamicFacts.map((f) => `- ${f}`));
|
|
208
|
+
}
|
|
209
|
+
if (preferences.length > 0) {
|
|
210
|
+
mdLines.push("### Preferences", ...preferences.map((f) => `- ${f}`));
|
|
211
|
+
}
|
|
153
212
|
return {
|
|
154
213
|
enabled: true,
|
|
155
214
|
namespace,
|
|
215
|
+
fundingSource,
|
|
156
216
|
staticFacts,
|
|
157
217
|
dynamicContext: dynamicFacts,
|
|
158
218
|
recalledMemories: relevantMemories,
|
|
159
219
|
formattedPromptContext: promptLines.join("\n"),
|
|
220
|
+
profileMarkdown: mdLines.join("\n"),
|
|
160
221
|
profile: {
|
|
161
222
|
static: staticFacts,
|
|
162
223
|
dynamic: dynamicFacts,
|
|
@@ -166,24 +227,28 @@ export class SupermemoryAdapter {
|
|
|
166
227
|
};
|
|
167
228
|
}
|
|
168
229
|
/**
|
|
169
|
-
* Stores a governed, secret-sanitized document/memory in the workspace's Supermemory v5 namespace
|
|
230
|
+
* Stores a governed, secret-sanitized document/memory in the workspace's Supermemory v5 namespace
|
|
231
|
+
* with `dreaming: "instant"` so profile facts are synthesized immediately.
|
|
170
232
|
*/
|
|
171
233
|
async addMemory(params) {
|
|
172
234
|
const namespace = this.namespaceForWorkspace(params.workspaceId);
|
|
173
235
|
const sanitizedContent = this.sanitizeContent(params.content);
|
|
174
236
|
const docId = params.documentId || `mem_${crypto.randomBytes(8).toString("hex")}`;
|
|
175
|
-
|
|
237
|
+
const { client, fundingSource } = this.resolveClient(params.apiKeyOverride);
|
|
238
|
+
if (!client) {
|
|
176
239
|
return {
|
|
177
240
|
documentId: docId,
|
|
178
241
|
namespace,
|
|
179
242
|
status: "local_only",
|
|
180
243
|
sanitizedContent,
|
|
244
|
+
fundingSource,
|
|
181
245
|
};
|
|
182
246
|
}
|
|
183
|
-
const res = await this.withTimeout(
|
|
247
|
+
const res = await this.withTimeout(() => client.add(namespace, {
|
|
184
248
|
id: docId,
|
|
185
249
|
content: `${params.title}\n\n${sanitizedContent}`,
|
|
186
250
|
taskType: "memory",
|
|
251
|
+
dreaming: params.dreaming || "instant",
|
|
187
252
|
metadata: {
|
|
188
253
|
title: params.title,
|
|
189
254
|
muxoWorkspaceId: params.workspaceId,
|
|
@@ -196,6 +261,7 @@ export class SupermemoryAdapter {
|
|
|
196
261
|
namespace,
|
|
197
262
|
status: String(res?.status || "queued"),
|
|
198
263
|
sanitizedContent,
|
|
264
|
+
fundingSource,
|
|
199
265
|
};
|
|
200
266
|
}
|
|
201
267
|
async recordExecutionMemory(params) {
|
|
@@ -205,6 +271,7 @@ export class SupermemoryAdapter {
|
|
|
205
271
|
title: `Execution: ${params.toolSlug} (${params.status})`,
|
|
206
272
|
content: params.summary,
|
|
207
273
|
kind: "execution_outcome",
|
|
274
|
+
apiKeyOverride: params.apiKeyOverride,
|
|
208
275
|
metadata: {
|
|
209
276
|
toolSlug: params.toolSlug,
|
|
210
277
|
lane: params.lane,
|
|
@@ -221,13 +288,14 @@ export class SupermemoryAdapter {
|
|
|
221
288
|
/**
|
|
222
289
|
* Deletes/forgets a memory document from the workspace's Supermemory v5 namespace.
|
|
223
290
|
*/
|
|
224
|
-
async deleteMemory(workspaceId, documentId) {
|
|
291
|
+
async deleteMemory(workspaceId, documentId, apiKeyOverride) {
|
|
225
292
|
const namespace = this.namespaceForWorkspace(workspaceId);
|
|
226
|
-
|
|
293
|
+
const { client } = this.resolveClient(apiKeyOverride);
|
|
294
|
+
if (!client) {
|
|
227
295
|
return { deleted: true, namespace };
|
|
228
296
|
}
|
|
229
297
|
try {
|
|
230
|
-
const res = await this.withTimeout(
|
|
298
|
+
const res = await this.withTimeout(() => client.documents.delete(namespace, {
|
|
231
299
|
ids: [documentId],
|
|
232
300
|
}), 1200);
|
|
233
301
|
return {
|
|
@@ -239,4 +307,46 @@ export class SupermemoryAdapter {
|
|
|
239
307
|
return { deleted: false, namespace };
|
|
240
308
|
}
|
|
241
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Semantically searches and forgets/prunes outdated memories in Supermemory v5 matching a query.
|
|
312
|
+
*/
|
|
313
|
+
async forgetMatching(params) {
|
|
314
|
+
const namespace = this.namespaceForWorkspace(params.workspaceId);
|
|
315
|
+
const { client, fundingSource } = this.resolveClient(params.apiKeyOverride);
|
|
316
|
+
if (!client || !params.query.trim()) {
|
|
317
|
+
return {
|
|
318
|
+
namespace,
|
|
319
|
+
deletedRemoteIds: [],
|
|
320
|
+
fundingSource,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
const searchRes = await this.withTimeout(() => client.search(namespace, {
|
|
325
|
+
query: params.query.trim(),
|
|
326
|
+
limit: Math.min(10, Math.max(1, Number(params.limit || 5))),
|
|
327
|
+
searchMode: "hybrid",
|
|
328
|
+
include: { documents: true, forgotten: false, related: false },
|
|
329
|
+
rewriteQuery: false,
|
|
330
|
+
}), 1200);
|
|
331
|
+
const docIds = Array.from(new Set((searchRes?.results || [])
|
|
332
|
+
.map((r) => String(r.included?.document?.id || r.id || ""))
|
|
333
|
+
.filter(Boolean)));
|
|
334
|
+
if (docIds.length > 0) {
|
|
335
|
+
await this.withTimeout(() => client.documents.delete(namespace, { ids: docIds }), 1200);
|
|
336
|
+
return {
|
|
337
|
+
namespace,
|
|
338
|
+
deletedRemoteIds: docIds,
|
|
339
|
+
fundingSource,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Fail-open on remote pruning errors
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
namespace,
|
|
348
|
+
deletedRemoteIds: [],
|
|
349
|
+
fundingSource,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
242
352
|
}
|