@unoverse-platform/studio 0.1.90 → 0.1.92
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/local/plugin.ts +21 -65
- package/package.json +13 -3
- package/vendor/base/src/agent-mcp/discovery.ts +203 -0
- package/vendor/base/src/agent-mcp/handoff.ts +56 -0
- package/vendor/base/src/agent-mcp/index.ts +44 -0
- package/vendor/base/src/agent-mcp/invoke.ts +153 -0
- package/vendor/base/src/agent-mcp/lean.ts +114 -0
- package/vendor/base/src/agent-mcp/memoryContext.ts +104 -0
- package/vendor/base/src/agent-mcp/memoryIngest.ts +88 -0
- package/vendor/base/src/agent-mcp/rowComponents.ts +234 -0
- package/vendor/base/src/agent-mcp/tools.ts +134 -0
- package/vendor/base/src/agent-mcp/types.ts +138 -0
- package/vendor/base/src/auth/auth.ts +307 -0
- package/vendor/base/src/auth/authConfig.ts +73 -0
- package/vendor/base/src/boot.ts +245 -0
- package/vendor/base/src/definitions/definitions.ts +18 -0
- package/vendor/base/src/definitions/dsPackage.ts +45 -0
- package/vendor/base/src/definitions/fsCache.ts +155 -0
- package/vendor/base/src/definitions/index.ts +19 -0
- package/vendor/base/src/definitions/inputs.ts +30 -0
- package/vendor/base/src/definitions/load/compile/component.ts +80 -0
- package/vendor/base/src/definitions/load/compile/index.ts +12 -0
- package/vendor/base/src/definitions/load/compile/sections.ts +132 -0
- package/vendor/base/src/definitions/load/compile/template.ts +153 -0
- package/vendor/base/src/definitions/load/expand/includes.ts +27 -0
- package/vendor/base/src/definitions/load/expand/index.ts +17 -0
- package/vendor/base/src/definitions/load/expand/inherit.ts +169 -0
- package/vendor/base/src/definitions/load/expand/referenced.ts +164 -0
- package/vendor/base/src/definitions/load/expand/refs.ts +106 -0
- package/vendor/base/src/definitions/load/expand/walk.ts +91 -0
- package/vendor/base/src/definitions/load/load.ts +487 -0
- package/vendor/base/src/definitions/model.ts +238 -0
- package/vendor/base/src/definitions/registry/catalog.ts +659 -0
- package/vendor/base/src/definitions/registry/homes.ts +252 -0
- package/vendor/base/src/definitions/theme.ts +383 -0
- package/vendor/base/src/executor.ts +284 -0
- package/vendor/base/src/http/uwsFetchAdapter.ts +397 -0
- package/vendor/base/src/items/baseVersion.ts +96 -0
- package/vendor/base/src/items/collect.ts +246 -0
- package/vendor/base/src/items/fingerprint.ts +34 -0
- package/vendor/base/src/items/publish.ts +212 -0
- package/vendor/base/src/lint/context.mjs +56 -0
- package/vendor/base/src/lint/design/defs.mjs +46 -0
- package/vendor/base/src/lint/design/file.mjs +737 -0
- package/vendor/base/src/lint/design/index.d.mts +30 -0
- package/vendor/base/src/lint/design/index.mjs +996 -0
- package/vendor/base/src/lint/design/tokens.mjs +128 -0
- package/vendor/base/src/lint/design/vocabulary.mjs +181 -0
- package/vendor/base/src/lint/design/walk.mjs +444 -0
- package/vendor/base/src/lint/index.mjs +28 -0
- package/vendor/base/src/lint/nodes/blocks.mjs +63 -0
- package/vendor/base/src/lint/nodes/index.d.mts +28 -0
- package/vendor/base/src/lint/nodes/index.mjs +82 -0
- package/vendor/base/src/lint/nodes/load.mjs +126 -0
- package/vendor/base/src/lint/nodes/node.mjs +764 -0
- package/vendor/base/src/lint/nodes/package.mjs +112 -0
- package/vendor/base/src/lint/nodes/schema.mjs +75 -0
- package/vendor/base/src/logger.ts +33 -0
- package/vendor/base/src/manifests/compose.ts +539 -0
- package/vendor/base/src/manifests/executor/callback.ts +107 -0
- package/vendor/base/src/manifests/executor/context.ts +110 -0
- package/vendor/base/src/manifests/executor/index.ts +47 -0
- package/vendor/base/src/manifests/executor/lookup.ts +21 -0
- package/vendor/base/src/manifests/executor/memory.ts +62 -0
- package/vendor/base/src/manifests/executor/promise.ts +71 -0
- package/vendor/base/src/manifests/executor/refire.ts +34 -0
- package/vendor/base/src/manifests/executor/send.ts +65 -0
- package/vendor/base/src/manifests/executor/session.ts +46 -0
- package/vendor/base/src/manifests/executor/toolBridge.ts +266 -0
- package/vendor/base/src/manifests/index.ts +280 -0
- package/vendor/base/src/manifests/integrity.ts +93 -0
- package/vendor/base/src/manifests/rows.ts +33 -0
- package/vendor/base/src/manifests/runtime/auth/aws.ts +240 -0
- package/vendor/base/src/manifests/runtime/auth/oauth.ts +76 -0
- package/vendor/base/src/manifests/runtime/authorize.ts +159 -0
- package/vendor/base/src/manifests/runtime/channels/final.ts +171 -0
- package/vendor/base/src/manifests/runtime/channels/service.ts +138 -0
- package/vendor/base/src/manifests/runtime/channels/workflow.ts +310 -0
- package/vendor/base/src/manifests/runtime/context.ts +156 -0
- package/vendor/base/src/manifests/runtime/docstore/handlers.ts +547 -0
- package/vendor/base/src/manifests/runtime/docstore/index.ts +135 -0
- package/vendor/base/src/manifests/runtime/docstore/sectionizer.ts +184 -0
- package/vendor/base/src/manifests/runtime/docstore/store.ts +172 -0
- package/vendor/base/src/manifests/runtime/docstore/types.ts +60 -0
- package/vendor/base/src/manifests/runtime/duplex/audioLane.ts +165 -0
- package/vendor/base/src/manifests/runtime/duplex/session.ts +511 -0
- package/vendor/base/src/manifests/runtime/events.ts +223 -0
- package/vendor/base/src/manifests/runtime/helpers.ts +53 -0
- package/vendor/base/src/manifests/runtime/http/allowedHosts.ts +118 -0
- package/vendor/base/src/manifests/runtime/http/request.ts +637 -0
- package/vendor/base/src/manifests/runtime/http/response.ts +162 -0
- package/vendor/base/src/manifests/runtime/index.ts +57 -0
- package/vendor/base/src/manifests/runtime/loops/chunk.ts +98 -0
- package/vendor/base/src/manifests/runtime/loops/loop.ts +191 -0
- package/vendor/base/src/manifests/runtime/loops/paginate.ts +143 -0
- package/vendor/base/src/manifests/runtime/loops/poll.ts +169 -0
- package/vendor/base/src/manifests/runtime/narrate.ts +53 -0
- package/vendor/base/src/manifests/runtime/state.ts +171 -0
- package/vendor/base/src/manifests/runtime/templating.ts +110 -0
- package/vendor/base/src/manifests/runtime/tools/regionSkills.ts +125 -0
- package/vendor/base/src/manifests/runtime/tools/toolloop.ts +550 -0
- package/vendor/base/src/manifests/runtime/usage.ts +87 -0
- package/vendor/base/src/manifests/source.ts +196 -0
- package/vendor/base/src/manifests/watch.ts +67 -0
- package/vendor/base/src/markdown/document.ts +141 -0
- package/vendor/base/src/paths.ts +180 -0
- package/vendor/base/src/platform/audioManager.ts +100 -0
- package/vendor/base/src/platform/clientTransport.ts +65 -0
- package/vendor/base/src/platform/executionContext.ts +157 -0
- package/vendor/base/src/platform/index.ts +10 -0
- package/vendor/base/src/platform/pluginAPI.ts +146 -0
- package/vendor/base/src/platform/redis.ts +54 -0
- package/vendor/base/src/platform/serviceCalls.ts +222 -0
- package/vendor/base/src/pluginBase.ts +248 -0
- package/vendor/base/src/plugins/README.md +57 -0
- package/vendor/base/src/plugins/discovery.ts +87 -0
- package/vendor/base/src/plugins/index.ts +16 -0
- package/vendor/base/src/plugins/loader.ts +179 -0
- package/vendor/base/src/plugins/redis.ts +36 -0
- package/vendor/base/src/plugins/state.ts +53 -0
- package/vendor/base/src/registry.ts +95 -0
- package/vendor/base/src/security/permissions.ts +93 -0
- package/vendor/base/src/security/rules.ts +73 -0
- package/vendor/base/src/template/SafeExpression.ts +556 -0
- package/vendor/base/src/template/StringTemplateResolver.ts +75 -0
- package/vendor/base/src/template/index.ts +22 -0
- package/vendor/base/src/types.ts +50 -0
- package/vendor/base/src/workflow/GetMemoryService.ts +158 -0
- package/vendor/base/src/workflow/PlatformMemoryCore.ts +449 -0
- package/vendor/base/src/workflow/routing.ts +122 -0
- package/vendor/sdk/lib/core/store.ts +26 -6
- package/local/mcp.ts +0 -265
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for node-service
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface NodeDefinition {
|
|
6
|
+
type: string;
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
/** Spatial-discovery selection text embedded by the catalog ranker (CatalogService);
|
|
10
|
+
* falls back to `description` when absent. Registered per node in pluginAPI. */
|
|
11
|
+
whenToUse?: string;
|
|
12
|
+
category: string;
|
|
13
|
+
version: string;
|
|
14
|
+
configSchema: object;
|
|
15
|
+
/** The authored settings-form field order; the canvas renders listed fields first. */
|
|
16
|
+
"ui:order"?: string[] | null;
|
|
17
|
+
inputs: object[];
|
|
18
|
+
outputs: object[];
|
|
19
|
+
// Visual properties
|
|
20
|
+
color: string;
|
|
21
|
+
logoUrl: string | null;
|
|
22
|
+
template: string | null;
|
|
23
|
+
nodeSize: { width: number; height: number };
|
|
24
|
+
// Service properties
|
|
25
|
+
isService: boolean;
|
|
26
|
+
serviceConnectors: object | null;
|
|
27
|
+
// Component template for UI nodes
|
|
28
|
+
componentTemplate: object | null;
|
|
29
|
+
// Per-component render URLs for the generic `Component` node (org-aware); the Canvas
|
|
30
|
+
// resolves an instance's URL from config.component. null for every other node.
|
|
31
|
+
componentUrls?: Record<string, string> | null;
|
|
32
|
+
// Credentials
|
|
33
|
+
credentials: object[];
|
|
34
|
+
// Test data
|
|
35
|
+
testData: object | null;
|
|
36
|
+
// Author-declared capabilities (e.g. cacheable) — passed through to Redis so
|
|
37
|
+
// the workflow engine can read them (memoization gate, etc.).
|
|
38
|
+
capabilities?: object | null;
|
|
39
|
+
executor: any;
|
|
40
|
+
executionMode: "single" | "generator"; // PromiseNode = single, CallbackNode = generator
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PluginMetadata {
|
|
44
|
+
version: string;
|
|
45
|
+
description: string;
|
|
46
|
+
category?: string;
|
|
47
|
+
displayName?: string;
|
|
48
|
+
features?: string[];
|
|
49
|
+
credentials?: { name: string; type: string; required: boolean; description: string }[];
|
|
50
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine's HTTP client for the DEDICATED MEMORY SERVER (:4104) — thin
|
|
3
|
+
* wrappers over its API (/compose, /evidence, /evidence/recent,
|
|
4
|
+
* /evidence/search). No logic lives here; memory is owned by the server.
|
|
5
|
+
*
|
|
6
|
+
* Used by the intrinsic agent memory tools (PlatformMemoryTools — the Memory
|
|
7
|
+
* toggles) and the Universe Copilot harness. NOT used by spatial search —
|
|
8
|
+
* "SpatialSearch serves knowledge tools only" (MEMORY_SPEC.md); the old
|
|
9
|
+
* includeMemory-in-search path is dead.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createLogger } from "../logger.js";
|
|
13
|
+
|
|
14
|
+
const logger = createLogger("GetMemoryService");
|
|
15
|
+
const MEMORY_SERVICE_URL = process.env.MEMORY_SERVICE_URL || "http://localhost:4104";
|
|
16
|
+
|
|
17
|
+
export interface GetMemoryInput {
|
|
18
|
+
userId: string;
|
|
19
|
+
workflowId: string;
|
|
20
|
+
query?: string;
|
|
21
|
+
domains?: string[];
|
|
22
|
+
minCertainty?: number;
|
|
23
|
+
limit?: number;
|
|
24
|
+
accessToken?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface MemoryEvidence {
|
|
28
|
+
memory_id: string;
|
|
29
|
+
content: { claim: string; premises?: string[] };
|
|
30
|
+
type: string; // inductive | deductive | abductive
|
|
31
|
+
domain: string;
|
|
32
|
+
certainty: number;
|
|
33
|
+
reinforcement_count: number;
|
|
34
|
+
created_at: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class GetMemoryService {
|
|
38
|
+
/**
|
|
39
|
+
* Retrieve composed understanding for a user (uses /compose endpoint)
|
|
40
|
+
*/
|
|
41
|
+
static async compose(input: GetMemoryInput): Promise<any> {
|
|
42
|
+
const { userId, workflowId, query, domains, accessToken } = input;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const params = new URLSearchParams({ userId, workflowId, mode: "full" });
|
|
46
|
+
if (domains?.length) params.set("domains", domains.join(","));
|
|
47
|
+
if (query) params.set("context", query);
|
|
48
|
+
|
|
49
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
50
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
51
|
+
|
|
52
|
+
const res = await fetch(`${MEMORY_SERVICE_URL}/compose?${params}`, { headers });
|
|
53
|
+
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
logger.warn("Memory compose failed", { status: res.status });
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const data: any = await res.json();
|
|
60
|
+
return data.composed || null;
|
|
61
|
+
} catch (err: any) {
|
|
62
|
+
logger.debug("Memory compose unavailable", { error: err.message });
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get recent evidence snapshot (recency-ordered, no query)
|
|
69
|
+
*/
|
|
70
|
+
static async recent(input: { userId: string; workflowId: string; limit?: number; accessToken?: string }): Promise<MemoryEvidence[]> {
|
|
71
|
+
const { userId, workflowId, limit, accessToken } = input;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const params = new URLSearchParams({ userId, workflowId });
|
|
75
|
+
if (limit) params.set("limit", String(limit));
|
|
76
|
+
|
|
77
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
78
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
79
|
+
|
|
80
|
+
const res = await fetch(`${MEMORY_SERVICE_URL}/evidence/recent?${params}`, { headers });
|
|
81
|
+
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
logger.warn("Memory recent failed", { status: res.status });
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const data: any = await res.json();
|
|
88
|
+
return data.evidence || [];
|
|
89
|
+
} catch (err: any) {
|
|
90
|
+
logger.debug("Memory recent unavailable", { error: err.message });
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Search user evidence by query (uses /evidence/search endpoint)
|
|
97
|
+
*/
|
|
98
|
+
static async search(input: GetMemoryInput): Promise<MemoryEvidence[]> {
|
|
99
|
+
const { userId, workflowId, query, domains, minCertainty, limit, accessToken } = input;
|
|
100
|
+
|
|
101
|
+
if (!query) {
|
|
102
|
+
return this.retrieve(input);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const params = new URLSearchParams({ userId, workflowId, query });
|
|
107
|
+
if (domains?.length) params.set("domains", domains.join(","));
|
|
108
|
+
if (minCertainty !== undefined) params.set("minCertainty", String(minCertainty));
|
|
109
|
+
if (limit) params.set("limit", String(limit));
|
|
110
|
+
|
|
111
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
112
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
113
|
+
|
|
114
|
+
const res = await fetch(`${MEMORY_SERVICE_URL}/evidence/search?${params}`, { headers });
|
|
115
|
+
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
logger.warn("Memory search failed", { status: res.status });
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const data: any = await res.json();
|
|
122
|
+
return data.evidence || [];
|
|
123
|
+
} catch (err: any) {
|
|
124
|
+
logger.debug("Memory search unavailable", { error: err.message });
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Retrieve raw evidence (structured, no query needed — uses /evidence endpoint)
|
|
131
|
+
*/
|
|
132
|
+
static async retrieve(input: GetMemoryInput): Promise<MemoryEvidence[]> {
|
|
133
|
+
const { userId, workflowId, domains, minCertainty, limit, accessToken } = input;
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const params = new URLSearchParams({ userId, workflowId });
|
|
137
|
+
if (domains?.length) params.set("domains", domains.join(","));
|
|
138
|
+
if (minCertainty !== undefined) params.set("minCertainty", String(minCertainty));
|
|
139
|
+
if (limit) params.set("limit", String(limit || 20));
|
|
140
|
+
|
|
141
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
142
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
143
|
+
|
|
144
|
+
const res = await fetch(`${MEMORY_SERVICE_URL}/evidence?${params}`, { headers });
|
|
145
|
+
|
|
146
|
+
if (!res.ok) {
|
|
147
|
+
logger.warn("Memory retrieve failed", { status: res.status });
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const data: any = await res.json();
|
|
152
|
+
return data.evidence || [];
|
|
153
|
+
} catch (err: any) {
|
|
154
|
+
logger.debug("Memory retrieve unavailable", { error: err.message });
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform Memory Tools — the REGISTRY-FREE core (schemas, gating, execution).
|
|
3
|
+
*
|
|
4
|
+
* Split from PlatformMemoryTools.ts (import-graph only, zero behavior change): everything here
|
|
5
|
+
* depends only on the logger + GetMemoryService + fetch, so the Unoverse Runtime can import it
|
|
6
|
+
* without dragging the engine's node/service registries (and through them Prisma + the XState
|
|
7
|
+
* actors) into its bundle — measured 148KB → 1MB before this split. PlatformMemoryTools.ts stays
|
|
8
|
+
* the engine-facing module: it re-exports all of this and adds the one registry-coupled step
|
|
9
|
+
* (setAvailableTools trace sync) inside injectPlatformMemoryTools. Engine callers are unchanged.
|
|
10
|
+
*
|
|
11
|
+
* BOTH memory faculties are PER-AGENT toggles on the agent node's own config
|
|
12
|
+
* (resolved from the calling node via memoryFlagsForNode), never canvas-wide:
|
|
13
|
+
* - data.config.enableUserMemory → queryMemory (who is this user)
|
|
14
|
+
* - data.config.enableAgentMemory → getGoalContext, writeNote,
|
|
15
|
+
* updateGoalState, searchHistory, resumeGoal, archiveGoal (goal-scoped working memory)
|
|
16
|
+
*
|
|
17
|
+
* recordAttempt is PLATFORM-ONLY (PLATFORM_MEMORY_METHODS): the judge writes the ledger
|
|
18
|
+
* through executePlatformMemoryMethod; it is never merged into an agent's schema.
|
|
19
|
+
*
|
|
20
|
+
* Per-agent (not canvas-wide) so memory never leaks into worker agents UNO
|
|
21
|
+
* builds inside the workflows it creates — those default off. Still a TOGGLE,
|
|
22
|
+
* not a connector: a bare agent with the toggle on still gets its schema with
|
|
23
|
+
* zero service edges. Errors return as data ({success:false, error}) — a thrown
|
|
24
|
+
* error becomes a 500 and the agent never sees the message.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { createLogger } from "../logger.js";
|
|
28
|
+
import { GetMemoryService } from "./GetMemoryService.js";
|
|
29
|
+
|
|
30
|
+
const logger = createLogger("PlatformMemoryTools");
|
|
31
|
+
// Server-to-server MEMORY_SERVICE_URL means the PLATFORM LANE (:4114, asserted identity)
|
|
32
|
+
// — the docker-compose doctrine, and what every other engine/server caller defaults to.
|
|
33
|
+
// The old :4104 default sent tokenless callers (debug runs, the builder MCP's goal tools)
|
|
34
|
+
// to the public JWT door, where every write 401'd silently.
|
|
35
|
+
const MEMORY_SERVICE_URL = process.env.MEMORY_SERVICE_URL || "http://localhost:4114";
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Tool schemas
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
// The ONE user-memory tool (MEMORY_SPEC v3 § Serving). The standing snapshot is no
|
|
42
|
+
// longer a tool at all — the agent HARNESS injects who-the-user-is + current state
|
|
43
|
+
// into the system context at init (zero calls). queryMemory remains as the single
|
|
44
|
+
// depth door: search the user's remembered facts when a topic needs prior context.
|
|
45
|
+
export const USER_MEMORY_METHODS: Record<string, any> = {
|
|
46
|
+
queryMemory: {
|
|
47
|
+
description:
|
|
48
|
+
"Search the user's remembered facts by topic (semantic + keyword). Use mid-conversation when a specific topic needs prior context — budget, preferences, past decisions about X, or where an earlier plan got to. Returns claims with certainty scores — weight stronger evidence higher. This is evidence about the user specifically, not a knowledge-base search. (A summary of who the user is was already provided in your context — query only for depth beyond it.)",
|
|
49
|
+
input: {
|
|
50
|
+
type: "object",
|
|
51
|
+
additionalProperties: false,
|
|
52
|
+
properties: {
|
|
53
|
+
query: { type: "string", description: "Topic to search in user memory" },
|
|
54
|
+
},
|
|
55
|
+
required: ["query"],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const AGENT_MEMORY_METHODS: Record<string, any> = {
|
|
61
|
+
getGoalContext: {
|
|
62
|
+
description:
|
|
63
|
+
"Your wake-up briefing: the active goal (description, acceptance criteria), the LEDGER (attempts so far, whether the goal is met, the open criteria the judge failed last time with its reason, any standing directive), your last saved goal-state (plan, current step), recent journal notes, durable environment facts, and recent past-goal summaries. Call FIRST when starting or resuming work — it replaces re-reading history. Read-only, cheap.",
|
|
64
|
+
input: { type: "object", additionalProperties: false, properties: {} },
|
|
65
|
+
},
|
|
66
|
+
writeNote: {
|
|
67
|
+
description:
|
|
68
|
+
"Append one note to your persistent journal (survives context resets and restarts). Write decisions WITH the why (category 'decision'), surprises/failures with cause ('error'), durable environment facts like rate limits or schema quirks ('fact' — these outlive the goal), step completions ('progress'). Never write transcripts or tool output that can be re-fetched. Be specific: numbers, names, ids.",
|
|
69
|
+
input: {
|
|
70
|
+
type: "object",
|
|
71
|
+
additionalProperties: false,
|
|
72
|
+
properties: {
|
|
73
|
+
content: { type: "string", description: "The note. Specific and self-contained." },
|
|
74
|
+
category: {
|
|
75
|
+
type: "string",
|
|
76
|
+
enum: ["progress", "result", "pending", "error", "note", "decision", "fact"],
|
|
77
|
+
description: "decision = choice + why; fact = durable environment learning; pending = blocked/waiting",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
required: ["content", "category"],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
updateGoalState: {
|
|
84
|
+
description:
|
|
85
|
+
"Overwrite your compact goal-state object — the FIRST thing future-you reads after a reset. Keep it current after each meaningful step: the goal description, the plan (short steps with status), and the current step. Supplied fields merge over the existing state; it is also snapshotted to durable storage. (The acceptance bar is NOT set here, and neither are blockers: the bar is locked independently and what is still open is derived from the judge's last verdict, so you cannot grade your own homework.)",
|
|
86
|
+
input: {
|
|
87
|
+
type: "object",
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
properties: {
|
|
90
|
+
description: { type: "string", description: "The goal in one sentence (sets/updates the goal description)" },
|
|
91
|
+
plan: { type: "array", items: { type: "string" }, description: "Short step list, each prefixed with its status, e.g. '[done] fetch schema'" },
|
|
92
|
+
currentStep: { type: "string", description: "What is being worked on right now" },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
searchHistory: {
|
|
97
|
+
description:
|
|
98
|
+
"Summaries of previously completed goals on this canvas, most recent first. Use at plan time — before starting something that may have been attempted before, and before retrying a failed approach.",
|
|
99
|
+
input: {
|
|
100
|
+
type: "object",
|
|
101
|
+
additionalProperties: false,
|
|
102
|
+
properties: {
|
|
103
|
+
limit: { type: "number", description: "Max summaries to return (default 10)" },
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
resumeGoal: {
|
|
108
|
+
description:
|
|
109
|
+
"Continue a goal you previously CLOSED — pick up where you left off instead of starting over. getGoalContext lists your recent goals with progress (done/total) and status; if the work isn't actually finished (or was archived prematurely), call resumeGoal to reopen it: the goal goes back to active and its saved plan/current-step/blockers are restored so you continue from the last state. Omit goalId to resume the most recently closed goal, or pass a specific goalId from getGoalContext's recentGoals. (Journal notes were promoted to durable memory on archive; the plan state is what's restored.) For a brand-new objective, do NOT resume — just start working and the platform opens a fresh goal.",
|
|
110
|
+
input: {
|
|
111
|
+
type: "object",
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
properties: {
|
|
114
|
+
goalId: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "Which closed goal to reopen (from getGoalContext.recentGoals). Omit for the most recent.",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
archiveGoal: {
|
|
122
|
+
description:
|
|
123
|
+
"Declare the CURRENT goal complete — the CLOSING step, not a fire-and-forget. Before calling it, REVIEW and reconcile: confirm the produced output meets EACH locked acceptance criterion (re-run checkAcceptance if unsure), then call updateGoalState one last time to mark every finished plan step '[done] …' and set currentStep to a one-line closing statement (a goal archived with its plan still unchecked reads as half-done in the dashboard). Then archiveGoal: it archives a permanent summary, promotes your 'fact' notes to durable environment memory, and clears the journal for the next goal. Call ONLY when the goal is fully achieved or explicitly abandoned. The summary must be specific — what was built/decided/produced, with names and outcomes, and how it was verified against the criteria. Future sessions rely on it.",
|
|
124
|
+
input: {
|
|
125
|
+
type: "object",
|
|
126
|
+
additionalProperties: false,
|
|
127
|
+
properties: {
|
|
128
|
+
summary: { type: "string", description: "Specific summary of the completed goal" },
|
|
129
|
+
},
|
|
130
|
+
required: ["summary"],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const USER_MEMORY_INSTRUCTIONS =
|
|
136
|
+
"User memory is available. A background summary of who this user is (identity + current state) was injected into your context at start — do not re-fetch it. queryMemory(topic) searches deeper when a specific topic needs prior context.";
|
|
137
|
+
|
|
138
|
+
export const AGENT_MEMORY_INSTRUCTIONS =
|
|
139
|
+
"You have persistent goal memory that survives restarts and context resets. On wake: getGoalContext before doing work — it shows the active goal, its ledger (attempts, whether it is met, the criteria still open from the judge's last verdict), AND your recent goals with their progress (done/total). If an earlier goal is unfinished or was closed too soon, resumeGoal reopens it so you continue from where you left off instead of starting over. While working: record decisions, failures, environment facts, and progress with writeNote, and keep updateGoalState accurate after each meaningful step (mark steps '[done] …' as you finish them — don't leave the plan frozen on step 1). On completion: REVIEW first — verify the output meets the locked acceptance criteria, mark the remaining plan steps done and set a closing currentStep via updateGoalState, then archiveGoal with a specific summary. The journal is for future-you — write what re-hydration needs, nothing else.";
|
|
140
|
+
|
|
141
|
+
// A harness BUILDER runs under an external gate (Define→build→Verdict→Deliver). It must NOT
|
|
142
|
+
// close or complete the goal itself — the harness's Deliver node owns archiving, and only when
|
|
143
|
+
// an independent Verdict passed. So the builder gets the read/journal memory tools WITHOUT the
|
|
144
|
+
// goal-lifecycle tools (archiveGoal/resumeGoal), and an instruction that forbids self-completion.
|
|
145
|
+
export const AGENT_MEMORY_INSTRUCTIONS_BUILDER =
|
|
146
|
+
"You have persistent goal memory that survives restarts and context resets. On wake: getGoalContext BEFORE doing work — it shows the active goal AND its ledger: the criteria the independent judge failed on the last attempt (each with its reason and how many attempts in a row it has failed), plus any standing directive. If open criteria are present, your last build was REJECTED: address those exact gaps before rebuilding, and do not re-submit the same build. While working: record decisions, failures, environment facts, and progress with writeNote, and keep updateGoalState accurate (plan, currentStep). You do NOT complete, archive, or close the goal — an external harness independently judges the result and owns completion. Build the best workflow, produce its real output, then stop and report; never declare the goal done yourself.";
|
|
147
|
+
|
|
148
|
+
// PLATFORM-ONLY methods: executed by the harness through executePlatformMemoryMethod, never
|
|
149
|
+
// merged into an agent's schema. The judge records verdicts; an agent cannot.
|
|
150
|
+
export const PLATFORM_MEMORY_METHODS = new Set(["recordAttempt"]);
|
|
151
|
+
|
|
152
|
+
// UnoverseMCP authoring methods. An agent whose toolset contains any of these IS a harness
|
|
153
|
+
// builder — used to strip its goal-completion authority (see mergePlatformMemorySchema).
|
|
154
|
+
const UNOVERSE_BUILDER_METHODS = new Set([
|
|
155
|
+
"saveWorkflow",
|
|
156
|
+
"getCanvas",
|
|
157
|
+
"getNodeCatalog",
|
|
158
|
+
"getNodeSchema",
|
|
159
|
+
"runTest",
|
|
160
|
+
"startTestRun",
|
|
161
|
+
"stepNode",
|
|
162
|
+
"readNodeTrace",
|
|
163
|
+
"removeEdges",
|
|
164
|
+
"tidyLayout",
|
|
165
|
+
"readBuilderSkill",
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
/** Is this agent a harness builder (wired to UnoverseMCP)? Detected from its own aggregated tools. */
|
|
169
|
+
function isHarnessBuilder(baseSchema: any | null): boolean {
|
|
170
|
+
const methods = baseSchema?.methods;
|
|
171
|
+
if (!methods) return false;
|
|
172
|
+
for (const name of Object.keys(methods)) {
|
|
173
|
+
if (UNOVERSE_BUILDER_METHODS.has(name)) return true;
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Toggle gating
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
export interface MemoryFlags {
|
|
183
|
+
userMemoryEnabled: boolean;
|
|
184
|
+
agentMemoryEnabled: boolean;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* BOTH memory faculties are PER-AGENT toggles on the agent node's own config
|
|
189
|
+
* (`data.config.enableUserMemory` / `enableAgentMemory`) — never canvas-wide.
|
|
190
|
+
* This stops memory leaking into worker agents UNO builds inside the workflows
|
|
191
|
+
* it creates (they default off). Resolve from the calling node in the cache.
|
|
192
|
+
*/
|
|
193
|
+
export function memoryFlagsForNode(cachedWorkflow: any, nodeId: string): MemoryFlags {
|
|
194
|
+
const nodes = cachedWorkflow?.workflow?.nodes;
|
|
195
|
+
const node = Array.isArray(nodes) ? nodes.find((n: any) => n?.id === nodeId) : null;
|
|
196
|
+
const cfg = node?.data?.config || {};
|
|
197
|
+
return {
|
|
198
|
+
userMemoryEnabled: cfg.enableUserMemory === true,
|
|
199
|
+
agentMemoryEnabled: cfg.enableAgentMemory === true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Is this method a platform memory tool enabled for the calling agent? */
|
|
204
|
+
export function isPlatformMemoryMethod(method: string, flags: MemoryFlags): boolean {
|
|
205
|
+
if (USER_MEMORY_METHODS[method]) return flags.userMemoryEnabled === true;
|
|
206
|
+
if (AGENT_MEMORY_METHODS[method]) return flags.agentMemoryEnabled === true;
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Merge the enabled platform memory toolsets into a (possibly null) aggregated
|
|
212
|
+
* MCP schema — the pure half of injectPlatformMemoryTools (no registry, no trace
|
|
213
|
+
* sync). Returns baseSchema untouched when no toggle is on. Platform methods win
|
|
214
|
+
* on name collision.
|
|
215
|
+
*/
|
|
216
|
+
export function mergePlatformMemorySchema(baseSchema: any | null, flags: MemoryFlags): any | null {
|
|
217
|
+
const methods: Record<string, any> = {};
|
|
218
|
+
const instructions: string[] = [];
|
|
219
|
+
|
|
220
|
+
if (flags.userMemoryEnabled === true) {
|
|
221
|
+
Object.assign(methods, USER_MEMORY_METHODS);
|
|
222
|
+
instructions.push(USER_MEMORY_INSTRUCTIONS);
|
|
223
|
+
}
|
|
224
|
+
if (flags.agentMemoryEnabled === true) {
|
|
225
|
+
if (isHarnessBuilder(baseSchema)) {
|
|
226
|
+
// Builder under a harness: read + journal memory, but NO goal-lifecycle (close/reopen)
|
|
227
|
+
// tools. The harness's Deliver node is the sole archiver, and only on an independent pass —
|
|
228
|
+
// this stops the builder self-certifying via archiveGoal (the false "COMPLETED 5/5").
|
|
229
|
+
const { archiveGoal: _a, resumeGoal: _r, ...readWriteMethods } = AGENT_MEMORY_METHODS;
|
|
230
|
+
Object.assign(methods, readWriteMethods);
|
|
231
|
+
instructions.push(AGENT_MEMORY_INSTRUCTIONS_BUILDER);
|
|
232
|
+
} else {
|
|
233
|
+
Object.assign(methods, AGENT_MEMORY_METHODS);
|
|
234
|
+
instructions.push(AGENT_MEMORY_INSTRUCTIONS);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (Object.keys(methods).length === 0) return baseSchema;
|
|
239
|
+
|
|
240
|
+
const merged = baseSchema
|
|
241
|
+
? {
|
|
242
|
+
...baseSchema,
|
|
243
|
+
methods: { ...baseSchema.methods, ...methods },
|
|
244
|
+
instructions: [baseSchema.instructions, ...instructions].filter(Boolean).join("\n\n"),
|
|
245
|
+
}
|
|
246
|
+
: {
|
|
247
|
+
name: "Unoverse",
|
|
248
|
+
version: "1.0.0",
|
|
249
|
+
methods,
|
|
250
|
+
instructions: instructions.join("\n\n"),
|
|
251
|
+
metadata: { source: "PlatformMemoryTools" },
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
logger.info("Injected platform memory tools", {
|
|
255
|
+
userMemory: flags.userMemoryEnabled === true,
|
|
256
|
+
agentMemory: flags.agentMemoryEnabled === true,
|
|
257
|
+
totalMethods: Object.keys(merged.methods).length,
|
|
258
|
+
hadBaseSchema: !!baseSchema,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return merged;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
// Execution (core-side, against memory-server)
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
|
|
268
|
+
interface MemoryCallIdentity {
|
|
269
|
+
userId: string;
|
|
270
|
+
workflowId: string;
|
|
271
|
+
agentId: string;
|
|
272
|
+
agentName?: string;
|
|
273
|
+
accessToken?: string;
|
|
274
|
+
conversationId?: string;
|
|
275
|
+
executionId?: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function resolveIdentity(params: any, context: any): MemoryCallIdentity | { error: string } {
|
|
279
|
+
const userId =
|
|
280
|
+
params?.userId || context?.workflow?.variables?.userId || context?.publishingContext?.userId;
|
|
281
|
+
const workflowId = context?.workflowId || context?.workflow?.id;
|
|
282
|
+
if (!userId) return { error: "No user identity in execution context — cannot access memory" };
|
|
283
|
+
if (!workflowId) return { error: "No workflow id in execution context — cannot access memory" };
|
|
284
|
+
|
|
285
|
+
// TWO DRAWERS (AGENT_MEMORY.md ruling 2026-09-05, part 2). The GOAL is a property of the
|
|
286
|
+
// canvas (HARNESS.md §12 ruling 1) — one active goal per workflowId, shared brief for
|
|
287
|
+
// everyone. SCRATCH is per agent: the calling node on a canvas, or "caller" for an external
|
|
288
|
+
// builder over the builder MCP (no node). The platform resolves the id from the execution
|
|
289
|
+
// context; agents never pass identity. A caller may still pass an explicit `agentId` to
|
|
290
|
+
// address a specific scratch (isolated builder scratch for a future tournament).
|
|
291
|
+
const nodes: any[] = context?.workflow?.nodes || context?.cachedWorkflow?.workflow?.nodes || context?.cachedWorkflow?.nodes || [];
|
|
292
|
+
const agentId: string = params?.agentId || context?.callingNodeId || context?.nodeId || "caller";
|
|
293
|
+
const agentNode = nodes.find((n: any) => n?.id === agentId);
|
|
294
|
+
const agentName: string | undefined = agentNode?.data?.label || (agentId === "caller" ? "External builder" : undefined);
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
userId,
|
|
298
|
+
workflowId,
|
|
299
|
+
agentId,
|
|
300
|
+
agentName,
|
|
301
|
+
accessToken: context?.auth?.accessToken,
|
|
302
|
+
conversationId: context?.workflow?.variables?.conversationId || context?.publishingContext?.conversationId,
|
|
303
|
+
executionId: context?.executionId,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function authHeaders(accessToken?: string): Record<string, string> {
|
|
308
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
309
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
310
|
+
return headers;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function memoryServerGet(path: string, query: Record<string, string>, accessToken?: string): Promise<any> {
|
|
314
|
+
const params = new URLSearchParams(query);
|
|
315
|
+
const res = await fetch(`${MEMORY_SERVICE_URL}${path}?${params}`, { headers: authHeaders(accessToken) });
|
|
316
|
+
if (!res.ok) throw new Error(`memory-server ${path} failed: ${res.status} ${await res.text()}`);
|
|
317
|
+
return res.json();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function memoryServerPost(path: string, body: any, accessToken?: string): Promise<any> {
|
|
321
|
+
const res = await fetch(`${MEMORY_SERVICE_URL}${path}`, {
|
|
322
|
+
method: "POST",
|
|
323
|
+
headers: authHeaders(accessToken),
|
|
324
|
+
body: JSON.stringify(body),
|
|
325
|
+
});
|
|
326
|
+
if (!res.ok) throw new Error(`memory-server ${path} failed: ${res.status} ${await res.text()}`);
|
|
327
|
+
return res.json();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Serve search results LEAN (MEMORY_SPEC v3): claim + certainty + domain only —
|
|
332
|
+
* NO premises, NO content dupe, NO ids/timestamps/reinforcement bookkeeping.
|
|
333
|
+
* Deduped by normalized claim so paraphrase clusters read as one line. The raw
|
|
334
|
+
* retrieval is unchanged; the dashboard still gets full rows.
|
|
335
|
+
*/
|
|
336
|
+
function leanEvidence(evidence: any[]): Array<{ claim: string; certainty?: number; domain?: string }> {
|
|
337
|
+
const out: Array<{ claim: string; certainty?: number; domain?: string }> = [];
|
|
338
|
+
const seen = new Set<string>();
|
|
339
|
+
for (const e of evidence || []) {
|
|
340
|
+
const claim = String(e?.claim ?? e?.content?.claim ?? "").trim();
|
|
341
|
+
if (!claim) continue;
|
|
342
|
+
const key = claim.toLowerCase();
|
|
343
|
+
if (seen.has(key)) continue;
|
|
344
|
+
seen.add(key);
|
|
345
|
+
const item: { claim: string; certainty?: number; domain?: string } = { claim };
|
|
346
|
+
if (typeof e?.certainty === "number") item.certainty = e.certainty;
|
|
347
|
+
if (typeof e?.domain === "string") item.domain = e.domain;
|
|
348
|
+
out.push(item);
|
|
349
|
+
}
|
|
350
|
+
return out;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Execute a platform memory tool. Always resolves — errors come back as
|
|
355
|
+
* {success:false, error} so the agent can read and react to them.
|
|
356
|
+
*/
|
|
357
|
+
export async function executePlatformMemoryMethod(method: string, params: any, context: any): Promise<any> {
|
|
358
|
+
const identity = resolveIdentity(params, context);
|
|
359
|
+
if ("error" in identity) {
|
|
360
|
+
logger.warn(`Memory tool ${method} refused`, { error: identity.error });
|
|
361
|
+
return { success: false, method, error: identity.error };
|
|
362
|
+
}
|
|
363
|
+
const { userId, workflowId, agentId, agentName, accessToken, conversationId, executionId } = identity;
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
switch (method) {
|
|
367
|
+
// ---- user memory (the ONE depth tool; the standing snapshot is harness-injected) ----
|
|
368
|
+
case "queryMemory": {
|
|
369
|
+
const evidence = await GetMemoryService.search({
|
|
370
|
+
userId,
|
|
371
|
+
workflowId,
|
|
372
|
+
query: params?.query,
|
|
373
|
+
limit: 15,
|
|
374
|
+
accessToken,
|
|
375
|
+
});
|
|
376
|
+
const lean = leanEvidence(evidence);
|
|
377
|
+
return { evidence: lean, count: lean.length };
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// ---- agent memory (goal-scoped) ----
|
|
381
|
+
case "getGoalContext": {
|
|
382
|
+
return await memoryServerGet("/agent/goal-context", { userId, workflowId, agentId }, accessToken);
|
|
383
|
+
}
|
|
384
|
+
case "writeNote": {
|
|
385
|
+
return await memoryServerPost(
|
|
386
|
+
"/agent/note",
|
|
387
|
+
{
|
|
388
|
+
userId,
|
|
389
|
+
workflowId,
|
|
390
|
+
agentId,
|
|
391
|
+
agentName,
|
|
392
|
+
content: params?.content,
|
|
393
|
+
category: params?.category || "note",
|
|
394
|
+
executionId,
|
|
395
|
+
conversationId,
|
|
396
|
+
},
|
|
397
|
+
accessToken,
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
case "updateGoalState": {
|
|
401
|
+
// description, acceptanceCriteria and directive are first-class columns on the goal
|
|
402
|
+
// (the judge reads criteria from goal.acceptanceCriteria; the directive is the one
|
|
403
|
+
// platform instruction slot), NOT part of the free-form state blob — pull them out so
|
|
404
|
+
// they route to their own fields. `directive` is only sent when the caller passed it,
|
|
405
|
+
// because null means CLEAR.
|
|
406
|
+
const { description, acceptanceCriteria, directive, ...stateFields } = params || {};
|
|
407
|
+
const state = Object.keys(stateFields).length > 0 ? stateFields : undefined;
|
|
408
|
+
const body: Record<string, any> = { userId, workflowId, agentId, agentName, description, acceptanceCriteria, state };
|
|
409
|
+
if (params && Object.prototype.hasOwnProperty.call(params, "directive")) body.directive = directive ?? null;
|
|
410
|
+
return await memoryServerPost("/agent/state", body, accessToken);
|
|
411
|
+
}
|
|
412
|
+
case "recordAttempt": {
|
|
413
|
+
// The judge's verdict → one ledger row. Platform-only (PLATFORM_MEMORY_METHODS).
|
|
414
|
+
return await memoryServerPost(
|
|
415
|
+
"/agent/attempt",
|
|
416
|
+
{ userId, workflowId, agentId, results: params?.results, deliverables: params?.deliverables || [] },
|
|
417
|
+
accessToken,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
case "searchHistory": {
|
|
421
|
+
return await memoryServerGet(
|
|
422
|
+
"/agent/history",
|
|
423
|
+
{ userId, workflowId, limit: String(params?.limit || 10) },
|
|
424
|
+
accessToken,
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
case "resumeGoal": {
|
|
428
|
+
return await memoryServerPost(
|
|
429
|
+
"/agent/resume",
|
|
430
|
+
{ userId, workflowId, agentId, goalId: params?.goalId },
|
|
431
|
+
accessToken,
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
case "archiveGoal": {
|
|
435
|
+
return await memoryServerPost(
|
|
436
|
+
"/agent/archive",
|
|
437
|
+
{ userId, workflowId, agentId, summary: params?.summary, conversationId },
|
|
438
|
+
accessToken,
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
default:
|
|
443
|
+
return { success: false, method, error: `Unknown platform memory method: ${method}` };
|
|
444
|
+
}
|
|
445
|
+
} catch (error: any) {
|
|
446
|
+
logger.error(`Memory tool ${method} failed`, { error: error.message });
|
|
447
|
+
return { success: false, method, error: error.message };
|
|
448
|
+
}
|
|
449
|
+
}
|