mindcache 3.5.3 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -4
- package/dist/{CloudAdapter-DK4YecbV.d.mts → CloudAdapter-PLGvGjoA.d.mts} +86 -7
- package/dist/{CloudAdapter-DK4YecbV.d.ts → CloudAdapter-PLGvGjoA.d.ts} +86 -7
- package/dist/cloud/index.d.mts +2 -2
- package/dist/cloud/index.d.ts +2 -2
- package/dist/cloud/index.js +379 -67
- package/dist/cloud/index.js.map +1 -1
- package/dist/cloud/index.mjs +379 -67
- package/dist/cloud/index.mjs.map +1 -1
- package/dist/index.d.mts +417 -19
- package/dist/index.d.ts +417 -19
- package/dist/index.js +1444 -105
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1433 -101
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +379 -67
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +379 -67
- package/dist/server.mjs.map +1 -1
- package/package.json +5 -9
package/dist/server.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MindCache } from './CloudAdapter-
|
|
2
|
-
export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState,
|
|
1
|
+
import { M as MindCache } from './CloudAdapter-PLGvGjoA.mjs';
|
|
2
|
+
export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState, p as DEFAULT_KEY_ATTRIBUTES, G as GlobalListener, H as HistoryEntry, l as HistoryOptions, K as KeyAttributes, k as KeyEntry, g as KeyType, L as Listener, m as MindCacheCloudOptions, n as MindCacheIndexedDBOptions, f as MindCacheOptions, j as STM, k as STMEntry, h as SystemTag, q as SystemTagHelpers } from './CloudAdapter-PLGvGjoA.mjs';
|
|
3
3
|
import 'yjs';
|
|
4
4
|
|
|
5
5
|
interface IndexedDBConfig {
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MindCache } from './CloudAdapter-
|
|
2
|
-
export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState,
|
|
1
|
+
import { M as MindCache } from './CloudAdapter-PLGvGjoA.js';
|
|
2
|
+
export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState, p as DEFAULT_KEY_ATTRIBUTES, G as GlobalListener, H as HistoryEntry, l as HistoryOptions, K as KeyAttributes, k as KeyEntry, g as KeyType, L as Listener, m as MindCacheCloudOptions, n as MindCacheIndexedDBOptions, f as MindCacheOptions, j as STM, k as STMEntry, h as SystemTag, q as SystemTagHelpers } from './CloudAdapter-PLGvGjoA.js';
|
|
3
3
|
import 'yjs';
|
|
4
4
|
|
|
5
5
|
interface IndexedDBConfig {
|
package/dist/server.js
CHANGED
|
@@ -6,6 +6,8 @@ var decoding = require('lib0/decoding');
|
|
|
6
6
|
var Y = require('yjs');
|
|
7
7
|
var yIndexeddb = require('y-indexeddb');
|
|
8
8
|
var diff = require('fast-diff');
|
|
9
|
+
var ai = require('ai');
|
|
10
|
+
var zod = require('zod');
|
|
9
11
|
|
|
10
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
13
|
|
|
@@ -211,7 +213,6 @@ var init_CloudAdapter = __esm({
|
|
|
211
213
|
if (!config.baseUrl) {
|
|
212
214
|
throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
|
|
213
215
|
}
|
|
214
|
-
this.validateConfig(config);
|
|
215
216
|
this.setupNetworkDetection();
|
|
216
217
|
}
|
|
217
218
|
ws = null;
|
|
@@ -227,43 +228,6 @@ var init_CloudAdapter = __esm({
|
|
|
227
228
|
handleOnline = null;
|
|
228
229
|
handleOffline = null;
|
|
229
230
|
_synced = false;
|
|
230
|
-
/**
|
|
231
|
-
* Validate configuration and warn about common mistakes
|
|
232
|
-
*/
|
|
233
|
-
validateConfig(config) {
|
|
234
|
-
const baseUrl = config.baseUrl;
|
|
235
|
-
if (!baseUrl) {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
console.log("\u2601\uFE0F MindCache Cloud Config:", {
|
|
239
|
-
baseUrl,
|
|
240
|
-
instanceId: config.instanceId,
|
|
241
|
-
hasTokenProvider: !!config.tokenProvider,
|
|
242
|
-
hasApiKey: !!config.apiKey
|
|
243
|
-
});
|
|
244
|
-
try {
|
|
245
|
-
const url = new URL(baseUrl);
|
|
246
|
-
if (url.hostname === "mindcache.dev") {
|
|
247
|
-
console.error(
|
|
248
|
-
'\u26A0\uFE0F MindCache Cloud WARNING: baseUrl is set to "mindcache.dev" but the API is at "api.mindcache.dev".\n Current: ' + baseUrl + "\n Expected: https://api.mindcache.dev\n This will cause WebSocket connection failures (404 errors)."
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
if (url.protocol === "ws:" || url.protocol === "wss:") {
|
|
252
|
-
console.warn(
|
|
253
|
-
"\u26A0\uFE0F MindCache Cloud: baseUrl uses WebSocket protocol (" + url.protocol + "). Consider using http:// or https:// - CloudAdapter will handle the WebSocket upgrade automatically."
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
if (url.hostname === "localhost" && url.port !== "8787" && url.port !== "3000") {
|
|
257
|
-
console.warn(
|
|
258
|
-
"\u26A0\uFE0F MindCache Cloud: localhost URL detected with non-standard port " + url.port + ". Default MindCache dev server runs on port 8787."
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
const wsUrl = baseUrl.replace("https://", "wss://").replace("http://", "ws://");
|
|
262
|
-
console.log("\u2601\uFE0F WebSocket will connect to:", wsUrl + "/sync/" + config.instanceId);
|
|
263
|
-
} catch (e) {
|
|
264
|
-
console.error("\u26A0\uFE0F MindCache Cloud: Invalid baseUrl format:", baseUrl);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
231
|
/** Browser network status - instantly updated via navigator.onLine */
|
|
268
232
|
get isOnline() {
|
|
269
233
|
return this._isOnline;
|
|
@@ -516,6 +480,76 @@ var SystemTagHelpers = {
|
|
|
516
480
|
hasTemplateInjection: (attrs) => attrs.systemTags.includes("ApplyTemplate")
|
|
517
481
|
};
|
|
518
482
|
|
|
483
|
+
// src/core/SchemaParser.ts
|
|
484
|
+
var SchemaParser = class {
|
|
485
|
+
/**
|
|
486
|
+
* Parse a markdown schema string into a CustomTypeDefinition
|
|
487
|
+
* @param schema - Markdown schema string
|
|
488
|
+
* @returns Parsed type definition
|
|
489
|
+
* @throws Error if schema format is invalid
|
|
490
|
+
*/
|
|
491
|
+
static parse(schema) {
|
|
492
|
+
const lines = schema.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
493
|
+
if (lines.length === 0) {
|
|
494
|
+
throw new Error("Schema cannot be empty");
|
|
495
|
+
}
|
|
496
|
+
const typeNameMatch = lines[0].match(/^#\s*(\w+)$/);
|
|
497
|
+
if (!typeNameMatch) {
|
|
498
|
+
throw new Error(`Invalid schema: first line must be "#TypeName", got "${lines[0]}"`);
|
|
499
|
+
}
|
|
500
|
+
const typeName = typeNameMatch[1];
|
|
501
|
+
const fields = [];
|
|
502
|
+
for (let i = 1; i < lines.length; i++) {
|
|
503
|
+
const line = lines[i];
|
|
504
|
+
const fieldMatch = line.match(/^\*\s*([^:]+):\s*(.+)$/);
|
|
505
|
+
if (fieldMatch) {
|
|
506
|
+
fields.push({
|
|
507
|
+
name: fieldMatch[1].trim(),
|
|
508
|
+
description: fieldMatch[2].trim()
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (fields.length === 0) {
|
|
513
|
+
throw new Error(`Schema "${typeName}" must have at least one field`);
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
name: typeName,
|
|
517
|
+
fields,
|
|
518
|
+
rawSchema: schema
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Generate a markdown representation of a type definition
|
|
523
|
+
* Useful for including in LLM prompts
|
|
524
|
+
*/
|
|
525
|
+
static toMarkdown(typeDef) {
|
|
526
|
+
const lines = [`#${typeDef.name}`];
|
|
527
|
+
for (const field of typeDef.fields) {
|
|
528
|
+
lines.push(`* ${field.name}: ${field.description}`);
|
|
529
|
+
}
|
|
530
|
+
return lines.join("\n");
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Generate a prompt-friendly description of the type
|
|
534
|
+
* More verbose than toMarkdown, better for LLM guidance
|
|
535
|
+
*/
|
|
536
|
+
static toPromptDescription(typeDef) {
|
|
537
|
+
const fieldDescs = typeDef.fields.map((f) => ` - ${f.name}: ${f.description}`).join("\n");
|
|
538
|
+
return `Type "${typeDef.name}" with fields:
|
|
539
|
+
${fieldDescs}`;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Generate an example value structure based on the type definition
|
|
543
|
+
*/
|
|
544
|
+
static generateExample(typeDef) {
|
|
545
|
+
const lines = [`#${typeDef.name.toLowerCase()}`];
|
|
546
|
+
for (const field of typeDef.fields) {
|
|
547
|
+
lines.push(`* ${field.name}: [${field.description}]`);
|
|
548
|
+
}
|
|
549
|
+
return lines.join("\n");
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
519
553
|
// src/core/MarkdownSerializer.ts
|
|
520
554
|
var MarkdownSerializer = class {
|
|
521
555
|
/**
|
|
@@ -862,18 +896,16 @@ var MarkdownSerializer = class {
|
|
|
862
896
|
return result;
|
|
863
897
|
}
|
|
864
898
|
};
|
|
865
|
-
|
|
866
|
-
// src/core/AIToolBuilder.ts
|
|
867
899
|
var AIToolBuilder = class _AIToolBuilder {
|
|
868
900
|
/**
|
|
869
|
-
|
|
870
|
-
|
|
901
|
+
* Sanitize key name for use in tool names
|
|
902
|
+
*/
|
|
871
903
|
static sanitizeKeyForTool(key) {
|
|
872
904
|
return key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
873
905
|
}
|
|
874
906
|
/**
|
|
875
|
-
|
|
876
|
-
|
|
907
|
+
* Find original key from sanitized tool name
|
|
908
|
+
*/
|
|
877
909
|
static findKeyFromSanitizedTool(mc, sanitizedKey) {
|
|
878
910
|
for (const key of mc.keys()) {
|
|
879
911
|
if (_AIToolBuilder.sanitizeKeyForTool(key) === sanitizedKey) {
|
|
@@ -883,15 +915,174 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
883
915
|
return void 0;
|
|
884
916
|
}
|
|
885
917
|
/**
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
918
|
+
* Generate framework-agnostic tools with raw JSON Schema.
|
|
919
|
+
* Works with: OpenAI SDK, Anthropic SDK, LangChain, etc.
|
|
920
|
+
*
|
|
921
|
+
* Tool format:
|
|
922
|
+
* {
|
|
923
|
+
* description: string,
|
|
924
|
+
* parameters: { type: 'object', properties: {...}, required: [...] },
|
|
925
|
+
* execute: async (args) => result
|
|
926
|
+
* }
|
|
927
|
+
*/
|
|
928
|
+
static createTools(mc) {
|
|
929
|
+
return _AIToolBuilder._buildTools(mc);
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Generate Vercel AI SDK v5 compatible tools using Zod schemas.
|
|
933
|
+
* Uses tool() helper with Zod for full AI SDK v5 compatibility.
|
|
934
|
+
*
|
|
935
|
+
* Use this with: generateText(), streamText() from 'ai' package
|
|
936
|
+
*/
|
|
893
937
|
static createVercelAITools(mc) {
|
|
894
938
|
const tools = {};
|
|
939
|
+
const registeredTypes = mc.getRegisteredTypes();
|
|
940
|
+
const typeDesc = registeredTypes.length > 0 ? `Optional type: ${registeredTypes.join(" | ")}` : "No types registered";
|
|
941
|
+
tools["create_key"] = ai.tool({
|
|
942
|
+
description: `Create a new key in MindCache. ${registeredTypes.length > 0 ? `Available types: ${registeredTypes.join(", ")}` : ""}`,
|
|
943
|
+
inputSchema: zod.z.object({
|
|
944
|
+
key: zod.z.string().describe('The key name (e.g., "contact_john_doe")'),
|
|
945
|
+
value: zod.z.string().describe("The value (JSON string for structured data)"),
|
|
946
|
+
type: zod.z.string().optional().describe(typeDesc)
|
|
947
|
+
}),
|
|
948
|
+
execute: async ({ key, value, type }) => {
|
|
949
|
+
if (mc.has(key)) {
|
|
950
|
+
return { result: `Key "${key}" exists. Use write_${_AIToolBuilder.sanitizeKeyForTool(key)}`, error: true };
|
|
951
|
+
}
|
|
952
|
+
if (type && !mc.getTypeSchema(type)) {
|
|
953
|
+
return { result: `Type "${type}" not registered`, error: true };
|
|
954
|
+
}
|
|
955
|
+
mc.set_value(key, value, { systemTags: ["SystemPrompt", "LLMRead", "LLMWrite"] });
|
|
956
|
+
if (type) {
|
|
957
|
+
mc.setType(key, type);
|
|
958
|
+
}
|
|
959
|
+
return { result: `Created "${key}"${type ? ` (${type})` : ""}`, key, value };
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
for (const key of mc.keys()) {
|
|
963
|
+
if (key.startsWith("$") || !mc.keyMatchesContext(key)) {
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
const attrs = mc.get_attributes(key);
|
|
967
|
+
if (!attrs?.systemTags?.includes("LLMWrite")) {
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
const sanitized = _AIToolBuilder.sanitizeKeyForTool(key);
|
|
971
|
+
const customTypeName = mc.getKeyType(key);
|
|
972
|
+
const customType = customTypeName ? mc.getTypeSchema(customTypeName) : void 0;
|
|
973
|
+
let desc = `Write to "${key}"`;
|
|
974
|
+
if (customType) {
|
|
975
|
+
desc = `Write to "${key}" (${customTypeName}). ${SchemaParser.toPromptDescription(customType)}`;
|
|
976
|
+
}
|
|
977
|
+
tools[`write_${sanitized}`] = ai.tool({
|
|
978
|
+
description: desc,
|
|
979
|
+
inputSchema: zod.z.object({
|
|
980
|
+
value: zod.z.string().describe(customType ? `JSON following ${customTypeName} schema` : "Value to write")
|
|
981
|
+
}),
|
|
982
|
+
execute: async ({ value }) => {
|
|
983
|
+
const success = mc.llm_set_key(key, value);
|
|
984
|
+
return success ? { result: `Wrote to ${key}`, key, value } : { result: `Failed to write to ${key}`, error: true };
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
if (attrs?.type === "document") {
|
|
988
|
+
tools[`append_${sanitized}`] = ai.tool({
|
|
989
|
+
description: `Append to "${key}" document`,
|
|
990
|
+
inputSchema: zod.z.object({ text: zod.z.string().describe("Text to append") }),
|
|
991
|
+
execute: async ({ text }) => {
|
|
992
|
+
const yText = mc.get_document(key);
|
|
993
|
+
if (yText) {
|
|
994
|
+
yText.insert(yText.length, text);
|
|
995
|
+
return { result: "Appended", key };
|
|
996
|
+
}
|
|
997
|
+
return { result: "Not found", error: true };
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
tools[`insert_${sanitized}`] = ai.tool({
|
|
1001
|
+
description: `Insert text at position in "${key}" document`,
|
|
1002
|
+
inputSchema: zod.z.object({
|
|
1003
|
+
index: zod.z.number().describe("Position (0 = start)"),
|
|
1004
|
+
text: zod.z.string().describe("Text to insert")
|
|
1005
|
+
}),
|
|
1006
|
+
execute: async ({ index, text }) => {
|
|
1007
|
+
mc.insert_text(key, index, text);
|
|
1008
|
+
return { result: `Inserted at ${index}`, key };
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
tools[`edit_${sanitized}`] = ai.tool({
|
|
1012
|
+
description: `Find and replace in "${key}" document`,
|
|
1013
|
+
inputSchema: zod.z.object({
|
|
1014
|
+
find: zod.z.string().describe("Text to find"),
|
|
1015
|
+
replace: zod.z.string().describe("Replacement")
|
|
1016
|
+
}),
|
|
1017
|
+
execute: async ({ find, replace }) => {
|
|
1018
|
+
const yText = mc.get_document(key);
|
|
1019
|
+
if (yText) {
|
|
1020
|
+
const text = yText.toString();
|
|
1021
|
+
const idx = text.indexOf(find);
|
|
1022
|
+
if (idx !== -1) {
|
|
1023
|
+
yText.delete(idx, find.length);
|
|
1024
|
+
yText.insert(idx, replace);
|
|
1025
|
+
return { result: `Replaced "${find}"`, key };
|
|
1026
|
+
}
|
|
1027
|
+
return { result: `"${find}" not found`, error: true };
|
|
1028
|
+
}
|
|
1029
|
+
return { result: "Document not found", error: true };
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return tools;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Internal: Build tools with raw JSON Schema (framework-agnostic).
|
|
1038
|
+
*/
|
|
1039
|
+
static _buildTools(mc) {
|
|
1040
|
+
const tools = {};
|
|
1041
|
+
const registeredTypes = mc.getRegisteredTypes();
|
|
1042
|
+
const typeInfo = registeredTypes.length > 0 ? `Available types: ${registeredTypes.join(", ")}` : "No custom types registered";
|
|
1043
|
+
tools["create_key"] = {
|
|
1044
|
+
description: `Create a new key in MindCache. ${typeInfo}. The new key will be readable and writable by the LLM.`,
|
|
1045
|
+
parameters: {
|
|
1046
|
+
type: "object",
|
|
1047
|
+
properties: {
|
|
1048
|
+
key: { type: "string", description: 'The key name to create (e.g., "contact_john_doe")' },
|
|
1049
|
+
value: { type: "string", description: "The value to store (use JSON string for structured data)" },
|
|
1050
|
+
type: {
|
|
1051
|
+
type: "string",
|
|
1052
|
+
description: registeredTypes.length > 0 ? `Optional: custom type name (${registeredTypes.join(" | ")})` : "Optional: custom type name (none registered)"
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
required: ["key", "value"]
|
|
1056
|
+
},
|
|
1057
|
+
execute: async ({ key, value, type }) => {
|
|
1058
|
+
if (mc.has(key)) {
|
|
1059
|
+
return {
|
|
1060
|
+
result: `Key "${key}" already exists. Use write_${_AIToolBuilder.sanitizeKeyForTool(key)} to update it.`,
|
|
1061
|
+
key,
|
|
1062
|
+
error: true
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
if (type && !mc.getTypeSchema(type)) {
|
|
1066
|
+
return {
|
|
1067
|
+
result: `Type "${type}" is not registered. Available types: ${registeredTypes.join(", ") || "none"}`,
|
|
1068
|
+
key,
|
|
1069
|
+
error: true
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
mc.set_value(key, value, {
|
|
1073
|
+
systemTags: ["SystemPrompt", "LLMRead", "LLMWrite"]
|
|
1074
|
+
});
|
|
1075
|
+
if (type) {
|
|
1076
|
+
mc.setType(key, type);
|
|
1077
|
+
}
|
|
1078
|
+
return {
|
|
1079
|
+
result: `Successfully created key "${key}"${type ? ` with type "${type}"` : ""}`,
|
|
1080
|
+
key,
|
|
1081
|
+
value,
|
|
1082
|
+
type
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
895
1086
|
for (const key of mc.keys()) {
|
|
896
1087
|
if (key.startsWith("$")) {
|
|
897
1088
|
continue;
|
|
@@ -906,12 +1097,28 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
906
1097
|
}
|
|
907
1098
|
const sanitizedKey = _AIToolBuilder.sanitizeKeyForTool(key);
|
|
908
1099
|
const isDocument = attributes?.type === "document";
|
|
1100
|
+
const customTypeName = mc.getKeyType(key);
|
|
1101
|
+
const customType = customTypeName ? mc.getTypeSchema(customTypeName) : void 0;
|
|
1102
|
+
let writeDescription;
|
|
1103
|
+
if (customType) {
|
|
1104
|
+
const schemaGuidance = SchemaParser.toPromptDescription(customType);
|
|
1105
|
+
const example = SchemaParser.generateExample(customType);
|
|
1106
|
+
writeDescription = `Write a value to "${key}" that must follow this schema:
|
|
1107
|
+
${schemaGuidance}
|
|
1108
|
+
|
|
1109
|
+
Example format:
|
|
1110
|
+
${example}`;
|
|
1111
|
+
} else if (isDocument) {
|
|
1112
|
+
writeDescription = `Rewrite the entire "${key}" document`;
|
|
1113
|
+
} else {
|
|
1114
|
+
writeDescription = `Write a value to the STM key: ${key}`;
|
|
1115
|
+
}
|
|
909
1116
|
tools[`write_${sanitizedKey}`] = {
|
|
910
|
-
description:
|
|
911
|
-
|
|
1117
|
+
description: writeDescription,
|
|
1118
|
+
parameters: {
|
|
912
1119
|
type: "object",
|
|
913
1120
|
properties: {
|
|
914
|
-
value: { type: "string", description: isDocument ? "New document content" : "The value to write" }
|
|
1121
|
+
value: { type: "string", description: customType ? `Value following ${customTypeName} schema` : isDocument ? "New document content" : "The value to write" }
|
|
915
1122
|
},
|
|
916
1123
|
required: ["value"]
|
|
917
1124
|
},
|
|
@@ -934,7 +1141,7 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
934
1141
|
if (isDocument) {
|
|
935
1142
|
tools[`append_${sanitizedKey}`] = {
|
|
936
1143
|
description: `Append text to the end of "${key}" document`,
|
|
937
|
-
|
|
1144
|
+
parameters: {
|
|
938
1145
|
type: "object",
|
|
939
1146
|
properties: {
|
|
940
1147
|
text: { type: "string", description: "Text to append" }
|
|
@@ -959,7 +1166,7 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
959
1166
|
};
|
|
960
1167
|
tools[`insert_${sanitizedKey}`] = {
|
|
961
1168
|
description: `Insert text at a position in "${key}" document`,
|
|
962
|
-
|
|
1169
|
+
parameters: {
|
|
963
1170
|
type: "object",
|
|
964
1171
|
properties: {
|
|
965
1172
|
index: { type: "number", description: "Position to insert at (0 = start)" },
|
|
@@ -982,7 +1189,7 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
982
1189
|
};
|
|
983
1190
|
tools[`edit_${sanitizedKey}`] = {
|
|
984
1191
|
description: `Find and replace text in "${key}" document`,
|
|
985
|
-
|
|
1192
|
+
parameters: {
|
|
986
1193
|
type: "object",
|
|
987
1194
|
properties: {
|
|
988
1195
|
find: { type: "string", description: "Text to find" },
|
|
@@ -1019,11 +1226,16 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
1019
1226
|
return tools;
|
|
1020
1227
|
}
|
|
1021
1228
|
/**
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1229
|
+
* Generate a system prompt containing all visible STM keys and their values.
|
|
1230
|
+
* Indicates which tools can be used to modify writable keys.
|
|
1231
|
+
*/
|
|
1025
1232
|
static getSystemPrompt(mc) {
|
|
1026
1233
|
const lines = [];
|
|
1234
|
+
const registeredTypes = mc.getRegisteredTypes();
|
|
1235
|
+
if (registeredTypes.length > 0) {
|
|
1236
|
+
lines.push(`[create_key tool available - registered types: ${registeredTypes.join(", ")}]`);
|
|
1237
|
+
lines.push("");
|
|
1238
|
+
}
|
|
1027
1239
|
for (const key of mc.keys()) {
|
|
1028
1240
|
if (key.startsWith("$")) {
|
|
1029
1241
|
continue;
|
|
@@ -1041,8 +1253,18 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
1041
1253
|
const isWritable = attributes?.systemTags?.includes("LLMWrite");
|
|
1042
1254
|
const isDocument = attributes?.type === "document";
|
|
1043
1255
|
const sanitizedKey = _AIToolBuilder.sanitizeKeyForTool(key);
|
|
1256
|
+
const customTypeName = mc.getKeyType(key);
|
|
1257
|
+
const customType = customTypeName ? mc.getTypeSchema(customTypeName) : void 0;
|
|
1044
1258
|
if (isWritable) {
|
|
1045
|
-
if (
|
|
1259
|
+
if (customType) {
|
|
1260
|
+
const schemaInfo = SchemaParser.toMarkdown(customType);
|
|
1261
|
+
lines.push(
|
|
1262
|
+
`${key} (type: ${customTypeName}): ${displayValue}
|
|
1263
|
+
Schema:
|
|
1264
|
+
${schemaInfo}
|
|
1265
|
+
Tool: write_${sanitizedKey}`
|
|
1266
|
+
);
|
|
1267
|
+
} else if (isDocument) {
|
|
1046
1268
|
lines.push(
|
|
1047
1269
|
`${key}: ${displayValue}. Document tools: write_${sanitizedKey}, append_${sanitizedKey}, edit_${sanitizedKey}`
|
|
1048
1270
|
);
|
|
@@ -1053,15 +1275,19 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
1053
1275
|
);
|
|
1054
1276
|
}
|
|
1055
1277
|
} else {
|
|
1056
|
-
|
|
1278
|
+
if (customTypeName) {
|
|
1279
|
+
lines.push(`${key} (type: ${customTypeName}): ${displayValue}`);
|
|
1280
|
+
} else {
|
|
1281
|
+
lines.push(`${key}: ${displayValue}`);
|
|
1282
|
+
}
|
|
1057
1283
|
}
|
|
1058
1284
|
}
|
|
1059
1285
|
return lines.join("\n");
|
|
1060
1286
|
}
|
|
1061
1287
|
/**
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1288
|
+
* Execute a tool call by name with the given value.
|
|
1289
|
+
* Returns the result or null if tool not found.
|
|
1290
|
+
*/
|
|
1065
1291
|
static executeToolCall(mc, toolName, value) {
|
|
1066
1292
|
const match = toolName.match(/^(write|append|insert|edit)_(.+)$/);
|
|
1067
1293
|
if (!match) {
|
|
@@ -1388,7 +1614,7 @@ var MindCache = class {
|
|
|
1388
1614
|
listeners = {};
|
|
1389
1615
|
globalListeners = [];
|
|
1390
1616
|
// Metadata
|
|
1391
|
-
version = "3.
|
|
1617
|
+
version = "3.6.0";
|
|
1392
1618
|
// Internal flag to prevent sync loops when receiving remote updates
|
|
1393
1619
|
// (Less critical with Yjs but kept for API compat)
|
|
1394
1620
|
normalizeSystemTags(tags) {
|
|
@@ -1425,6 +1651,8 @@ var MindCache = class {
|
|
|
1425
1651
|
_history = [];
|
|
1426
1652
|
_historyOptions = { maxEntries: 100, snapshotInterval: 10 };
|
|
1427
1653
|
_historyEnabled = false;
|
|
1654
|
+
// Custom type registry
|
|
1655
|
+
_typeRegistry = /* @__PURE__ */ new Map();
|
|
1428
1656
|
constructor(options) {
|
|
1429
1657
|
this.doc = options?.doc || new Y__namespace.Doc();
|
|
1430
1658
|
this.rootMap = this.doc.getMap("mindcache");
|
|
@@ -2381,6 +2609,71 @@ var MindCache = class {
|
|
|
2381
2609
|
systemGetKeysByTag(tag) {
|
|
2382
2610
|
return TagManager.systemGetKeysByTag(this, tag);
|
|
2383
2611
|
}
|
|
2612
|
+
// ============================================
|
|
2613
|
+
// Custom Type Methods
|
|
2614
|
+
// ============================================
|
|
2615
|
+
/**
|
|
2616
|
+
* Register a custom type with a markdown schema definition.
|
|
2617
|
+
*
|
|
2618
|
+
* Schema format:
|
|
2619
|
+
* ```
|
|
2620
|
+
* #TypeName
|
|
2621
|
+
* * fieldName: description of the field
|
|
2622
|
+
* * anotherField: description
|
|
2623
|
+
* ```
|
|
2624
|
+
*
|
|
2625
|
+
* @param name - Type name (e.g., 'Contact')
|
|
2626
|
+
* @param schema - Markdown schema definition
|
|
2627
|
+
* @throws Error if schema format is invalid
|
|
2628
|
+
*/
|
|
2629
|
+
registerType(name, schema) {
|
|
2630
|
+
const typeDef = SchemaParser.parse(schema);
|
|
2631
|
+
typeDef.name = name;
|
|
2632
|
+
this._typeRegistry.set(name, typeDef);
|
|
2633
|
+
}
|
|
2634
|
+
/**
|
|
2635
|
+
* Assign a custom type to a key.
|
|
2636
|
+
* The key must exist and the type must be registered.
|
|
2637
|
+
* Also sets the underlying type to 'json' since custom types are structured JSON data.
|
|
2638
|
+
*
|
|
2639
|
+
* @param key - Key to assign type to
|
|
2640
|
+
* @param typeName - Registered type name
|
|
2641
|
+
* @throws Error if key doesn't exist or type is not registered
|
|
2642
|
+
*/
|
|
2643
|
+
setType(key, typeName) {
|
|
2644
|
+
if (!this.rootMap.has(key)) {
|
|
2645
|
+
throw new Error(`Key "${key}" does not exist`);
|
|
2646
|
+
}
|
|
2647
|
+
if (!this._typeRegistry.has(typeName)) {
|
|
2648
|
+
throw new Error(`Type "${typeName}" is not registered. Use registerType() first.`);
|
|
2649
|
+
}
|
|
2650
|
+
this.set_attributes(key, { type: "json", customType: typeName });
|
|
2651
|
+
}
|
|
2652
|
+
/**
|
|
2653
|
+
* Get a registered type schema definition.
|
|
2654
|
+
*
|
|
2655
|
+
* @param typeName - Type name to look up
|
|
2656
|
+
* @returns The type definition or undefined if not registered
|
|
2657
|
+
*/
|
|
2658
|
+
getTypeSchema(typeName) {
|
|
2659
|
+
return this._typeRegistry.get(typeName);
|
|
2660
|
+
}
|
|
2661
|
+
/**
|
|
2662
|
+
* Get all registered type names.
|
|
2663
|
+
*/
|
|
2664
|
+
getRegisteredTypes() {
|
|
2665
|
+
return Array.from(this._typeRegistry.keys());
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* Get the custom type assigned to a key.
|
|
2669
|
+
*
|
|
2670
|
+
* @param key - Key to check
|
|
2671
|
+
* @returns Type name or undefined if no custom type assigned
|
|
2672
|
+
*/
|
|
2673
|
+
getKeyType(key) {
|
|
2674
|
+
const attrs = this.get_attributes(key);
|
|
2675
|
+
return attrs?.customType;
|
|
2676
|
+
}
|
|
2384
2677
|
/**
|
|
2385
2678
|
* Helper to get sorted keys (by zIndex).
|
|
2386
2679
|
* Respects context filtering when set.
|
|
@@ -2642,9 +2935,28 @@ var MindCache = class {
|
|
|
2642
2935
|
findKeyFromSanitizedTool(sanitizedKey) {
|
|
2643
2936
|
return AIToolBuilder.findKeyFromSanitizedTool(this, sanitizedKey);
|
|
2644
2937
|
}
|
|
2938
|
+
/**
|
|
2939
|
+
* Generate framework-agnostic tools with raw JSON Schema.
|
|
2940
|
+
* Works with: OpenAI SDK, Anthropic SDK, LangChain, and other frameworks.
|
|
2941
|
+
*
|
|
2942
|
+
* Tool format:
|
|
2943
|
+
* {
|
|
2944
|
+
* description: string,
|
|
2945
|
+
* parameters: { type: 'object', properties: {...}, required: [...] },
|
|
2946
|
+
* execute: async (args) => result
|
|
2947
|
+
* }
|
|
2948
|
+
*
|
|
2949
|
+
* Security: All tools use llm_set_key internally which:
|
|
2950
|
+
* - Only modifies VALUES, never attributes/systemTags
|
|
2951
|
+
* - Prevents LLMs from escalating privileges
|
|
2952
|
+
*/
|
|
2953
|
+
create_tools() {
|
|
2954
|
+
return AIToolBuilder.createTools(this);
|
|
2955
|
+
}
|
|
2645
2956
|
/**
|
|
2646
2957
|
* Generate Vercel AI SDK compatible tools for writable keys.
|
|
2647
|
-
*
|
|
2958
|
+
* Wraps parameters with jsonSchema() for AI SDK v5 compatibility.
|
|
2959
|
+
* Use this with: generateText(), streamText() from 'ai' package.
|
|
2648
2960
|
*
|
|
2649
2961
|
* Security: All tools use llm_set_key internally which:
|
|
2650
2962
|
* - Only modifies VALUES, never attributes/systemTags
|