@rubytech/create-maxy-code 0.1.411 → 0.1.414
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/dist/__tests__/installer-cwd-pin-and-auth-verify.test.js +82 -0
- package/dist/index.js +44 -5
- package/package.json +1 -1
- package/payload/platform/lib/account-scope/dist/index.d.ts +27 -0
- package/payload/platform/lib/account-scope/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/account-scope/dist/index.js +33 -0
- package/payload/platform/lib/account-scope/dist/index.js.map +1 -0
- package/payload/platform/lib/account-scope/src/index.ts +43 -0
- package/payload/platform/lib/account-scope/tsconfig.json +5 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +37 -1
- package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +2 -0
- package/payload/platform/plugins/docs/references/cross-account-authority.md +25 -0
- package/payload/platform/plugins/docs/references/memory-guide.md +6 -0
- package/payload/platform/plugins/filesystem/.claude-plugin/plugin.json +21 -0
- package/payload/platform/plugins/filesystem/PLUGIN.md +63 -0
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/index.js +193 -0
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/filesystem/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/index.js +91 -0
- package/payload/platform/plugins/filesystem/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.js +89 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/result.d.ts +12 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/result.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/result.js +6 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/result.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts +45 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js +86 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/walk.d.ts +11 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/walk.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/walk.js +64 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/walk.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.js +94 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts +8 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js +40 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.d.ts +6 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.js +13 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.d.ts +7 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.js +71 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.d.ts +6 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.js +26 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.d.ts +6 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.js +28 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts +7 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js +25 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/package.json +21 -0
- package/payload/platform/plugins/filesystem/mcp/vitest.config.ts +8 -0
- package/payload/platform/plugins/memory/PLUGIN.md +8 -0
- package/payload/platform/plugins/memory/mcp/dist/index-testable.d.ts +34 -0
- package/payload/platform/plugins/memory/mcp/dist/index-testable.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/index-testable.js +60 -0
- package/payload/platform/plugins/memory/mcp/dist/index-testable.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +327 -146
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-owner-userid.d.ts +15 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-owner-userid.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-owner-userid.js +29 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-owner-userid.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/cross-account.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/cross-account.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/cross-account.test.js +74 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/cross-account.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-owner-userid.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-owner-userid.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-owner-userid.test.js +40 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-owner-userid.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-tool-account.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-tool-account.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-tool-account.test.js +54 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-tool-account.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +11 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +13 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/claude-host-creds.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/claude-host-creds.js +6 -1
- package/payload/platform/services/claude-session-manager/dist/claude-host-creds.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/claude-keychain-write.d.ts +7 -1
- package/payload/platform/services/claude-session-manager/dist/claude-keychain-write.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/claude-keychain-write.js +7 -2
- package/payload/platform/services/claude-session-manager/dist/claude-keychain-write.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +37 -0
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +34 -1
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/cross-account-census.d.ts +34 -0
- package/payload/platform/services/claude-session-manager/dist/cross-account-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/cross-account-census.js +98 -0
- package/payload/platform/services/claude-session-manager/dist/cross-account-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +10 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +17 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +25 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +7 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/server/{chunk-ZYS5V5QG.js → chunk-3Z5WE53X.js} +4 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-BRQgI2lW.js → AdminLoginScreens-CYPTMmTk.js} +1 -1
- package/payload/server/public/assets/{AdminShell-By9n5icG.js → AdminShell-CZH_EZIy.js} +1 -1
- package/payload/server/public/assets/{Checkbox-DjEWgYu1.js → Checkbox-B0pbYJDQ.js} +1 -1
- package/payload/server/public/assets/{Transcript-BejWvOaO.js → Transcript-CYaAPBFX.js} +1 -1
- package/payload/server/public/assets/{admin-BFEMryQm.js → admin-BKDMSRto.js} +1 -1
- package/payload/server/public/assets/{browser-CMJMEUz6.js → browser-CxeMDDZA.js} +1 -1
- package/payload/server/public/assets/{calendar-C6ZGlHEP.js → calendar-DiIiTY9-.js} +1 -1
- package/payload/server/public/assets/chat-C56Oqvt1.js +1 -0
- package/payload/server/public/assets/chevron-left-Da-iZGi_.js +1 -0
- package/payload/server/public/assets/data-ZUdT44Ba.js +1 -0
- package/payload/server/public/assets/{graph-DIrXtPLv.js → graph-DC3dwnMZ.js} +1 -1
- package/payload/server/public/assets/{graph-labels-BtPf1Jom.js → graph-labels-Csnovm_c.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DeJ4K8kL.js → maximize-2-WRUJsg5n.js} +1 -1
- package/payload/server/public/assets/{operator-B8QhqzLI.js → operator-BpzeHTAw.js} +1 -1
- package/payload/server/public/assets/{page-iFOy0dFx.js → page-8jJOxx6y.js} +1 -1
- package/payload/server/public/assets/{page-Df6KYkf4.js → page-IQDLdebG.js} +1 -1
- package/payload/server/public/assets/{public-BrUIRQZd.js → public-Dqg7jwjq.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-CYfntpwu.js → rotate-ccw-BayMWwfc.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-Cvnc_fwQ.css → useSubAccountSwitcher-CRZfyJXR.css} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +5 -5
- package/payload/server/public/chat.html +9 -9
- package/payload/server/public/data.html +8 -8
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +11 -11
- package/payload/server/public/operator.html +11 -11
- package/payload/server/public/public.html +9 -9
- package/payload/server/server.js +72 -15
- package/payload/server/public/assets/chat-B7s62Nnp.js +0 -1
- package/payload/server/public/assets/chevron-left-Dfjcaiyr.js +0 -1
- package/payload/server/public/assets/data-741ZbBwR.js +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-BK_KfOLC.js → useSubAccountSwitcher-C9aLg8yI.js} +0 -0
|
@@ -41,6 +41,7 @@ import { profileRead } from "./tools/profile-read.js";
|
|
|
41
41
|
import { memoryBrainCaptureRecent } from "./tools/memory-brain-capture-recent.js";
|
|
42
42
|
import { profileUpdate } from "./tools/profile-update.js";
|
|
43
43
|
import { profileDelete } from "./tools/profile-delete.js";
|
|
44
|
+
import { resolveOwnerUserId } from "./lib/resolve-owner-userid.js";
|
|
44
45
|
import { graphPruneDenylistAdd } from "./tools/graph-prune-denylist-add.js";
|
|
45
46
|
import { graphPruneDenylistList } from "./tools/graph-prune-denylist-list.js";
|
|
46
47
|
import { graphPruneDenylistRemove } from "./tools/graph-prune-denylist-remove.js";
|
|
@@ -59,6 +60,10 @@ import { getSession, closeDriver } from "./lib/neo4j.js";
|
|
|
59
60
|
import { embed } from "./lib/embeddings.js";
|
|
60
61
|
import { notTrashed } from "../../../../lib/graph-trash/dist/index.js";
|
|
61
62
|
import { lifelineTool } from "../../../../lib/mcp-lifeline/dist/index.js";
|
|
63
|
+
import { resolve } from "node:path";
|
|
64
|
+
import { enumerateValidAccountIds } from "../../../../lib/account-enumeration/dist/index.js";
|
|
65
|
+
import { readHouseAdminScope } from "../../../../lib/account-scope/dist/index.js";
|
|
66
|
+
import { makeResolveToolAccount } from "./index-testable.js";
|
|
62
67
|
const server = new McpServer({
|
|
63
68
|
name: "maxy-memory",
|
|
64
69
|
version: "0.1.0",
|
|
@@ -74,17 +79,62 @@ const accountId = process.env.ACCOUNT_ID ?? null;
|
|
|
74
79
|
// accountId`; `agentSlug` empty on a specialist spawn (provenance lost);
|
|
75
80
|
// `agentScope` non-empty on the admin operator spawn (search wrongly scoped).
|
|
76
81
|
process.stderr.write(`[memory] boot accountId=${accountId ?? "null"} sessionId=${process.env.SESSION_ID || "-"} agentSlug=${process.env.AGENT_SLUG || "-"} agentScope=${process.env.AGENT_SLUG_SCOPE || "-"}\n`);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
// The no-account refusal (formerly `refuseNoAccount`) is now handled inside
|
|
83
|
+
// `resolveToolAccount` / `makeResolveToolAccount` (index-testable.ts), which
|
|
84
|
+
// preserves the same message when the boot ACCOUNT_ID is null. Task 1455.
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Cross-account authority (Task 1455). A house-scoped admin session may set an
|
|
87
|
+
// optional `targetAccountId` on any account-scoped tool to read/write a
|
|
88
|
+
// sub-account's subgraph; omitting it is byte-identical to own-account.
|
|
89
|
+
//
|
|
90
|
+
// `houseScope` rides the spawn env (Task 1440, `HOUSE_ADMIN_SCOPE`). `accountsDir`
|
|
91
|
+
// mirrors neo4j.ts's platform-root resolution (PLATFORM_ROOT env, else relative
|
|
92
|
+
// to the compiled file): from dist/index.js, `../../../..` is `platform/`, and
|
|
93
|
+
// accounts live at `<platform>/../data/accounts`. `enumerateValidAccountIds`
|
|
94
|
+
// returns [] (never throws) on a missing dir, so a misresolved path fails CLOSED
|
|
95
|
+
// — every target rejects invalid-target. The boot line makes that visible rather
|
|
96
|
+
// than silent: a zero `validAccounts` on a provisioned install is the alarm.
|
|
97
|
+
const houseScope = readHouseAdminScope();
|
|
98
|
+
const accountsDir = resolve(process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."), "..", "data/accounts");
|
|
99
|
+
process.stderr.write(`[xacct] boot houseScope=${houseScope ? "yes" : "no"} accountsDir=${accountsDir} validAccounts=${enumerateValidAccountIds(accountsDir).length}\n`);
|
|
100
|
+
const resolveToolAccount = makeResolveToolAccount({
|
|
101
|
+
accountId,
|
|
102
|
+
houseScope,
|
|
103
|
+
isValid: (id) => enumerateValidAccountIds(accountsDir).includes(id),
|
|
104
|
+
});
|
|
105
|
+
// Single source for the operator-facing targetAccountId description — the LLM
|
|
106
|
+
// reads this verbatim, so it must not drift across the 35 targetable tools.
|
|
107
|
+
const XACCT_DESC = "House-scoped admin only: operate on the named sub-account subgraph instead of your own. Only a house-scoped session may set this; a non-house session that sets it is rejected.";
|
|
108
|
+
// Boot account, captured before the tool handlers shadow `accountId` with the
|
|
109
|
+
// resolved (possibly cross-account) id. A resolved id != this is a cross-account
|
|
110
|
+
// call (the resolver only returns a target for a house-authorised session).
|
|
111
|
+
const BOOT_ACCOUNT_ID = accountId;
|
|
112
|
+
async function resolveProfileIdentity(toolName, crossAccount, resolvedAccountId, callerUserId) {
|
|
113
|
+
if (crossAccount) {
|
|
114
|
+
const owner = await resolveOwnerUserId(resolvedAccountId);
|
|
115
|
+
if (!owner) {
|
|
116
|
+
return {
|
|
117
|
+
reject: {
|
|
118
|
+
content: [{
|
|
119
|
+
type: "text",
|
|
120
|
+
text: `${toolName} failed: target account ${resolvedAccountId.slice(0, 8)}… has no owner AdminUser to attribute the profile to — its graph root is unprovisioned (see Task 1359 seedAccountGraphRoot).`,
|
|
121
|
+
}],
|
|
122
|
+
isError: true,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
process.stderr.write(`[xacct] op=identity tool=${toolName} target=${resolvedAccountId.slice(0, 8)} resolved-userId=${owner.slice(0, 8)}\n`);
|
|
127
|
+
return { userId: owner };
|
|
128
|
+
}
|
|
129
|
+
if (!callerUserId) {
|
|
130
|
+
return {
|
|
131
|
+
reject: {
|
|
132
|
+
content: [{ type: "text", text: `${toolName} requires an authenticated admin session with userId` }],
|
|
133
|
+
isError: true,
|
|
84
134
|
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return { userId: callerUserId };
|
|
88
138
|
}
|
|
89
139
|
// Load the markdown schema sidecar once at startup. Every memory-write call
|
|
90
140
|
// reads its required-property and synonym maps. If loading fails we throw —
|
|
@@ -242,9 +292,12 @@ eagerTool(server, "memory-search", "Search the knowledge graph using semantic ve
|
|
|
242
292
|
.enum(["entity", "temporal", "event", "general", "none"])
|
|
243
293
|
.optional()
|
|
244
294
|
.describe("Hint that selects the per-class index mix (route-hint contract). Pass 'entity' for who/what-is-this lookups (vector-heavy, Person|Company|Concept filter), 'temporal' for when-did-this-happen (BM25-heavy over :Event with Timeline), 'event' for pure event listings, 'none' to skip graph lookup entirely (greetings/instructions). Omit or pass 'general' for the balanced default. Routing only takes effect when MAXY_GS_ROUTE is enabled; otherwise the value is recorded in the log line but does not change index selection."),
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
295
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
296
|
+
}, async ({ query, labels, limit, expandHops, keywords, keywordMatch, agentSlug: toolAgentSlug, fields, retrievalClass, targetAccountId }) => {
|
|
297
|
+
const scoped = resolveToolAccount("memory-search", targetAccountId);
|
|
298
|
+
if ("reject" in scoped)
|
|
299
|
+
return scoped.reject;
|
|
300
|
+
const accountId = scoped.accountId;
|
|
248
301
|
// AGENT_SLUG_SCOPE takes precedence over the tool param (security: public
|
|
249
302
|
// agent server-level enforcement). Empty for the admin operator, so admin
|
|
250
303
|
// falls through to the optional tool param (default: unscoped).
|
|
@@ -358,9 +411,12 @@ eagerTool(server, "memory-lookup-by-name", "Deterministic by-name entity lookup.
|
|
|
358
411
|
.number()
|
|
359
412
|
.optional()
|
|
360
413
|
.describe("Maximum number of matching nodes to return (default 25)."),
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
414
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
415
|
+
}, async ({ name, labels, limit, targetAccountId }) => {
|
|
416
|
+
const scoped = resolveToolAccount("memory-lookup-by-name", targetAccountId);
|
|
417
|
+
if ("reject" in scoped)
|
|
418
|
+
return scoped.reject;
|
|
419
|
+
const accountId = scoped.accountId;
|
|
364
420
|
const effectiveAgentSlug = envAgentScopeSlug;
|
|
365
421
|
try {
|
|
366
422
|
const hits = await memoryLookupByName({
|
|
@@ -425,9 +481,12 @@ lifelineTool(server, "conversation-archive-list-chunks", "Page through the :Sect
|
|
|
425
481
|
.max(20)
|
|
426
482
|
.optional()
|
|
427
483
|
.describe("Chunks per page (1..20). Default 5."),
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
484
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
485
|
+
}, async ({ archiveElementId, chunkOffset, chunkLimit, targetAccountId }) => {
|
|
486
|
+
const scoped = resolveToolAccount("conversation-archive-list-chunks", targetAccountId);
|
|
487
|
+
if ("reject" in scoped)
|
|
488
|
+
return scoped.reject;
|
|
489
|
+
const accountId = scoped.accountId;
|
|
431
490
|
try {
|
|
432
491
|
const result = await conversationArchiveListChunks({
|
|
433
492
|
accountId,
|
|
@@ -504,9 +563,12 @@ lifelineTool(server, "conversation-archive-derive-insights", "Convert one chunk'
|
|
|
504
563
|
.describe("Claims the dispatched specialist emitted in-turn from the chunk body. Zero is valid — pass [] to record an empty-chunk pass."),
|
|
505
564
|
inlineRewrite: z.boolean().optional().describe("When true, count mention-claim subjects in this chunk and return those reaching inlineRewriteThreshold in inlineRewriteSignals. The calling skill accumulates signals across chunks; when an entity's cumulative count hits threshold, resolve it via memory-search and dispatch the compiled-truth-rewriter specialist."),
|
|
506
565
|
inlineRewriteThreshold: z.number().int().min(1).optional().describe("Minimum mention-claim count for a subject to appear in inlineRewriteSignals. Default: 2."),
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
566
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
567
|
+
}, async ({ archiveElementId, chunkElementId, claims, inlineRewrite, inlineRewriteThreshold, targetAccountId }) => {
|
|
568
|
+
const scoped = resolveToolAccount("conversation-archive-derive-insights", targetAccountId);
|
|
569
|
+
if ("reject" in scoped)
|
|
570
|
+
return scoped.reject;
|
|
571
|
+
const accountId = scoped.accountId;
|
|
510
572
|
try {
|
|
511
573
|
const result = await conversationArchiveDeriveInsights({
|
|
512
574
|
accountId,
|
|
@@ -583,9 +645,12 @@ lifelineTool(server, "conversation-archive-enrich-rejection", "Record or undo a
|
|
|
583
645
|
mode: z
|
|
584
646
|
.enum(["record", "undo"])
|
|
585
647
|
.describe("record = append rejection; undo = remove rejection (called after `wire`)."),
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
648
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
649
|
+
}, async ({ archiveElementId, chunkElementId, kind, contentHash, mode, targetAccountId }) => {
|
|
650
|
+
const scoped = resolveToolAccount("conversation-archive-enrich-rejection", targetAccountId);
|
|
651
|
+
if ("reject" in scoped)
|
|
652
|
+
return scoped.reject;
|
|
653
|
+
const accountId = scoped.accountId;
|
|
589
654
|
try {
|
|
590
655
|
const result = await conversationArchiveEnrichRejection({
|
|
591
656
|
accountId,
|
|
@@ -629,9 +694,12 @@ eagerTool(server, "memory-report-read-latest", "Return the most recent :Report n
|
|
|
629
694
|
.max(20)
|
|
630
695
|
.optional()
|
|
631
696
|
.describe("Maximum number of reports to return, newest first. Default 1."),
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
697
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
698
|
+
}, async ({ keyword, limit, targetAccountId }) => {
|
|
699
|
+
const scoped = resolveToolAccount("memory-report-read-latest", targetAccountId);
|
|
700
|
+
if ("reject" in scoped)
|
|
701
|
+
return scoped.reject;
|
|
702
|
+
const accountId = scoped.accountId;
|
|
635
703
|
try {
|
|
636
704
|
const result = await memoryReportReadLatest({ accountId, keyword, limit });
|
|
637
705
|
if (result.results.length === 0) {
|
|
@@ -686,9 +754,12 @@ eagerTool(server, "memory-report-list", "List :Report nodes, newest first, with
|
|
|
686
754
|
.min(0)
|
|
687
755
|
.optional()
|
|
688
756
|
.describe("Zero-based offset for pagination. Default 0."),
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
757
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
758
|
+
}, async ({ keyword, sourceWorkflow, limit, offset, targetAccountId }) => {
|
|
759
|
+
const scoped = resolveToolAccount("memory-report-list", targetAccountId);
|
|
760
|
+
if ("reject" in scoped)
|
|
761
|
+
return scoped.reject;
|
|
762
|
+
const accountId = scoped.accountId;
|
|
692
763
|
try {
|
|
693
764
|
const result = await memoryReportList({
|
|
694
765
|
accountId,
|
|
@@ -736,9 +807,12 @@ eagerTool(server, "memory-compiled-truth-history", "Return the audit history of
|
|
|
736
807
|
nodeId: z
|
|
737
808
|
.string()
|
|
738
809
|
.describe("elementId of the :Person | :Organization | :Concept whose revision history is being read."),
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
810
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
811
|
+
}, async ({ nodeId, targetAccountId }) => {
|
|
812
|
+
const scoped = resolveToolAccount("memory-compiled-truth-history", targetAccountId);
|
|
813
|
+
if ("reject" in scoped)
|
|
814
|
+
return scoped.reject;
|
|
815
|
+
const accountId = scoped.accountId;
|
|
742
816
|
try {
|
|
743
817
|
const result = await memoryCompiledTruthHistory({ accountId, nodeId });
|
|
744
818
|
if (result.revisions.length === 0) {
|
|
@@ -793,9 +867,12 @@ if (!readOnly) {
|
|
|
793
867
|
.string()
|
|
794
868
|
.optional()
|
|
795
869
|
.describe("Active Task elementId for autonomous-workflow writes. When set, an inbound :PRODUCED edge from this Task is composed into relationships before the write. Task must share the same accountId; mismatch is rejected. Omit for direct conversation asks — the platform composes the edge from the active conversation instead."),
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
870
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
871
|
+
}, async ({ labels, properties, scope, relationships, producedByTaskId, targetAccountId }) => {
|
|
872
|
+
const scoped = resolveToolAccount("memory-write", targetAccountId);
|
|
873
|
+
if ("reject" in scoped)
|
|
874
|
+
return scoped.reject;
|
|
875
|
+
const accountId = scoped.accountId;
|
|
799
876
|
try {
|
|
800
877
|
const result = await memoryWrite({
|
|
801
878
|
labels,
|
|
@@ -853,9 +930,12 @@ if (!readOnly) {
|
|
|
853
930
|
.string()
|
|
854
931
|
.optional()
|
|
855
932
|
.describe("ISO 8601 timestamp the report describes. Defaults to now(). Override only when persisting a backdated report."),
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
933
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
934
|
+
}, async ({ title, body, keywords, sourceWorkflow, occurredAt, targetAccountId }) => {
|
|
935
|
+
const scoped = resolveToolAccount("memory-report-write", targetAccountId);
|
|
936
|
+
if ("reject" in scoped)
|
|
937
|
+
return scoped.reject;
|
|
938
|
+
const accountId = scoped.accountId;
|
|
859
939
|
try {
|
|
860
940
|
const result = await memoryReportWrite({
|
|
861
941
|
accountId,
|
|
@@ -896,9 +976,12 @@ if (!readOnly) {
|
|
|
896
976
|
properties: z
|
|
897
977
|
.record(z.string(), z.unknown())
|
|
898
978
|
.describe("Properties to set or overwrite. Same restrictions as memory-update — embedding/accountId/createdAt are silently stripped; compiled-truth fields are refused unless the caller is the compiled-truth-rewriter specialist."),
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
979
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
980
|
+
}, async ({ label, name, properties, targetAccountId }) => {
|
|
981
|
+
const scoped = resolveToolAccount("memory-update-by-name", targetAccountId);
|
|
982
|
+
if ("reject" in scoped)
|
|
983
|
+
return scoped.reject;
|
|
984
|
+
const accountId = scoped.accountId;
|
|
902
985
|
try {
|
|
903
986
|
const result = await memoryUpdateByName({
|
|
904
987
|
label,
|
|
@@ -937,9 +1020,12 @@ if (!readOnly) {
|
|
|
937
1020
|
properties: z
|
|
938
1021
|
.record(z.string(), z.unknown())
|
|
939
1022
|
.describe("Properties to set or overwrite. Restricted keys (embedding, accountId, createdAt) are ignored. Compiled-truth fields are system-managed; only the compiled-truth-rewriter specialist may write them."),
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1023
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1024
|
+
}, async ({ nodeId, properties, targetAccountId }) => {
|
|
1025
|
+
const scoped = resolveToolAccount("memory-update", targetAccountId);
|
|
1026
|
+
if ("reject" in scoped)
|
|
1027
|
+
return scoped.reject;
|
|
1028
|
+
const accountId = scoped.accountId;
|
|
943
1029
|
try {
|
|
944
1030
|
const result = await memoryUpdate({
|
|
945
1031
|
nodeId,
|
|
@@ -978,9 +1064,12 @@ if (!readOnly) {
|
|
|
978
1064
|
toId: z.string().describe("elementId of the target node (from memory-search results)."),
|
|
979
1065
|
relationshipType: z.string().describe("Relationship type label — e.g. RELATES_TO, MENTIONS, WORKED_WITH. Uppercase-coerced. Underscore-prefixed types (_SOFT_DELETE, etc.) are reserved and rejected."),
|
|
980
1066
|
properties: z.record(z.string(), z.unknown()).optional().describe("Properties to set on the relationship on CREATE. Ignored on DELETE and on idempotent CREATE (MERGE-matched)."),
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1067
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1068
|
+
}, async ({ action, fromId, toId, relationshipType, properties, targetAccountId }) => {
|
|
1069
|
+
const scoped = resolveToolAccount("memory-edge", targetAccountId);
|
|
1070
|
+
if ("reject" in scoped)
|
|
1071
|
+
return scoped.reject;
|
|
1072
|
+
const accountId = scoped.accountId;
|
|
984
1073
|
try {
|
|
985
1074
|
const result = await memoryEdge({
|
|
986
1075
|
action,
|
|
@@ -1014,9 +1103,13 @@ if (!readOnly) {
|
|
|
1014
1103
|
};
|
|
1015
1104
|
}
|
|
1016
1105
|
});
|
|
1017
|
-
eagerTool(server, "session-compact-status", "Check whether a session compaction summary exists in the graph. Returns the most recent summary title, date, and briefing text. Use this at session start to determine whether a prior session was compacted and its context should be restored.", {
|
|
1018
|
-
|
|
1019
|
-
|
|
1106
|
+
eagerTool(server, "session-compact-status", "Check whether a session compaction summary exists in the graph. Returns the most recent summary title, date, and briefing text. Use this at session start to determine whether a prior session was compacted and its context should be restored.", {
|
|
1107
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1108
|
+
}, async ({ targetAccountId }) => {
|
|
1109
|
+
const scoped = resolveToolAccount("session-compact-status", targetAccountId);
|
|
1110
|
+
if ("reject" in scoped)
|
|
1111
|
+
return scoped.reject;
|
|
1112
|
+
const accountId = scoped.accountId;
|
|
1020
1113
|
const session = getSession();
|
|
1021
1114
|
try {
|
|
1022
1115
|
const result = await session.run(`MATCH (n:CreativeWork {accountId: $accountId})
|
|
@@ -1043,8 +1136,10 @@ if (!readOnly) {
|
|
|
1043
1136
|
eagerTool(server, "session-compact", "Write a session summary to the knowledge graph. Call this when compacting context — provide the full briefing and the tool handles labelling, structure, and embedding.", {
|
|
1044
1137
|
content: z.string().describe("The session briefing — what was discussed, decisions made, work in progress, open questions, and anything learned about the user or their business"),
|
|
1045
1138
|
}, async ({ content }) => {
|
|
1046
|
-
|
|
1047
|
-
|
|
1139
|
+
const scoped = resolveToolAccount("session-compact", undefined);
|
|
1140
|
+
if ("reject" in scoped)
|
|
1141
|
+
return scoped.reject;
|
|
1142
|
+
const accountId = scoped.accountId;
|
|
1048
1143
|
try {
|
|
1049
1144
|
// Write doctrine: session summaries link back to the
|
|
1050
1145
|
// Conversation they summarise, so an operator searching a session's
|
|
@@ -1103,9 +1198,13 @@ if (!readOnly) {
|
|
|
1103
1198
|
};
|
|
1104
1199
|
}
|
|
1105
1200
|
});
|
|
1106
|
-
eagerTool(server, "memory-reindex", "Rebuild vector embeddings for all nodes missing embeddings. Run after seeding or bulk updates.", {
|
|
1107
|
-
|
|
1108
|
-
|
|
1201
|
+
eagerTool(server, "memory-reindex", "Rebuild vector embeddings for all nodes missing embeddings. Run after seeding or bulk updates.", {
|
|
1202
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1203
|
+
}, async ({ targetAccountId }) => {
|
|
1204
|
+
const scoped = resolveToolAccount("memory-reindex", targetAccountId);
|
|
1205
|
+
if ("reject" in scoped)
|
|
1206
|
+
return scoped.reject;
|
|
1207
|
+
const accountId = scoped.accountId;
|
|
1109
1208
|
try {
|
|
1110
1209
|
const result = await memoryReindex(accountId);
|
|
1111
1210
|
return {
|
|
@@ -1140,8 +1239,10 @@ if (!readOnly) {
|
|
|
1140
1239
|
mimeType: z.string().describe("MIME type of the file"),
|
|
1141
1240
|
attachmentId: z.string().describe("UUID of the file attachment — used as cache key for memory-ingest"),
|
|
1142
1241
|
}, async ({ storagePath, filename, mimeType, attachmentId }) => {
|
|
1143
|
-
|
|
1144
|
-
|
|
1242
|
+
const scoped = resolveToolAccount("memory-ingest-extract", undefined);
|
|
1243
|
+
if ("reject" in scoped)
|
|
1244
|
+
return scoped.reject;
|
|
1245
|
+
const accountId = scoped.accountId;
|
|
1145
1246
|
try {
|
|
1146
1247
|
const result = await memoryIngestExtract({ storagePath, filename, mimeType, attachmentId });
|
|
1147
1248
|
return {
|
|
@@ -1231,9 +1332,12 @@ if (!readOnly) {
|
|
|
1231
1332
|
inlineRewrite: z.boolean().optional().describe("When true, after writing all sections and edges, run the inline compiled-truth reconciliation gate. Counts MENTIONS/REFERENCES edges from this document (KnowledgeDocument + its sections) to existing entities that carry compiledTruth. Entities with >= inlineRewriteThreshold such edges (default 2) and compiledTruthUpdatedAt older than 7 days are returned in inlineRewriteCandidates. Dispatch the compiled-truth-rewriter specialist for each before the skill returns. Disabled by default."),
|
|
1232
1333
|
forceRewrite: z.boolean().optional().describe("When inlineRewrite is true, bypass the 7-day per-entity cooldown on compiledTruthUpdatedAt. All threshold-qualifying entities are returned as inlineRewriteCandidates regardless of when their truth was last rewritten."),
|
|
1233
1334
|
inlineRewriteThreshold: z.number().int().min(1).optional().describe("Minimum MENTIONS/REFERENCES edge count from this source to an entity for it to qualify as an inline-rewrite candidate. Default: 2."),
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1335
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1336
|
+
}, async ({ attachmentId, conversationIdentity, source, archiveSha256, archiveSourceFile, participantElementIds, lastIngestedMessageHash, lastIngestedMessageAt, archiveTitle, cleanupPriorChunks, sessionIndex, documentSummary, anchorNodeId, anchorLabel, sections, documentEdges, orphanCandidates, scope, sourceUrl, sourceType, documentKeywords, userKeywords, sessionId: sessionIdOverride, inlineRewrite, forceRewrite, inlineRewriteThreshold, targetAccountId }) => {
|
|
1337
|
+
const scoped = resolveToolAccount("memory-ingest", targetAccountId);
|
|
1338
|
+
if ("reject" in scoped)
|
|
1339
|
+
return scoped.reject;
|
|
1340
|
+
const accountId = scoped.accountId;
|
|
1237
1341
|
try {
|
|
1238
1342
|
const result = await memoryIngest({
|
|
1239
1343
|
accountId,
|
|
@@ -1296,9 +1400,12 @@ if (!readOnly) {
|
|
|
1296
1400
|
});
|
|
1297
1401
|
eagerTool(server, "kd-classify", "Operator-solicited reclassify for any :KnowledgeDocument that carries a `body` property (today: email-thread KDs; future: any thread-shaped source). Reads the KD by attachmentId, decides via a body-growth gate (proceed iff body grew ≥25% since the last classify, or first-ever classify), stages the body to a temp file under $ACCOUNT_DIR/tmp/, and returns a dispatch envelope the admin agent hands to the `librarian` specialist. Librarian runs the document-ingest skill against the temp file; memory-ingest MERGEs by attachmentId, replacing any prior :Section children, and stamps lastClassifiedAt + lastClassifiedBodyLength on the KD so the next gate call has a baseline. Bodyless attachment KDs (PDFs etc.) are not supported here — they have no growth signal.", {
|
|
1298
1402
|
attachmentId: z.string().describe("attachmentId of the :KnowledgeDocument to classify. For email threads, this is sha256(`email:<accountId>:<rootMessageId>`)."),
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1403
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1404
|
+
}, async ({ attachmentId, targetAccountId }) => {
|
|
1405
|
+
const scoped = resolveToolAccount("kd-classify", targetAccountId);
|
|
1406
|
+
if ("reject" in scoped)
|
|
1407
|
+
return scoped.reject;
|
|
1408
|
+
const accountId = scoped.accountId;
|
|
1302
1409
|
try {
|
|
1303
1410
|
const text = await kdClassify({ accountId, attachmentId });
|
|
1304
1411
|
return { content: [{ type: "text", text }] };
|
|
@@ -1336,9 +1443,12 @@ if (!readOnly) {
|
|
|
1336
1443
|
.string()
|
|
1337
1444
|
.optional()
|
|
1338
1445
|
.describe("Skill-run UUID for provenance stamping. Falls back to SESSION_ID env var when absent."),
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1446
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1447
|
+
}, async ({ archiveType, ownerNodeId, rows, sessionId: sessionIdOverride, targetAccountId }) => {
|
|
1448
|
+
const scoped = resolveToolAccount("memory-archive-write", targetAccountId);
|
|
1449
|
+
if ("reject" in scoped)
|
|
1450
|
+
return scoped.reject;
|
|
1451
|
+
const accountId = scoped.accountId;
|
|
1342
1452
|
try {
|
|
1343
1453
|
const result = await memoryArchiveWrite({
|
|
1344
1454
|
archiveType,
|
|
@@ -1418,9 +1528,12 @@ if (!readOnly) {
|
|
|
1418
1528
|
.string()
|
|
1419
1529
|
.optional()
|
|
1420
1530
|
.describe("Skill-run UUID for provenance stamping. Falls back to SESSION_ID env var when absent."),
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1531
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1532
|
+
}, async ({ ownerNodeId, extractedDir, mode, importId, filters, resolutions, selectiveIngestThreshold, sessionId: sessionIdOverride, targetAccountId, }) => {
|
|
1533
|
+
const scoped = resolveToolAccount("obsidian-vault-import", targetAccountId);
|
|
1534
|
+
if ("reject" in scoped)
|
|
1535
|
+
return scoped.reject;
|
|
1536
|
+
const accountId = scoped.accountId;
|
|
1424
1537
|
try {
|
|
1425
1538
|
const result = await obsidianVaultImport({
|
|
1426
1539
|
accountId,
|
|
@@ -1469,9 +1582,12 @@ if (!readOnly) {
|
|
|
1469
1582
|
"When present, used verbatim as `KnowledgeDocument.name` (capped at 200 chars). " +
|
|
1470
1583
|
"When absent, the server falls back to the markdown H1, then a URL-derived slug, then the URL."),
|
|
1471
1584
|
scope: z.string().optional().describe("Intended visibility scope (for logging). The actual scope is set when the agent subsequently calls memory-ingest."),
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1585
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1586
|
+
}, async ({ url, content, title, scope, targetAccountId }) => {
|
|
1587
|
+
const scoped = resolveToolAccount("memory-ingest-web", targetAccountId);
|
|
1588
|
+
if ("reject" in scoped)
|
|
1589
|
+
return scoped.reject;
|
|
1590
|
+
const accountId = scoped.accountId;
|
|
1475
1591
|
try {
|
|
1476
1592
|
const result = await memoryIngestWeb({
|
|
1477
1593
|
accountId,
|
|
@@ -1518,9 +1634,12 @@ if (!readOnly) {
|
|
|
1518
1634
|
agentType: z.enum(["admin", "public"]).optional().describe("Scope to conversations matching c.agentType. Omit to scope across both."),
|
|
1519
1635
|
limit: z.number().int().positive().optional().describe("Max candidates to return (default 200, hard cap 1000)."),
|
|
1520
1636
|
dryRun: z.boolean().optional().describe("Preview matches without minting an actionable filterToken. Candidates are listed in the response, but no delete can be performed against them — caller must re-run without dryRun to receive a token."),
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1637
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1638
|
+
}, async ({ filter, agentType, limit, dryRun, targetAccountId }) => {
|
|
1639
|
+
const scoped = resolveToolAccount("memory-find-candidates", targetAccountId);
|
|
1640
|
+
if ("reject" in scoped)
|
|
1641
|
+
return scoped.reject;
|
|
1642
|
+
const accountId = scoped.accountId;
|
|
1524
1643
|
try {
|
|
1525
1644
|
const result = await memoryFindCandidates({ accountId, filter, agentType, limit, dryRun });
|
|
1526
1645
|
if (result.items.length === 0) {
|
|
@@ -1561,9 +1680,12 @@ if (!readOnly) {
|
|
|
1561
1680
|
"ranked discovery on general labels. Use this before any branch that claims a " +
|
|
1562
1681
|
"singleton root is missing.", {
|
|
1563
1682
|
label: z.enum(MEMORY_NODE_EXISTS_LABELS).describe("Installer-seeded singleton label. One of: LocalBusiness, AdminUser, UserProfile, Person."),
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1683
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1684
|
+
}, async ({ label, targetAccountId }) => {
|
|
1685
|
+
const scoped = resolveToolAccount("memory-node-exists", targetAccountId);
|
|
1686
|
+
if ("reject" in scoped)
|
|
1687
|
+
return scoped.reject;
|
|
1688
|
+
const accountId = scoped.accountId;
|
|
1567
1689
|
try {
|
|
1568
1690
|
const result = await memoryNodeExists({ accountId, label });
|
|
1569
1691
|
const payload = JSON.stringify(result);
|
|
@@ -1588,9 +1710,12 @@ if (!readOnly) {
|
|
|
1588
1710
|
filterToken: z.string().optional().describe("Opaque token from memory-find-candidates. Required for bulk-selector flows; the server re-runs the " +
|
|
1589
1711
|
"canonical predicate on this elementId before trashing. Omit for single-node deletes where the caller " +
|
|
1590
1712
|
"chose the target directly (e.g. from a memory-search result)."),
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1713
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1714
|
+
}, async ({ elementId, reason, filterToken, targetAccountId }) => {
|
|
1715
|
+
const scoped = resolveToolAccount("memory-delete", targetAccountId);
|
|
1716
|
+
if ("reject" in scoped)
|
|
1717
|
+
return scoped.reject;
|
|
1718
|
+
const accountId = scoped.accountId;
|
|
1594
1719
|
try {
|
|
1595
1720
|
const result = await memoryDelete({ accountId, elementId, reason, filterToken });
|
|
1596
1721
|
const head = result.alreadyTrashed
|
|
@@ -1617,9 +1742,12 @@ if (!readOnly) {
|
|
|
1617
1742
|
"node needs back (e.g. a fresh LocalBusiness was created while the old one was in trash) — " +
|
|
1618
1743
|
"the error names the conflicting elementId so the caller can decide how to resolve.", {
|
|
1619
1744
|
elementId: z.string().describe("Neo4j elementId of the trashed node to restore."),
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1745
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1746
|
+
}, async ({ elementId, targetAccountId }) => {
|
|
1747
|
+
const scoped = resolveToolAccount("memory-restore", targetAccountId);
|
|
1748
|
+
if ("reject" in scoped)
|
|
1749
|
+
return scoped.reject;
|
|
1750
|
+
const accountId = scoped.accountId;
|
|
1623
1751
|
try {
|
|
1624
1752
|
const result = await memoryRestore({ accountId, elementId });
|
|
1625
1753
|
const cascade = result.cascade.sections + result.cascade.chunks > 0
|
|
@@ -1647,9 +1775,12 @@ if (!readOnly) {
|
|
|
1647
1775
|
graceDays: z.number().int().min(0).optional().describe("Minimum age in days a trashed node must reach before it's eligible. Default 30."),
|
|
1648
1776
|
dryRun: z.boolean().optional().describe("When true, lists candidates without deleting. Default false."),
|
|
1649
1777
|
labels: z.array(z.string()).optional().describe("Optional whitelist of node labels — only nodes carrying any of these labels are eligible."),
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1778
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1779
|
+
}, async ({ graceDays, dryRun, labels, targetAccountId }) => {
|
|
1780
|
+
const scoped = resolveToolAccount("memory-empty-trash", targetAccountId);
|
|
1781
|
+
if ("reject" in scoped)
|
|
1782
|
+
return scoped.reject;
|
|
1783
|
+
const accountId = scoped.accountId;
|
|
1653
1784
|
try {
|
|
1654
1785
|
const result = await memoryEmptyTrash({ accountId, graceDays, dryRun, labels });
|
|
1655
1786
|
const lines = [];
|
|
@@ -1673,9 +1804,13 @@ if (!readOnly) {
|
|
|
1673
1804
|
});
|
|
1674
1805
|
lifelineTool(server, "memory-list-attachments", "List stored file attachments for this account with their ingestion status. " +
|
|
1675
1806
|
"Returns original filenames, sizes, upload dates, and whether each file has been ingested " +
|
|
1676
|
-
"into the knowledge graph. Does not include web-ingested documents (those have no file on disk).", {
|
|
1677
|
-
|
|
1678
|
-
|
|
1807
|
+
"into the knowledge graph. Does not include web-ingested documents (those have no file on disk).", {
|
|
1808
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1809
|
+
}, async ({ targetAccountId }) => {
|
|
1810
|
+
const scoped = resolveToolAccount("memory-list-attachments", targetAccountId);
|
|
1811
|
+
if ("reject" in scoped)
|
|
1812
|
+
return scoped.reject;
|
|
1813
|
+
const accountId = scoped.accountId;
|
|
1679
1814
|
try {
|
|
1680
1815
|
const result = await memoryListAttachments(accountId);
|
|
1681
1816
|
if (result.entries.length === 0) {
|
|
@@ -1713,9 +1848,12 @@ if (!readOnly) {
|
|
|
1713
1848
|
"extracted text for PDFs (via pdftotext), and metadata + HTTP URL for images. " +
|
|
1714
1849
|
"Use this to show the user what's in a file or to prepare content for editing.", {
|
|
1715
1850
|
attachmentId: z.string().describe("UUID of the attachment to read"),
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1851
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1852
|
+
}, async ({ attachmentId, targetAccountId }) => {
|
|
1853
|
+
const scoped = resolveToolAccount("memory-read-attachment", targetAccountId);
|
|
1854
|
+
if ("reject" in scoped)
|
|
1855
|
+
return scoped.reject;
|
|
1856
|
+
const accountId = scoped.accountId;
|
|
1719
1857
|
try {
|
|
1720
1858
|
const result = await memoryReadAttachment(accountId, attachmentId);
|
|
1721
1859
|
let text = `**${result.filename}** (${result.mimeType}, ${result.sizeBytes} bytes)\nStored: ${result.storedAt}\n`;
|
|
@@ -1740,9 +1878,12 @@ if (!readOnly) {
|
|
|
1740
1878
|
"Only text/plain and text/markdown files are editable — PDFs and images are rejected.", {
|
|
1741
1879
|
attachmentId: z.string().describe("UUID of the attachment to edit"),
|
|
1742
1880
|
content: z.string().describe("The full replacement text content"),
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1881
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1882
|
+
}, async ({ attachmentId, content, targetAccountId }) => {
|
|
1883
|
+
const scoped = resolveToolAccount("memory-edit-attachment", targetAccountId);
|
|
1884
|
+
if ("reject" in scoped)
|
|
1885
|
+
return scoped.reject;
|
|
1886
|
+
const accountId = scoped.accountId;
|
|
1746
1887
|
try {
|
|
1747
1888
|
const result = await memoryEditAttachment({ accountId, attachmentId, content });
|
|
1748
1889
|
let text = `Edited: ${result.filename} (${result.oldSizeBytes} → ${result.newSizeBytes} bytes)`;
|
|
@@ -1768,9 +1909,12 @@ if (!readOnly) {
|
|
|
1768
1909
|
"is not renamed — it uses UUID-based naming. Only the human-readable metadata changes.", {
|
|
1769
1910
|
attachmentId: z.string().describe("UUID of the attachment to rename"),
|
|
1770
1911
|
newFilename: z.string().describe("The new filename (e.g. 'quarterly-report-q1.pdf')"),
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1912
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
1913
|
+
}, async ({ attachmentId, newFilename, targetAccountId }) => {
|
|
1914
|
+
const scoped = resolveToolAccount("memory-rename-attachment", targetAccountId);
|
|
1915
|
+
if ("reject" in scoped)
|
|
1916
|
+
return scoped.reject;
|
|
1917
|
+
const accountId = scoped.accountId;
|
|
1774
1918
|
try {
|
|
1775
1919
|
const result = await memoryRenameAttachment({ accountId, attachmentId, newFilename });
|
|
1776
1920
|
if (result.oldFilename === result.newFilename) {
|
|
@@ -1874,9 +2018,12 @@ if (!readOnly) {
|
|
|
1874
2018
|
.number()
|
|
1875
2019
|
.optional()
|
|
1876
2020
|
.describe("Maximum results (default 50 for conversations, 200 for messages)"),
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
2021
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2022
|
+
}, async ({ sessionId, agentType, agentSlug, since, includeMessages, limit, targetAccountId }) => {
|
|
2023
|
+
const scoped = resolveToolAccount("conversation-list", targetAccountId);
|
|
2024
|
+
if ("reject" in scoped)
|
|
2025
|
+
return scoped.reject;
|
|
2026
|
+
const accountId = scoped.accountId;
|
|
1880
2027
|
const startTime = Date.now();
|
|
1881
2028
|
const dbSession = getSession();
|
|
1882
2029
|
try {
|
|
@@ -2055,16 +2202,20 @@ if (!readOnly) {
|
|
|
2055
2202
|
.describe("Operator-identity fields written to the OWNS-bound Person. Use canonical `telephone` (NOT `phone` — that is the schema synonym, not the canonical name). Tool throws if the AdminUser-OWNS-Person edge is missing rather than silently no-op."),
|
|
2056
2203
|
mergeSourceIds: z.array(z.string()).optional()
|
|
2057
2204
|
.describe("For mode 'merge': preferenceIds of sources to combine into this preference"),
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2205
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2206
|
+
}, async ({ category, key, value, source, mode, sessionId, profileFields, personFields, mergeSourceIds, targetAccountId }) => {
|
|
2207
|
+
const scoped = resolveToolAccount("profile-update", targetAccountId);
|
|
2208
|
+
if ("reject" in scoped)
|
|
2209
|
+
return scoped.reject;
|
|
2210
|
+
const accountId = scoped.accountId;
|
|
2211
|
+
const crossAccount = accountId !== BOOT_ACCOUNT_ID;
|
|
2061
2212
|
try {
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2213
|
+
const ident = await resolveProfileIdentity("profile-update", crossAccount, accountId, userId);
|
|
2214
|
+
if ("reject" in ident)
|
|
2215
|
+
return ident.reject;
|
|
2065
2216
|
const result = await profileUpdate({
|
|
2066
2217
|
accountId,
|
|
2067
|
-
userId,
|
|
2218
|
+
userId: ident.userId,
|
|
2068
2219
|
category,
|
|
2069
2220
|
key,
|
|
2070
2221
|
value,
|
|
@@ -2074,6 +2225,7 @@ if (!readOnly) {
|
|
|
2074
2225
|
profileFields: profileFields,
|
|
2075
2226
|
personFields,
|
|
2076
2227
|
mergeSourceIds,
|
|
2228
|
+
bootstrapProfile: crossAccount,
|
|
2077
2229
|
});
|
|
2078
2230
|
return {
|
|
2079
2231
|
content: [{
|
|
@@ -2096,14 +2248,18 @@ if (!readOnly) {
|
|
|
2096
2248
|
category: z.enum(["communication", "scheduling", "decision", "workflow", "content", "interaction"])
|
|
2097
2249
|
.describe("Preference category"),
|
|
2098
2250
|
key: z.string().describe("Preference key to delete"),
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2251
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2252
|
+
}, async ({ category, key, targetAccountId }) => {
|
|
2253
|
+
const scoped = resolveToolAccount("profile-delete", targetAccountId);
|
|
2254
|
+
if ("reject" in scoped)
|
|
2255
|
+
return scoped.reject;
|
|
2256
|
+
const accountId = scoped.accountId;
|
|
2257
|
+
const crossAccount = accountId !== BOOT_ACCOUNT_ID;
|
|
2102
2258
|
try {
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
const result = await profileDelete({ accountId, userId, category, key });
|
|
2259
|
+
const ident = await resolveProfileIdentity("profile-delete", crossAccount, accountId, userId);
|
|
2260
|
+
if ("reject" in ident)
|
|
2261
|
+
return ident.reject;
|
|
2262
|
+
const result = await profileDelete({ accountId, userId: ident.userId, category, key });
|
|
2107
2263
|
return {
|
|
2108
2264
|
content: [{
|
|
2109
2265
|
type: "text",
|
|
@@ -2130,14 +2286,18 @@ if (!readOnly) {
|
|
|
2130
2286
|
"Use detail=true when the owner asks 'what do you know about me?' or when reviewing memory accuracy.", {
|
|
2131
2287
|
detail: z.boolean().optional().describe("When true, returns per-preference confidence, source, evidence trail, and memory statistics. " +
|
|
2132
2288
|
"Default false returns a compact summary for system prompt injection."),
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2289
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2290
|
+
}, async ({ detail, targetAccountId }) => {
|
|
2291
|
+
const scoped = resolveToolAccount("profile-read", targetAccountId);
|
|
2292
|
+
if ("reject" in scoped)
|
|
2293
|
+
return scoped.reject;
|
|
2294
|
+
const accountId = scoped.accountId;
|
|
2295
|
+
const crossAccount = accountId !== BOOT_ACCOUNT_ID;
|
|
2136
2296
|
try {
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
const result = await profileRead({ accountId, userId, detail: detail ?? false });
|
|
2297
|
+
const ident = await resolveProfileIdentity("profile-read", crossAccount, accountId, userId);
|
|
2298
|
+
if ("reject" in ident)
|
|
2299
|
+
return ident.reject;
|
|
2300
|
+
const result = await profileRead({ accountId, userId: ident.userId, detail: detail ?? false });
|
|
2141
2301
|
return {
|
|
2142
2302
|
content: [{ type: "text", text: result.summary }],
|
|
2143
2303
|
};
|
|
@@ -2166,10 +2326,13 @@ if (!readOnly) {
|
|
|
2166
2326
|
"Use this when the operator asks 'what has the brain captured today?', 'show me recent mentions of X', or 'what ideas did I leave on the table this week?'.", {
|
|
2167
2327
|
windowHours: z.number().int().optional().describe("Hours back from now. Default 24. Capped at 720 (30 days)."),
|
|
2168
2328
|
limit: z.number().int().optional().describe("Max rows returned. Default 50, max 200."),
|
|
2169
|
-
|
|
2329
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2330
|
+
}, async ({ windowHours, limit, targetAccountId }) => {
|
|
2170
2331
|
try {
|
|
2171
|
-
|
|
2172
|
-
|
|
2332
|
+
const scoped = resolveToolAccount("memory-brain-capture-recent", targetAccountId);
|
|
2333
|
+
if ("reject" in scoped)
|
|
2334
|
+
return scoped.reject;
|
|
2335
|
+
const accountId = scoped.accountId;
|
|
2173
2336
|
const result = await memoryBrainCaptureRecent({ accountId, windowHours, limit });
|
|
2174
2337
|
return {
|
|
2175
2338
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -2203,8 +2366,10 @@ if (!readOnly) {
|
|
|
2203
2366
|
"per-device and survives upgrades.", {
|
|
2204
2367
|
values: z.array(z.string().min(1)).min(1).describe("Substring values to add. Match is exact substring (case-sensitive) against string-typed properties only."),
|
|
2205
2368
|
}, async ({ values }) => {
|
|
2206
|
-
|
|
2207
|
-
|
|
2369
|
+
const scoped = resolveToolAccount("graph-prune-denylist-add", undefined);
|
|
2370
|
+
if ("reject" in scoped)
|
|
2371
|
+
return scoped.reject;
|
|
2372
|
+
const accountId = scoped.accountId;
|
|
2208
2373
|
try {
|
|
2209
2374
|
const result = await graphPruneDenylistAdd(values);
|
|
2210
2375
|
const lines = [
|
|
@@ -2229,8 +2394,10 @@ if (!readOnly) {
|
|
|
2229
2394
|
"restored — audit entries on each affected node remain for forensic review.", {
|
|
2230
2395
|
values: z.array(z.string().min(1)).min(1).describe("Substring values to remove (must match exactly as previously added)."),
|
|
2231
2396
|
}, async ({ values }) => {
|
|
2232
|
-
|
|
2233
|
-
|
|
2397
|
+
const scoped = resolveToolAccount("graph-prune-denylist-remove", undefined);
|
|
2398
|
+
if ("reject" in scoped)
|
|
2399
|
+
return scoped.reject;
|
|
2400
|
+
const accountId = scoped.accountId;
|
|
2234
2401
|
try {
|
|
2235
2402
|
const result = await graphPruneDenylistRemove(values);
|
|
2236
2403
|
const lines = [
|
|
@@ -2257,9 +2424,12 @@ if (!readOnly) {
|
|
|
2257
2424
|
"that should not propagate (e.g. wrong-account hostnames, fabricated identifiers).", {
|
|
2258
2425
|
sessionId: z.string().min(1).describe("The Conversation node's sessionId to scope the expunge to."),
|
|
2259
2426
|
pattern: z.string().min(1).describe("The substring to scrub from string properties on linked :Memory nodes."),
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2427
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2428
|
+
}, async ({ sessionId, pattern, targetAccountId }) => {
|
|
2429
|
+
const scoped = resolveToolAccount("conversation-memory-expunge", targetAccountId);
|
|
2430
|
+
if ("reject" in scoped)
|
|
2431
|
+
return scoped.reject;
|
|
2432
|
+
const accountId = scoped.accountId;
|
|
2263
2433
|
try {
|
|
2264
2434
|
const result = await conversationMemoryExpunge({ accountId, sessionId, pattern });
|
|
2265
2435
|
const lines = [
|
|
@@ -2286,8 +2456,10 @@ if (!readOnly) {
|
|
|
2286
2456
|
// graph-prune-denylist-list and conversation-search are read-only — available regardless of readOnly mode.
|
|
2287
2457
|
lifelineTool(server, "graph-prune-denylist-list", "List the current operator-curated deny-list values used by the daily graph-prune cron. " +
|
|
2288
2458
|
"Returns the substring values, the timestamp of the last edit, and the total count.", {}, () => {
|
|
2289
|
-
|
|
2290
|
-
|
|
2459
|
+
const scoped = resolveToolAccount("graph-prune-denylist-list", undefined);
|
|
2460
|
+
if ("reject" in scoped)
|
|
2461
|
+
return scoped.reject;
|
|
2462
|
+
const accountId = scoped.accountId;
|
|
2291
2463
|
try {
|
|
2292
2464
|
const result = graphPruneDenylistList();
|
|
2293
2465
|
if (result.count === 0) {
|
|
@@ -2311,9 +2483,12 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
|
|
|
2311
2483
|
.number()
|
|
2312
2484
|
.optional()
|
|
2313
2485
|
.describe("Maximum number of results (default 10)"),
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2486
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2487
|
+
}, async ({ query, limit: maxResults, targetAccountId }) => {
|
|
2488
|
+
const scoped = resolveToolAccount("conversation-search", targetAccountId);
|
|
2489
|
+
if ("reject" in scoped)
|
|
2490
|
+
return scoped.reject;
|
|
2491
|
+
const accountId = scoped.accountId;
|
|
2317
2492
|
try {
|
|
2318
2493
|
const queryEmbedding = await embed(query);
|
|
2319
2494
|
const resultLimit = maxResults ?? 10;
|
|
@@ -2438,9 +2613,12 @@ lifelineTool(server, "memory-dream-run", "Operator-initiated dream-cycle: graph-
|
|
|
2438
2613
|
operatorId: z.string().optional().describe("Identifier of the operator who triggered the run; appears in the report and log line."),
|
|
2439
2614
|
phases: z.array(z.number().int().min(1).max(7)).optional().describe("Subset of phases to run. Default [1,2,3,4,5,6,7]. Order is fixed."),
|
|
2440
2615
|
maxEventsPerRun: z.number().int().positive().optional().describe("Phase 4 cap on :TimelineEvent rows scanned per run. Default 200."),
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2616
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2617
|
+
}, async ({ operatorId, phases, maxEventsPerRun, targetAccountId }) => {
|
|
2618
|
+
const scoped = resolveToolAccount("memory-dream-run", targetAccountId);
|
|
2619
|
+
if ("reject" in scoped)
|
|
2620
|
+
return scoped.reject;
|
|
2621
|
+
const accountId = scoped.accountId;
|
|
2444
2622
|
try {
|
|
2445
2623
|
const result = await memoryDreamRun({ accountId, operatorId, phases, maxEventsPerRun });
|
|
2446
2624
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
@@ -2455,9 +2633,12 @@ lifelineTool(server, "memory-dream-run", "Operator-initiated dream-cycle: graph-
|
|
|
2455
2633
|
lifelineTool(server, "memory-review-queue", "Read-only summary of the dream-cycle's review queues (:OrphanCandidate, :CitationProposal). " +
|
|
2456
2634
|
"Returns per-queue counts and a small sample so the operator can see whether to triage.", {
|
|
2457
2635
|
sampleSize: z.number().int().positive().optional().describe("Sample rows per queue. Default 5, max 25."),
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2636
|
+
targetAccountId: z.string().optional().describe(XACCT_DESC),
|
|
2637
|
+
}, async ({ sampleSize, targetAccountId }) => {
|
|
2638
|
+
const scoped = resolveToolAccount("memory-review-queue", targetAccountId);
|
|
2639
|
+
if ("reject" in scoped)
|
|
2640
|
+
return scoped.reject;
|
|
2641
|
+
const accountId = scoped.accountId;
|
|
2461
2642
|
try {
|
|
2462
2643
|
const result = await memoryReviewQueue({ accountId, sampleSize });
|
|
2463
2644
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|