@muxoai/platform 1.4.2 → 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 +88 -0
- package/dist/durable-workflow.d.ts +71 -4
- package/dist/durable-workflow.js +199 -5
- package/dist/engine.d.ts +64 -2
- package/dist/engine.js +147 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mcp-schema.js +22 -1
- package/dist/mcp.js +62 -3
- 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/sdk.d.ts +24 -1
- package/dist/sdk.js +53 -2
- package/dist/server.js +128 -3
- package/dist/types.d.ts +19 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/plugins/muxo/.claude-plugin/plugin.json +1 -1
- package/plugins/muxo/.codex-plugin/plugin.json +2 -2
- package/plugins/muxo/.cursor-plugin/plugin.json +1 -1
- package/plugins/muxo/plugin.json +2 -2
package/dist/engine.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { isStripeProjectsExclusiveProvider, normalizeStripeProjectsProviderSlug, wrapMuxoConnectUrl, } from "./composio-catalog.js";
|
|
3
3
|
import { APPROVED_PLAN_STATUSES, approvalRequiredError, buildApprovalHumanHandoff, buildApprovalUrl, buildOAuthHumanHandoff, clampWaitSeconds, looksLikeToolSlug, unknownToolError, } from "./mcp-schema.js";
|
|
4
|
-
import { completeCloudProvisioningWorkflow, createCloudProvisioningWorkflow, normalizeWorkflowTarget, workflowNotFoundError, } from "./durable-workflow.js";
|
|
4
|
+
import { completeCloudProvisioningWorkflow, createCloudProvisioningWorkflow, exportTemporalEventHistory, normalizeWorkflowTarget, rollbackDurableWorkflow as runSagaRollbackOnWorkflow, signalDurableWorkflow as sendSignalToWorkflow, workflowNotFoundError, } from "./durable-workflow.js";
|
|
5
5
|
import { buildMemoryKnowledgeGraph } from "./memory-graph.js";
|
|
6
|
+
import { MUXO_COMMERCIAL_PLAYBOOKS, buildCommercialRoiReport, buildOtelTraceExport, buildPlaybookSagaExecution, compileWorkspacePolicyToCedarAndRego, evaluateCedarAndOpaPolicy, getCommercialPlaybook, } from "./oss-suite.js";
|
|
6
7
|
import { resolveNaturalLanguageIntent, } from "./nl.js";
|
|
7
8
|
import { DEFAULT_WORKSPACE_POLICY, buildLlmPolicyAndGovernanceBrief, compileNaturalLanguageGuardrailWithLlm, describePolicyInPlainEnglish, formatHumanFriendlyExplanation, parseNaturalLanguageGuardrail, simulatePolicyEvaluation, } from "./policy.js";
|
|
8
9
|
import { ComposioInstantAdapter } from "./providers/composio-instant.js";
|
|
@@ -1130,18 +1131,25 @@ export class MuxoEngine {
|
|
|
1130
1131
|
}
|
|
1131
1132
|
/**
|
|
1132
1133
|
* Synthesizes a Bi-Temporal Knowledge Graph (entities, active relationships, superseded historical relationships,
|
|
1133
|
-
* Mermaid diagram, and human + technical explanations)
|
|
1134
|
+
* Mermaid diagram, point-in-time `asOf` time-travel, 2-hop BFS subgraph, and human + technical explanations)
|
|
1135
|
+
* directly from SQLite temporal_facts, memories, resources, and connections.
|
|
1134
1136
|
*/
|
|
1135
|
-
async getMemoryGraph(ctx,
|
|
1137
|
+
async getMemoryGraph(ctx, queryOrOptions) {
|
|
1136
1138
|
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
1137
|
-
const
|
|
1139
|
+
const opts = typeof queryOrOptions === "string"
|
|
1140
|
+
? { query: queryOrOptions }
|
|
1141
|
+
: queryOrOptions || {};
|
|
1142
|
+
const overview = await this.getMemoryOverview(ctx, opts.query);
|
|
1138
1143
|
return buildMemoryKnowledgeGraph({
|
|
1139
1144
|
workspace: ws,
|
|
1140
1145
|
namespace: overview.namespace,
|
|
1141
|
-
query,
|
|
1146
|
+
query: opts.query,
|
|
1147
|
+
asOf: opts.asOf || null,
|
|
1148
|
+
focalEntity: opts.focalEntity || null,
|
|
1149
|
+
maxHops: opts.maxHops,
|
|
1142
1150
|
facts: this.store.listTemporalFacts(ws.id, {
|
|
1143
1151
|
includeHistorical: true,
|
|
1144
|
-
query,
|
|
1152
|
+
query: opts.query,
|
|
1145
1153
|
limit: 100,
|
|
1146
1154
|
}),
|
|
1147
1155
|
resources: this.store.listResources(ws.id),
|
|
@@ -2473,6 +2481,139 @@ export class MuxoEngine {
|
|
|
2473
2481
|
listDurableWorkflows(workspaceId) {
|
|
2474
2482
|
return Array.from(this.durableWorkflows.values()).filter((w) => w.workspaceId === workspaceId);
|
|
2475
2483
|
}
|
|
2484
|
+
getDurableWorkflow(ctx, workflowId) {
|
|
2485
|
+
const wf = this.durableWorkflows.get(workflowId);
|
|
2486
|
+
if (!wf || wf.workspaceId !== ctx.workspace.id) {
|
|
2487
|
+
throw workflowNotFoundError(workflowId);
|
|
2488
|
+
}
|
|
2489
|
+
return wf;
|
|
2490
|
+
}
|
|
2491
|
+
getDurableWorkflowHistory(ctx, workflowId) {
|
|
2492
|
+
const wf = this.getDurableWorkflow(ctx, workflowId);
|
|
2493
|
+
return exportTemporalEventHistory(wf);
|
|
2494
|
+
}
|
|
2495
|
+
signalDurableWorkflow(ctx, workflowId, params) {
|
|
2496
|
+
const wf = this.getDurableWorkflow(ctx, workflowId);
|
|
2497
|
+
return sendSignalToWorkflow(wf, params);
|
|
2498
|
+
}
|
|
2499
|
+
rollbackDurableWorkflow(ctx, workflowId, params) {
|
|
2500
|
+
const wf = this.getDurableWorkflow(ctx, workflowId);
|
|
2501
|
+
return runSagaRollbackOnWorkflow(wf, params);
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* AWS Cedar & Open Policy Agent (OPA / Rego) Policy-as-Code Compiler & Evaluator.
|
|
2505
|
+
*/
|
|
2506
|
+
getPolicyAsCodeBundle(ctx) {
|
|
2507
|
+
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
2508
|
+
return compileWorkspacePolicyToCedarAndRego(ws.policy, ws);
|
|
2509
|
+
}
|
|
2510
|
+
async evaluatePolicyAsCode(ctx, params) {
|
|
2511
|
+
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
2512
|
+
let resolvedSlug = String(params.toolSlug || "instant.web.search").trim();
|
|
2513
|
+
let riskLevel = params.riskLevel;
|
|
2514
|
+
let creditCost = params.creditCost;
|
|
2515
|
+
let lane = params.lane;
|
|
2516
|
+
try {
|
|
2517
|
+
const tool = await this.inspectTool(resolvedSlug);
|
|
2518
|
+
resolvedSlug = tool.slug;
|
|
2519
|
+
if (!riskLevel)
|
|
2520
|
+
riskLevel = tool.riskLevel;
|
|
2521
|
+
if (typeof creditCost !== "number")
|
|
2522
|
+
creditCost = tool.creditCost;
|
|
2523
|
+
if (!lane)
|
|
2524
|
+
lane = tool.lane;
|
|
2525
|
+
}
|
|
2526
|
+
catch {
|
|
2527
|
+
// Fall back to slug prefix heuristics
|
|
2528
|
+
}
|
|
2529
|
+
return evaluateCedarAndOpaPolicy({
|
|
2530
|
+
policy: ws.policy,
|
|
2531
|
+
workspace: ws,
|
|
2532
|
+
toolSlug: resolvedSlug,
|
|
2533
|
+
input: params.input || {},
|
|
2534
|
+
riskLevel,
|
|
2535
|
+
creditCost,
|
|
2536
|
+
lane,
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
/**
|
|
2540
|
+
* OpenTelemetry (OTel GenAI / MCP Semantic Conventions) & Langfuse Trace Exporter.
|
|
2541
|
+
*/
|
|
2542
|
+
exportOtelTraces(ctx, limit = 25) {
|
|
2543
|
+
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
2544
|
+
const runs = this.store.listRuns(ws.id, limit);
|
|
2545
|
+
const receipts = this.store.listReceipts(ws.id, limit);
|
|
2546
|
+
const plans = this.store.listPlans(ws.id, limit);
|
|
2547
|
+
return buildOtelTraceExport({
|
|
2548
|
+
workspace: ws,
|
|
2549
|
+
runs,
|
|
2550
|
+
receipts,
|
|
2551
|
+
plans,
|
|
2552
|
+
});
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* Turnkey Commercial Business Saga Playbooks.
|
|
2556
|
+
*/
|
|
2557
|
+
listCommercialPlaybooks() {
|
|
2558
|
+
return MUXO_COMMERCIAL_PLAYBOOKS;
|
|
2559
|
+
}
|
|
2560
|
+
runCommercialPlaybook(ctx, params) {
|
|
2561
|
+
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
2562
|
+
const playbook = getCommercialPlaybook(params.slug);
|
|
2563
|
+
if (!playbook) {
|
|
2564
|
+
const err = new Error(`Unknown commercial playbook '${params.slug}'. Available playbooks: ${MUXO_COMMERCIAL_PLAYBOOKS.map((p) => p.slug).join(", ")}`);
|
|
2565
|
+
err.statusCode = 404;
|
|
2566
|
+
err.code = "PLAYBOOK_NOT_FOUND";
|
|
2567
|
+
throw err;
|
|
2568
|
+
}
|
|
2569
|
+
const wfId = `wf_saga_${Date.now()}_${crypto.randomBytes(4).toString("hex")}`;
|
|
2570
|
+
const executed = buildPlaybookSagaExecution({
|
|
2571
|
+
id: wfId,
|
|
2572
|
+
workspaceId: ws.id,
|
|
2573
|
+
workspaceSlug: ws.slug,
|
|
2574
|
+
playbook,
|
|
2575
|
+
input: params.input || {},
|
|
2576
|
+
});
|
|
2577
|
+
this.durableWorkflows.set(wfId, executed.workflow);
|
|
2578
|
+
const savedFact = this.store.upsertTemporalFact({
|
|
2579
|
+
workspaceId: ws.id,
|
|
2580
|
+
subject: executed.temporalFact.subject,
|
|
2581
|
+
predicate: executed.temporalFact.predicate,
|
|
2582
|
+
object: executed.temporalFact.object,
|
|
2583
|
+
summary: executed.temporalFact.summary,
|
|
2584
|
+
confidence: 0.99,
|
|
2585
|
+
sourceKind: "execution_outcome",
|
|
2586
|
+
sourceReferenceId: executed.temporalFact.episodeId,
|
|
2587
|
+
});
|
|
2588
|
+
return {
|
|
2589
|
+
ok: true,
|
|
2590
|
+
playbook: executed.playbook,
|
|
2591
|
+
workflow: executed.workflow,
|
|
2592
|
+
temporalFact: savedFact,
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
/**
|
|
2596
|
+
* FinOps & Commercial ROI Unit-Economics Analytics.
|
|
2597
|
+
*/
|
|
2598
|
+
getCommercialRoiReport(ctx) {
|
|
2599
|
+
const ws = this.store.getWorkspace(ctx.workspace.id);
|
|
2600
|
+
const runs = this.store.listRuns(ws.id, 100);
|
|
2601
|
+
const plans = this.store.listPlans(ws.id, 100);
|
|
2602
|
+
const resources = this.store.listResources(ws.id);
|
|
2603
|
+
const byokKeys = this.store.listByokKeys(ws.id);
|
|
2604
|
+
const temporalFacts = this.store.listTemporalFacts(ws.id, {
|
|
2605
|
+
includeHistorical: false,
|
|
2606
|
+
limit: 100,
|
|
2607
|
+
});
|
|
2608
|
+
return buildCommercialRoiReport({
|
|
2609
|
+
workspace: ws,
|
|
2610
|
+
runs,
|
|
2611
|
+
plans,
|
|
2612
|
+
resources,
|
|
2613
|
+
byokKeys,
|
|
2614
|
+
temporalFacts,
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2476
2617
|
/**
|
|
2477
2618
|
* Hybrid Semantic Vector + Bi-Temporal Recall (`@cf/baai/bge-base-en-v1.5` + Vectorize model).
|
|
2478
2619
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { getConfig, ROOT_DIR, type MuxoConfig } from "./config.js";
|
|
2
|
+
export * from "./durable-workflow.js";
|
|
2
3
|
export { MuxoEngine, type ExecutionContext } from "./engine.js";
|
|
3
4
|
export { handleJsonRpcMcpRequest, MUXO_MCP_TOOLS, type McpToolDefinition } from "./mcp.js";
|
|
5
|
+
export * from "./memory-graph.js";
|
|
6
|
+
export * from "./oss-suite.js";
|
|
4
7
|
export { MuxoClient, type MuxoClientOptions } from "./sdk.js";
|
|
5
8
|
export { createMuxoServer } from "./server.js";
|
|
6
9
|
export { MuxoStore } from "./store.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { getConfig, ROOT_DIR } from "./config.js";
|
|
2
|
+
export * from "./durable-workflow.js";
|
|
2
3
|
export { MuxoEngine } from "./engine.js";
|
|
3
4
|
export { handleJsonRpcMcpRequest, MUXO_MCP_TOOLS } from "./mcp.js";
|
|
5
|
+
export * from "./memory-graph.js";
|
|
6
|
+
export * from "./oss-suite.js";
|
|
4
7
|
export { MuxoClient } from "./sdk.js";
|
|
5
8
|
export { createMuxoServer } from "./server.js";
|
|
6
9
|
export { MuxoStore } from "./store.js";
|
package/dist/mcp-schema.js
CHANGED
|
@@ -1057,6 +1057,11 @@ export const MUXO_MCP_TOOLS = [
|
|
|
1057
1057
|
"set_guardrail",
|
|
1058
1058
|
"reset_guardrails",
|
|
1059
1059
|
"check_policy",
|
|
1060
|
+
"cedar_policy",
|
|
1061
|
+
"otel_traces",
|
|
1062
|
+
"roi_analytics",
|
|
1063
|
+
"playbooks",
|
|
1064
|
+
"run_playbook",
|
|
1060
1065
|
"kill_switch",
|
|
1061
1066
|
"governance_status",
|
|
1062
1067
|
"scan_context",
|
|
@@ -1064,7 +1069,7 @@ export const MUXO_MCP_TOOLS = [
|
|
|
1064
1069
|
"switch_workspace",
|
|
1065
1070
|
"onboard_team",
|
|
1066
1071
|
],
|
|
1067
|
-
description: "Control-plane operation: 'inspect' (default), 'remember' (save fact/preference), 'recall' (list memories), 'forget' (delete matching memories), 'memory_graph' (bi-temporal entity/relationship lineage), 'set_guardrail' (apply plain-English or structured parameter_rules guardrail), 'reset_guardrails' (restore default safe guardrails), 'check_policy' (dry-run evaluate tool_slug + input against policy and parameter guardrails before planning), 'kill_switch' (pause/resume agent execution), 'governance_status' (Microsoft 9-module status + LLM policy brief), 'scan_context' (OWASP ASI-06 check), 'list_workspaces', 'switch_workspace', or 'onboard_team'",
|
|
1072
|
+
description: "Control-plane operation: 'inspect' (default), 'remember' (save fact/preference), 'recall' (list memories), 'forget' (delete matching memories), 'memory_graph' (Graphiti bi-temporal entity/relationship lineage with optional as_of time-travel & focal_entity 2-hop BFS), 'set_guardrail' (apply plain-English or structured parameter_rules guardrail), 'reset_guardrails' (restore default safe guardrails), 'check_policy' (dry-run evaluate tool_slug + input against policy and parameter guardrails before planning), 'cedar_policy' (compile/evaluate AWS Cedar & OPA Rego policy-as-code), 'otel_traces' (export W3C OpenTelemetry GenAI/MCP spans & Langfuse batch), 'roi_analytics' (FinOps & BYOK unit-economics ROI report), 'playbooks' / 'run_playbook' (list or execute turnkey multi-step Temporal Saga playbooks), 'kill_switch' (pause/resume agent execution), 'governance_status' (Microsoft 9-module status + LLM policy brief), 'scan_context' (OWASP ASI-06 check), 'list_workspaces', 'switch_workspace', or 'onboard_team'",
|
|
1068
1073
|
},
|
|
1069
1074
|
prompt: {
|
|
1070
1075
|
type: "string",
|
|
@@ -1161,6 +1166,22 @@ export const MUXO_MCP_TOOLS = [
|
|
|
1161
1166
|
type: "boolean",
|
|
1162
1167
|
description: "If true, attach the Bi-Temporal Knowledge Graph (nodes, activeEdges, historicalEdges, mermaid) to the context response",
|
|
1163
1168
|
},
|
|
1169
|
+
as_of: {
|
|
1170
|
+
type: "string",
|
|
1171
|
+
description: "Optional ISO-8601 timestamp for Graphiti point-in-time ('as-of') bi-temporal knowledge graph reconstruction",
|
|
1172
|
+
},
|
|
1173
|
+
focal_entity: {
|
|
1174
|
+
type: "string",
|
|
1175
|
+
description: "Optional entity ID or label for k-hop BFS neighborhood subgraph extraction",
|
|
1176
|
+
},
|
|
1177
|
+
max_hops: {
|
|
1178
|
+
type: "number",
|
|
1179
|
+
description: "Maximum BFS traversal hops around focal_entity (1 to 4, default 2)",
|
|
1180
|
+
},
|
|
1181
|
+
slug: {
|
|
1182
|
+
type: "string",
|
|
1183
|
+
description: "Optional playbook slug when action='run_playbook' (e.g. 'fullstack-cloud-bootstrap', 'competitor-seo-growth-brief', 'incident-containment-audit', 'customer-release-readiness')",
|
|
1184
|
+
},
|
|
1164
1185
|
plan_id: {
|
|
1165
1186
|
type: "string",
|
|
1166
1187
|
description: "Optional plan ID to inspect context for",
|
package/dist/mcp.js
CHANGED
|
@@ -223,8 +223,53 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
|
|
|
223
223
|
: Array.isArray(args.parameterRules)
|
|
224
224
|
? args.parameterRules
|
|
225
225
|
: undefined;
|
|
226
|
+
const asOf = args.as_of || args.asOf ? String(args.as_of || args.asOf) : null;
|
|
227
|
+
const focalEntity = args.focal_entity || args.focalEntity
|
|
228
|
+
? String(args.focal_entity || args.focalEntity)
|
|
229
|
+
: null;
|
|
230
|
+
const rawMaxHops = args.max_hops ?? args.maxHops;
|
|
231
|
+
const maxHops = rawMaxHops !== undefined && rawMaxHops !== null
|
|
232
|
+
? Number(rawMaxHops)
|
|
233
|
+
: undefined;
|
|
226
234
|
if (action === "memory_graph") {
|
|
227
|
-
return engine.getMemoryGraph(ctx,
|
|
235
|
+
return engine.getMemoryGraph(ctx, {
|
|
236
|
+
query,
|
|
237
|
+
asOf,
|
|
238
|
+
focalEntity,
|
|
239
|
+
maxHops,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (action === "cedar_policy" || action === "policy_as_code") {
|
|
243
|
+
if (args.tool_slug || args.slug) {
|
|
244
|
+
return engine.evaluatePolicyAsCode(ctx, {
|
|
245
|
+
toolSlug: String(args.tool_slug || args.slug),
|
|
246
|
+
input: (args.input || args.arguments) || {},
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return engine.getPolicyAsCodeBundle(ctx);
|
|
250
|
+
}
|
|
251
|
+
if (action === "otel_traces" || action === "telemetry") {
|
|
252
|
+
return engine.exportOtelTraces(ctx, Number(args.limit || 25));
|
|
253
|
+
}
|
|
254
|
+
if (action === "roi_analytics" || action === "roi") {
|
|
255
|
+
return engine.getCommercialRoiReport(ctx);
|
|
256
|
+
}
|
|
257
|
+
if (action === "playbooks") {
|
|
258
|
+
return {
|
|
259
|
+
ok: true,
|
|
260
|
+
playbooks: engine.listCommercialPlaybooks(),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
if (action === "run_playbook") {
|
|
264
|
+
const slug = String(args.slug ||
|
|
265
|
+
args.playbook ||
|
|
266
|
+
query ||
|
|
267
|
+
prompt ||
|
|
268
|
+
"fullstack-cloud-bootstrap").trim();
|
|
269
|
+
return engine.runCommercialPlaybook(ctx, {
|
|
270
|
+
slug,
|
|
271
|
+
input: (args.input || args.arguments) || {},
|
|
272
|
+
});
|
|
228
273
|
}
|
|
229
274
|
if (action === "governance_status") {
|
|
230
275
|
return engine.getGovernanceOverview(ctx);
|
|
@@ -343,7 +388,12 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
|
|
|
343
388
|
}
|
|
344
389
|
const runCtx = await engine.getRunContext(ctx, query);
|
|
345
390
|
if (args.include_graph === true) {
|
|
346
|
-
const memoryGraph = await engine.getMemoryGraph(ctx,
|
|
391
|
+
const memoryGraph = await engine.getMemoryGraph(ctx, {
|
|
392
|
+
query,
|
|
393
|
+
asOf,
|
|
394
|
+
focalEntity,
|
|
395
|
+
maxHops,
|
|
396
|
+
});
|
|
347
397
|
return { ...runCtx, memoryGraph };
|
|
348
398
|
}
|
|
349
399
|
return runCtx;
|
|
@@ -425,7 +475,16 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
|
|
|
425
475
|
return engine.forgetWorkspaceMemoryMatching(ctx, query);
|
|
426
476
|
}
|
|
427
477
|
case "memory_graph":
|
|
428
|
-
return engine.getMemoryGraph(ctx,
|
|
478
|
+
return engine.getMemoryGraph(ctx, {
|
|
479
|
+
query: args.query ? String(args.query) : undefined,
|
|
480
|
+
asOf: args.as_of || args.asOf ? String(args.as_of || args.asOf) : null,
|
|
481
|
+
focalEntity: args.focal_entity || args.focalEntity
|
|
482
|
+
? String(args.focal_entity || args.focalEntity)
|
|
483
|
+
: null,
|
|
484
|
+
maxHops: args.max_hops !== undefined || args.maxHops !== undefined
|
|
485
|
+
? Number(args.max_hops ?? args.maxHops)
|
|
486
|
+
: undefined,
|
|
487
|
+
});
|
|
429
488
|
case "set_guardrail":
|
|
430
489
|
case "configure_guardrails": {
|
|
431
490
|
const rawParamRules = Array.isArray(args.parameter_rules)
|
package/dist/memory-graph.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConnectionRecord, GovernancePolicy, MemoryKnowledgeGraph, ProvisionedResource, TemporalGraphFact } from "./types.js";
|
|
1
|
+
import type { ConnectionRecord, GovernancePolicy, MemoryGraphEdge, MemoryGraphNode, MemoryKnowledgeGraph, ProvisionedResource, TemporalGraphFact } from "./types.js";
|
|
2
2
|
export interface MemoryGraphInput {
|
|
3
3
|
workspace: {
|
|
4
4
|
id: string;
|
|
@@ -9,13 +9,37 @@ export interface MemoryGraphInput {
|
|
|
9
9
|
};
|
|
10
10
|
namespace: string;
|
|
11
11
|
query?: string;
|
|
12
|
+
asOf?: string | null;
|
|
13
|
+
focalEntity?: string | null;
|
|
14
|
+
maxHops?: number;
|
|
12
15
|
facts: TemporalGraphFact[];
|
|
13
16
|
resources: Array<Pick<ProvisionedResource, "resourceName" | "status" | "providerName" | "serviceSlug">>;
|
|
14
17
|
activeConnections: Array<Pick<ConnectionRecord, "id" | "providerSlug" | "providerName" | "createdAt">>;
|
|
15
18
|
memoriesCount: number;
|
|
16
19
|
}
|
|
17
20
|
/**
|
|
18
|
-
*
|
|
21
|
+
* Graphiti-style Point-in-Time ("As-Of") Bi-Temporal Fact Filter.
|
|
22
|
+
* Reconstructs which facts were active at `asOf` vs. already retired by `asOf`,
|
|
23
|
+
* excluding facts created after `asOf`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function filterFactsAsOf(facts: TemporalGraphFact[], asOf?: string | null): {
|
|
26
|
+
scopedFacts: TemporalGraphFact[];
|
|
27
|
+
isActiveAtPointInTime: (fact: TemporalGraphFact) => boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Graphiti-style Multi-Hop Subgraph Community Traversal (BFS).
|
|
31
|
+
* Finds all nodes and edges within `maxHops` (default 2) of a focal entity.
|
|
32
|
+
*/
|
|
33
|
+
export declare function traverseSubgraphBfs(nodes: MemoryGraphNode[], edges: MemoryGraphEdge[], focalQuery: string, maxHops?: number): {
|
|
34
|
+
focalEntity: string;
|
|
35
|
+
maxHops: number;
|
|
36
|
+
nodes: MemoryGraphNode[];
|
|
37
|
+
edges: MemoryGraphEdge[];
|
|
38
|
+
hopDistances: Record<string, number>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Builds the Graphiti-inspired Bi-Temporal Knowledge Graph (nodes, active/historical edges,
|
|
42
|
+
* episodic provenance, point-in-time `asOf` time-travel, 2-hop BFS subgraph, and Mermaid preview)
|
|
19
43
|
* from runtime-agnostic inputs so the Node engine and the Edge Worker render identical graphs.
|
|
20
44
|
*/
|
|
21
45
|
export declare function buildMemoryKnowledgeGraph(input: MemoryGraphInput): MemoryKnowledgeGraph;
|
package/dist/memory-graph.js
CHANGED
|
@@ -1,11 +1,102 @@
|
|
|
1
1
|
import { formatHumanFriendlyExplanation } from "./policy.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Graphiti-style Point-in-Time ("As-Of") Bi-Temporal Fact Filter.
|
|
4
|
+
* Reconstructs which facts were active at `asOf` vs. already retired by `asOf`,
|
|
5
|
+
* excluding facts created after `asOf`.
|
|
6
|
+
*/
|
|
7
|
+
export function filterFactsAsOf(facts, asOf) {
|
|
8
|
+
if (!asOf || !asOf.trim()) {
|
|
9
|
+
return {
|
|
10
|
+
scopedFacts: facts,
|
|
11
|
+
isActiveAtPointInTime: (fact) => fact.validTo === null,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const asOfMs = Date.parse(asOf);
|
|
15
|
+
if (!Number.isFinite(asOfMs)) {
|
|
16
|
+
return {
|
|
17
|
+
scopedFacts: facts,
|
|
18
|
+
isActiveAtPointInTime: (fact) => fact.validTo === null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const scopedFacts = facts.filter((fact) => {
|
|
22
|
+
const validFromMs = Date.parse(fact.validFrom || fact.createdAt);
|
|
23
|
+
return !Number.isFinite(validFromMs) || validFromMs <= asOfMs;
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
scopedFacts,
|
|
27
|
+
isActiveAtPointInTime: (fact) => {
|
|
28
|
+
if (!fact.validTo)
|
|
29
|
+
return true;
|
|
30
|
+
const validToMs = Date.parse(fact.validTo);
|
|
31
|
+
return Number.isFinite(validToMs) && validToMs > asOfMs;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Graphiti-style Multi-Hop Subgraph Community Traversal (BFS).
|
|
37
|
+
* Finds all nodes and edges within `maxHops` (default 2) of a focal entity.
|
|
38
|
+
*/
|
|
39
|
+
export function traverseSubgraphBfs(nodes, edges, focalQuery, maxHops = 2) {
|
|
40
|
+
const needle = focalQuery.trim().toLowerCase();
|
|
41
|
+
const clampedHops = Math.min(4, Math.max(1, Number(maxHops) || 2));
|
|
42
|
+
const seedNode = nodes.find((n) => n.id.toLowerCase() === needle) ||
|
|
43
|
+
nodes.find((n) => n.label.toLowerCase() === needle) ||
|
|
44
|
+
nodes.find((n) => n.id.toLowerCase().includes(needle) ||
|
|
45
|
+
n.label.toLowerCase().includes(needle)) ||
|
|
46
|
+
nodes[0];
|
|
47
|
+
if (!seedNode) {
|
|
48
|
+
return {
|
|
49
|
+
focalEntity: focalQuery,
|
|
50
|
+
maxHops: clampedHops,
|
|
51
|
+
nodes: [],
|
|
52
|
+
edges: [],
|
|
53
|
+
hopDistances: {},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const hopDistances = { [seedNode.id]: 0 };
|
|
57
|
+
const queue = [
|
|
58
|
+
{ nodeId: seedNode.id, depth: 0 },
|
|
59
|
+
];
|
|
60
|
+
while (queue.length > 0) {
|
|
61
|
+
const current = queue.shift();
|
|
62
|
+
if (current.depth >= clampedHops)
|
|
63
|
+
continue;
|
|
64
|
+
for (const edge of edges) {
|
|
65
|
+
let neighborId = null;
|
|
66
|
+
if (edge.source === current.nodeId)
|
|
67
|
+
neighborId = edge.target;
|
|
68
|
+
else if (edge.target === current.nodeId)
|
|
69
|
+
neighborId = edge.source;
|
|
70
|
+
if (neighborId && hopDistances[neighborId] === undefined) {
|
|
71
|
+
hopDistances[neighborId] = current.depth + 1;
|
|
72
|
+
queue.push({ nodeId: neighborId, depth: current.depth + 1 });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const subNodes = nodes
|
|
77
|
+
.filter((n) => hopDistances[n.id] !== undefined)
|
|
78
|
+
.map((n) => ({ ...n, hopDistance: hopDistances[n.id] }));
|
|
79
|
+
const subEdges = edges.filter((e) => hopDistances[e.source] !== undefined &&
|
|
80
|
+
hopDistances[e.target] !== undefined);
|
|
81
|
+
return {
|
|
82
|
+
focalEntity: seedNode.id,
|
|
83
|
+
maxHops: clampedHops,
|
|
84
|
+
nodes: subNodes,
|
|
85
|
+
edges: subEdges,
|
|
86
|
+
hopDistances,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Builds the Graphiti-inspired Bi-Temporal Knowledge Graph (nodes, active/historical edges,
|
|
91
|
+
* episodic provenance, point-in-time `asOf` time-travel, 2-hop BFS subgraph, and Mermaid preview)
|
|
4
92
|
* from runtime-agnostic inputs so the Node engine and the Edge Worker render identical graphs.
|
|
5
93
|
*/
|
|
6
94
|
export function buildMemoryKnowledgeGraph(input) {
|
|
7
95
|
const ws = input.workspace;
|
|
8
96
|
const query = input.query;
|
|
97
|
+
const asOf = input.asOf ?? null;
|
|
98
|
+
const maxHops = Math.min(4, Math.max(1, Number(input.maxHops || 2)));
|
|
99
|
+
const { scopedFacts, isActiveAtPointInTime } = filterFactsAsOf(input.facts, asOf);
|
|
9
100
|
const nodeMap = new Map();
|
|
10
101
|
const rootId = `workspace:${ws.slug}`;
|
|
11
102
|
nodeMap.set(rootId, {
|
|
@@ -34,7 +125,9 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
34
125
|
? "tool"
|
|
35
126
|
: id.startsWith("guardrail:")
|
|
36
127
|
? "guardrail"
|
|
37
|
-
:
|
|
128
|
+
: id.startsWith("episode:")
|
|
129
|
+
? "episode"
|
|
130
|
+
: fallbackKind;
|
|
38
131
|
const label = id.includes(":")
|
|
39
132
|
? id.split(":").slice(1).join(":")
|
|
40
133
|
: id.length > 36
|
|
@@ -50,8 +143,11 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
50
143
|
nodeMap.set(id, created);
|
|
51
144
|
return created;
|
|
52
145
|
};
|
|
53
|
-
|
|
54
|
-
|
|
146
|
+
let episodesCount = 0;
|
|
147
|
+
const edges = scopedFacts.map((fact) => {
|
|
148
|
+
const status = isActiveAtPointInTime(fact)
|
|
149
|
+
? "active"
|
|
150
|
+
: "historical";
|
|
55
151
|
const objKind = fact.sourceKind === "preference"
|
|
56
152
|
? "preference"
|
|
57
153
|
: fact.sourceKind === "policy_decision"
|
|
@@ -61,6 +157,15 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
61
157
|
: "entity";
|
|
62
158
|
ensureNode(fact.subject, status, "entity", fact.subject);
|
|
63
159
|
ensureNode(fact.object, status, objKind, fact.summary);
|
|
160
|
+
const episodeId = fact.episodeId || fact.sourceReferenceId || null;
|
|
161
|
+
if (episodeId) {
|
|
162
|
+
const epNodeId = episodeId.startsWith("episode:")
|
|
163
|
+
? episodeId
|
|
164
|
+
: `episode:${episodeId}`;
|
|
165
|
+
if (!nodeMap.has(epNodeId))
|
|
166
|
+
episodesCount += 1;
|
|
167
|
+
ensureNode(epNodeId, status, "episode", `Episodic provenance (${episodeId})`);
|
|
168
|
+
}
|
|
64
169
|
return {
|
|
65
170
|
id: fact.id,
|
|
66
171
|
source: fact.subject,
|
|
@@ -72,7 +177,10 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
72
177
|
confidence: fact.confidence,
|
|
73
178
|
status,
|
|
74
179
|
validFrom: fact.validFrom,
|
|
75
|
-
validTo: fact.validTo,
|
|
180
|
+
validTo: status === "active" && asOf ? null : fact.validTo,
|
|
181
|
+
transactionFrom: fact.transactionFrom || fact.createdAt,
|
|
182
|
+
transactionTo: fact.transactionTo ?? fact.validTo,
|
|
183
|
+
episodeId,
|
|
76
184
|
supersededById: fact.supersededById ?? null,
|
|
77
185
|
sourceKind: fact.sourceKind,
|
|
78
186
|
sourceReferenceId: fact.sourceReferenceId ?? null,
|
|
@@ -95,6 +203,9 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
95
203
|
status: "active",
|
|
96
204
|
validFrom: conn.createdAt,
|
|
97
205
|
validTo: null,
|
|
206
|
+
transactionFrom: conn.createdAt,
|
|
207
|
+
transactionTo: null,
|
|
208
|
+
episodeId: conn.id,
|
|
98
209
|
supersededById: null,
|
|
99
210
|
sourceKind: "system",
|
|
100
211
|
sourceReferenceId: conn.id,
|
|
@@ -104,6 +215,10 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
104
215
|
const activeEdges = edges.filter((e) => e.status === "active");
|
|
105
216
|
const historicalEdges = edges.filter((e) => e.status === "historical");
|
|
106
217
|
const nodes = Array.from(nodeMap.values());
|
|
218
|
+
const focalTarget = input.focalEntity || query || null;
|
|
219
|
+
const subgraph = focalTarget
|
|
220
|
+
? traverseSubgraphBfs(nodes, edges, focalTarget, maxHops)
|
|
221
|
+
: null;
|
|
107
222
|
const safeMermaidId = (raw, idx) => `N${idx}_${raw.replace(/[^a-zA-Z0-9]/g, "_").slice(0, 14)}`;
|
|
108
223
|
const nodeIndex = new Map();
|
|
109
224
|
nodes.slice(0, 24).forEach((n, idx) => {
|
|
@@ -128,7 +243,7 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
128
243
|
mermaidLines.push(` ${srcId} -.->|RETIRED: ${pred}| ${tgtId}`);
|
|
129
244
|
}
|
|
130
245
|
}
|
|
131
|
-
const headline = `Bi-Temporal Knowledge Graph (${ws.name}): ${activeEdges.length} active relationship${activeEdges.length === 1 ? "" : "s"}, ${historicalEdges.length} superseded historical relationship${historicalEdges.length === 1 ? "" : "s"} across ${nodes.length} node${nodes.length === 1 ? "" : "s"}.`;
|
|
246
|
+
const headline = `Bi-Temporal Knowledge Graph (${ws.name}${asOf ? ` as of ${asOf}` : ""}): ${activeEdges.length} active relationship${activeEdges.length === 1 ? "" : "s"}, ${historicalEdges.length} superseded historical relationship${historicalEdges.length === 1 ? "" : "s"} across ${nodes.length} node${nodes.length === 1 ? "" : "s"}.`;
|
|
132
247
|
const activePreview = activeEdges
|
|
133
248
|
.slice(0, 4)
|
|
134
249
|
.map((e) => `${e.source} --[${e.predicate}]--> ${e.target}`)
|
|
@@ -142,7 +257,7 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
142
257
|
? `Time-travel lineage: ${historicalEdges.length} older fact${historicalEdges.length === 1 ? " was" : "s were"} automatically retired when newer workspace settings or facts replaced them.`
|
|
143
258
|
: "No superseded historical facts yet.",
|
|
144
259
|
].join(" ");
|
|
145
|
-
const technical = `workspace=${ws.id} | namespace=${input.namespace} | nodes=${nodes.length} | activeEdges=${activeEdges.length} | historicalEdges=${historicalEdges.length} | memories=${input.memoriesCount} | activePreview=[${activePreview || "none"}]`;
|
|
260
|
+
const technical = `workspace=${ws.id} | namespace=${input.namespace} | asOf=${asOf || "latest"} | nodes=${nodes.length} | activeEdges=${activeEdges.length} | historicalEdges=${historicalEdges.length} | episodes=${episodesCount} | memories=${input.memoriesCount} | activePreview=[${activePreview || "none"}]`;
|
|
146
261
|
const explanation = formatHumanFriendlyExplanation({
|
|
147
262
|
headline,
|
|
148
263
|
nonTechnical,
|
|
@@ -154,11 +269,15 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
154
269
|
workspaceSlug: ws.slug,
|
|
155
270
|
namespace: input.namespace,
|
|
156
271
|
generatedAt: new Date().toISOString(),
|
|
272
|
+
asOf,
|
|
273
|
+
focalEntity: subgraph?.focalEntity ?? null,
|
|
274
|
+
maxHops,
|
|
157
275
|
query: query ?? null,
|
|
158
276
|
nodes,
|
|
159
277
|
edges,
|
|
160
278
|
activeEdges,
|
|
161
279
|
historicalEdges,
|
|
280
|
+
subgraph,
|
|
162
281
|
stats: {
|
|
163
282
|
nodesCount: nodes.length,
|
|
164
283
|
activeEdgesCount: activeEdges.length,
|
|
@@ -166,6 +285,7 @@ export function buildMemoryKnowledgeGraph(input) {
|
|
|
166
285
|
memoriesCount: input.memoriesCount,
|
|
167
286
|
resourcesCount: input.resources.length,
|
|
168
287
|
connectionsCount: input.activeConnections.length,
|
|
288
|
+
episodesCount,
|
|
169
289
|
},
|
|
170
290
|
mermaid: mermaidLines.join("\n"),
|
|
171
291
|
explanation,
|