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.mjs
CHANGED
|
@@ -4,6 +4,8 @@ import * as decoding from 'lib0/decoding';
|
|
|
4
4
|
import * as Y from 'yjs';
|
|
5
5
|
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
6
6
|
import diff from 'fast-diff';
|
|
7
|
+
import { tool } from 'ai';
|
|
8
|
+
import { z } from 'zod';
|
|
7
9
|
|
|
8
10
|
var __defProp = Object.defineProperty;
|
|
9
11
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -183,7 +185,6 @@ var init_CloudAdapter = __esm({
|
|
|
183
185
|
if (!config.baseUrl) {
|
|
184
186
|
throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
|
|
185
187
|
}
|
|
186
|
-
this.validateConfig(config);
|
|
187
188
|
this.setupNetworkDetection();
|
|
188
189
|
}
|
|
189
190
|
ws = null;
|
|
@@ -199,43 +200,6 @@ var init_CloudAdapter = __esm({
|
|
|
199
200
|
handleOnline = null;
|
|
200
201
|
handleOffline = null;
|
|
201
202
|
_synced = false;
|
|
202
|
-
/**
|
|
203
|
-
* Validate configuration and warn about common mistakes
|
|
204
|
-
*/
|
|
205
|
-
validateConfig(config) {
|
|
206
|
-
const baseUrl = config.baseUrl;
|
|
207
|
-
if (!baseUrl) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
console.log("\u2601\uFE0F MindCache Cloud Config:", {
|
|
211
|
-
baseUrl,
|
|
212
|
-
instanceId: config.instanceId,
|
|
213
|
-
hasTokenProvider: !!config.tokenProvider,
|
|
214
|
-
hasApiKey: !!config.apiKey
|
|
215
|
-
});
|
|
216
|
-
try {
|
|
217
|
-
const url = new URL(baseUrl);
|
|
218
|
-
if (url.hostname === "mindcache.dev") {
|
|
219
|
-
console.error(
|
|
220
|
-
'\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)."
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
if (url.protocol === "ws:" || url.protocol === "wss:") {
|
|
224
|
-
console.warn(
|
|
225
|
-
"\u26A0\uFE0F MindCache Cloud: baseUrl uses WebSocket protocol (" + url.protocol + "). Consider using http:// or https:// - CloudAdapter will handle the WebSocket upgrade automatically."
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
if (url.hostname === "localhost" && url.port !== "8787" && url.port !== "3000") {
|
|
229
|
-
console.warn(
|
|
230
|
-
"\u26A0\uFE0F MindCache Cloud: localhost URL detected with non-standard port " + url.port + ". Default MindCache dev server runs on port 8787."
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
const wsUrl = baseUrl.replace("https://", "wss://").replace("http://", "ws://");
|
|
234
|
-
console.log("\u2601\uFE0F WebSocket will connect to:", wsUrl + "/sync/" + config.instanceId);
|
|
235
|
-
} catch (e) {
|
|
236
|
-
console.error("\u26A0\uFE0F MindCache Cloud: Invalid baseUrl format:", baseUrl);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
203
|
/** Browser network status - instantly updated via navigator.onLine */
|
|
240
204
|
get isOnline() {
|
|
241
205
|
return this._isOnline;
|
|
@@ -488,6 +452,76 @@ var SystemTagHelpers = {
|
|
|
488
452
|
hasTemplateInjection: (attrs) => attrs.systemTags.includes("ApplyTemplate")
|
|
489
453
|
};
|
|
490
454
|
|
|
455
|
+
// src/core/SchemaParser.ts
|
|
456
|
+
var SchemaParser = class {
|
|
457
|
+
/**
|
|
458
|
+
* Parse a markdown schema string into a CustomTypeDefinition
|
|
459
|
+
* @param schema - Markdown schema string
|
|
460
|
+
* @returns Parsed type definition
|
|
461
|
+
* @throws Error if schema format is invalid
|
|
462
|
+
*/
|
|
463
|
+
static parse(schema) {
|
|
464
|
+
const lines = schema.trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
465
|
+
if (lines.length === 0) {
|
|
466
|
+
throw new Error("Schema cannot be empty");
|
|
467
|
+
}
|
|
468
|
+
const typeNameMatch = lines[0].match(/^#\s*(\w+)$/);
|
|
469
|
+
if (!typeNameMatch) {
|
|
470
|
+
throw new Error(`Invalid schema: first line must be "#TypeName", got "${lines[0]}"`);
|
|
471
|
+
}
|
|
472
|
+
const typeName = typeNameMatch[1];
|
|
473
|
+
const fields = [];
|
|
474
|
+
for (let i = 1; i < lines.length; i++) {
|
|
475
|
+
const line = lines[i];
|
|
476
|
+
const fieldMatch = line.match(/^\*\s*([^:]+):\s*(.+)$/);
|
|
477
|
+
if (fieldMatch) {
|
|
478
|
+
fields.push({
|
|
479
|
+
name: fieldMatch[1].trim(),
|
|
480
|
+
description: fieldMatch[2].trim()
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (fields.length === 0) {
|
|
485
|
+
throw new Error(`Schema "${typeName}" must have at least one field`);
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
name: typeName,
|
|
489
|
+
fields,
|
|
490
|
+
rawSchema: schema
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Generate a markdown representation of a type definition
|
|
495
|
+
* Useful for including in LLM prompts
|
|
496
|
+
*/
|
|
497
|
+
static toMarkdown(typeDef) {
|
|
498
|
+
const lines = [`#${typeDef.name}`];
|
|
499
|
+
for (const field of typeDef.fields) {
|
|
500
|
+
lines.push(`* ${field.name}: ${field.description}`);
|
|
501
|
+
}
|
|
502
|
+
return lines.join("\n");
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Generate a prompt-friendly description of the type
|
|
506
|
+
* More verbose than toMarkdown, better for LLM guidance
|
|
507
|
+
*/
|
|
508
|
+
static toPromptDescription(typeDef) {
|
|
509
|
+
const fieldDescs = typeDef.fields.map((f) => ` - ${f.name}: ${f.description}`).join("\n");
|
|
510
|
+
return `Type "${typeDef.name}" with fields:
|
|
511
|
+
${fieldDescs}`;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Generate an example value structure based on the type definition
|
|
515
|
+
*/
|
|
516
|
+
static generateExample(typeDef) {
|
|
517
|
+
const lines = [`#${typeDef.name.toLowerCase()}`];
|
|
518
|
+
for (const field of typeDef.fields) {
|
|
519
|
+
lines.push(`* ${field.name}: [${field.description}]`);
|
|
520
|
+
}
|
|
521
|
+
return lines.join("\n");
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
|
|
491
525
|
// src/core/MarkdownSerializer.ts
|
|
492
526
|
var MarkdownSerializer = class {
|
|
493
527
|
/**
|
|
@@ -834,18 +868,16 @@ var MarkdownSerializer = class {
|
|
|
834
868
|
return result;
|
|
835
869
|
}
|
|
836
870
|
};
|
|
837
|
-
|
|
838
|
-
// src/core/AIToolBuilder.ts
|
|
839
871
|
var AIToolBuilder = class _AIToolBuilder {
|
|
840
872
|
/**
|
|
841
|
-
|
|
842
|
-
|
|
873
|
+
* Sanitize key name for use in tool names
|
|
874
|
+
*/
|
|
843
875
|
static sanitizeKeyForTool(key) {
|
|
844
876
|
return key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
845
877
|
}
|
|
846
878
|
/**
|
|
847
|
-
|
|
848
|
-
|
|
879
|
+
* Find original key from sanitized tool name
|
|
880
|
+
*/
|
|
849
881
|
static findKeyFromSanitizedTool(mc, sanitizedKey) {
|
|
850
882
|
for (const key of mc.keys()) {
|
|
851
883
|
if (_AIToolBuilder.sanitizeKeyForTool(key) === sanitizedKey) {
|
|
@@ -855,15 +887,174 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
855
887
|
return void 0;
|
|
856
888
|
}
|
|
857
889
|
/**
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
890
|
+
* Generate framework-agnostic tools with raw JSON Schema.
|
|
891
|
+
* Works with: OpenAI SDK, Anthropic SDK, LangChain, etc.
|
|
892
|
+
*
|
|
893
|
+
* Tool format:
|
|
894
|
+
* {
|
|
895
|
+
* description: string,
|
|
896
|
+
* parameters: { type: 'object', properties: {...}, required: [...] },
|
|
897
|
+
* execute: async (args) => result
|
|
898
|
+
* }
|
|
899
|
+
*/
|
|
900
|
+
static createTools(mc) {
|
|
901
|
+
return _AIToolBuilder._buildTools(mc);
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Generate Vercel AI SDK v5 compatible tools using Zod schemas.
|
|
905
|
+
* Uses tool() helper with Zod for full AI SDK v5 compatibility.
|
|
906
|
+
*
|
|
907
|
+
* Use this with: generateText(), streamText() from 'ai' package
|
|
908
|
+
*/
|
|
865
909
|
static createVercelAITools(mc) {
|
|
866
910
|
const tools = {};
|
|
911
|
+
const registeredTypes = mc.getRegisteredTypes();
|
|
912
|
+
const typeDesc = registeredTypes.length > 0 ? `Optional type: ${registeredTypes.join(" | ")}` : "No types registered";
|
|
913
|
+
tools["create_key"] = tool({
|
|
914
|
+
description: `Create a new key in MindCache. ${registeredTypes.length > 0 ? `Available types: ${registeredTypes.join(", ")}` : ""}`,
|
|
915
|
+
inputSchema: z.object({
|
|
916
|
+
key: z.string().describe('The key name (e.g., "contact_john_doe")'),
|
|
917
|
+
value: z.string().describe("The value (JSON string for structured data)"),
|
|
918
|
+
type: z.string().optional().describe(typeDesc)
|
|
919
|
+
}),
|
|
920
|
+
execute: async ({ key, value, type }) => {
|
|
921
|
+
if (mc.has(key)) {
|
|
922
|
+
return { result: `Key "${key}" exists. Use write_${_AIToolBuilder.sanitizeKeyForTool(key)}`, error: true };
|
|
923
|
+
}
|
|
924
|
+
if (type && !mc.getTypeSchema(type)) {
|
|
925
|
+
return { result: `Type "${type}" not registered`, error: true };
|
|
926
|
+
}
|
|
927
|
+
mc.set_value(key, value, { systemTags: ["SystemPrompt", "LLMRead", "LLMWrite"] });
|
|
928
|
+
if (type) {
|
|
929
|
+
mc.setType(key, type);
|
|
930
|
+
}
|
|
931
|
+
return { result: `Created "${key}"${type ? ` (${type})` : ""}`, key, value };
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
for (const key of mc.keys()) {
|
|
935
|
+
if (key.startsWith("$") || !mc.keyMatchesContext(key)) {
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
const attrs = mc.get_attributes(key);
|
|
939
|
+
if (!attrs?.systemTags?.includes("LLMWrite")) {
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
const sanitized = _AIToolBuilder.sanitizeKeyForTool(key);
|
|
943
|
+
const customTypeName = mc.getKeyType(key);
|
|
944
|
+
const customType = customTypeName ? mc.getTypeSchema(customTypeName) : void 0;
|
|
945
|
+
let desc = `Write to "${key}"`;
|
|
946
|
+
if (customType) {
|
|
947
|
+
desc = `Write to "${key}" (${customTypeName}). ${SchemaParser.toPromptDescription(customType)}`;
|
|
948
|
+
}
|
|
949
|
+
tools[`write_${sanitized}`] = tool({
|
|
950
|
+
description: desc,
|
|
951
|
+
inputSchema: z.object({
|
|
952
|
+
value: z.string().describe(customType ? `JSON following ${customTypeName} schema` : "Value to write")
|
|
953
|
+
}),
|
|
954
|
+
execute: async ({ value }) => {
|
|
955
|
+
const success = mc.llm_set_key(key, value);
|
|
956
|
+
return success ? { result: `Wrote to ${key}`, key, value } : { result: `Failed to write to ${key}`, error: true };
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
if (attrs?.type === "document") {
|
|
960
|
+
tools[`append_${sanitized}`] = tool({
|
|
961
|
+
description: `Append to "${key}" document`,
|
|
962
|
+
inputSchema: z.object({ text: z.string().describe("Text to append") }),
|
|
963
|
+
execute: async ({ text }) => {
|
|
964
|
+
const yText = mc.get_document(key);
|
|
965
|
+
if (yText) {
|
|
966
|
+
yText.insert(yText.length, text);
|
|
967
|
+
return { result: "Appended", key };
|
|
968
|
+
}
|
|
969
|
+
return { result: "Not found", error: true };
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
tools[`insert_${sanitized}`] = tool({
|
|
973
|
+
description: `Insert text at position in "${key}" document`,
|
|
974
|
+
inputSchema: z.object({
|
|
975
|
+
index: z.number().describe("Position (0 = start)"),
|
|
976
|
+
text: z.string().describe("Text to insert")
|
|
977
|
+
}),
|
|
978
|
+
execute: async ({ index, text }) => {
|
|
979
|
+
mc.insert_text(key, index, text);
|
|
980
|
+
return { result: `Inserted at ${index}`, key };
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
tools[`edit_${sanitized}`] = tool({
|
|
984
|
+
description: `Find and replace in "${key}" document`,
|
|
985
|
+
inputSchema: z.object({
|
|
986
|
+
find: z.string().describe("Text to find"),
|
|
987
|
+
replace: z.string().describe("Replacement")
|
|
988
|
+
}),
|
|
989
|
+
execute: async ({ find, replace }) => {
|
|
990
|
+
const yText = mc.get_document(key);
|
|
991
|
+
if (yText) {
|
|
992
|
+
const text = yText.toString();
|
|
993
|
+
const idx = text.indexOf(find);
|
|
994
|
+
if (idx !== -1) {
|
|
995
|
+
yText.delete(idx, find.length);
|
|
996
|
+
yText.insert(idx, replace);
|
|
997
|
+
return { result: `Replaced "${find}"`, key };
|
|
998
|
+
}
|
|
999
|
+
return { result: `"${find}" not found`, error: true };
|
|
1000
|
+
}
|
|
1001
|
+
return { result: "Document not found", error: true };
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return tools;
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Internal: Build tools with raw JSON Schema (framework-agnostic).
|
|
1010
|
+
*/
|
|
1011
|
+
static _buildTools(mc) {
|
|
1012
|
+
const tools = {};
|
|
1013
|
+
const registeredTypes = mc.getRegisteredTypes();
|
|
1014
|
+
const typeInfo = registeredTypes.length > 0 ? `Available types: ${registeredTypes.join(", ")}` : "No custom types registered";
|
|
1015
|
+
tools["create_key"] = {
|
|
1016
|
+
description: `Create a new key in MindCache. ${typeInfo}. The new key will be readable and writable by the LLM.`,
|
|
1017
|
+
parameters: {
|
|
1018
|
+
type: "object",
|
|
1019
|
+
properties: {
|
|
1020
|
+
key: { type: "string", description: 'The key name to create (e.g., "contact_john_doe")' },
|
|
1021
|
+
value: { type: "string", description: "The value to store (use JSON string for structured data)" },
|
|
1022
|
+
type: {
|
|
1023
|
+
type: "string",
|
|
1024
|
+
description: registeredTypes.length > 0 ? `Optional: custom type name (${registeredTypes.join(" | ")})` : "Optional: custom type name (none registered)"
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
required: ["key", "value"]
|
|
1028
|
+
},
|
|
1029
|
+
execute: async ({ key, value, type }) => {
|
|
1030
|
+
if (mc.has(key)) {
|
|
1031
|
+
return {
|
|
1032
|
+
result: `Key "${key}" already exists. Use write_${_AIToolBuilder.sanitizeKeyForTool(key)} to update it.`,
|
|
1033
|
+
key,
|
|
1034
|
+
error: true
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
if (type && !mc.getTypeSchema(type)) {
|
|
1038
|
+
return {
|
|
1039
|
+
result: `Type "${type}" is not registered. Available types: ${registeredTypes.join(", ") || "none"}`,
|
|
1040
|
+
key,
|
|
1041
|
+
error: true
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
mc.set_value(key, value, {
|
|
1045
|
+
systemTags: ["SystemPrompt", "LLMRead", "LLMWrite"]
|
|
1046
|
+
});
|
|
1047
|
+
if (type) {
|
|
1048
|
+
mc.setType(key, type);
|
|
1049
|
+
}
|
|
1050
|
+
return {
|
|
1051
|
+
result: `Successfully created key "${key}"${type ? ` with type "${type}"` : ""}`,
|
|
1052
|
+
key,
|
|
1053
|
+
value,
|
|
1054
|
+
type
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
867
1058
|
for (const key of mc.keys()) {
|
|
868
1059
|
if (key.startsWith("$")) {
|
|
869
1060
|
continue;
|
|
@@ -878,12 +1069,28 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
878
1069
|
}
|
|
879
1070
|
const sanitizedKey = _AIToolBuilder.sanitizeKeyForTool(key);
|
|
880
1071
|
const isDocument = attributes?.type === "document";
|
|
1072
|
+
const customTypeName = mc.getKeyType(key);
|
|
1073
|
+
const customType = customTypeName ? mc.getTypeSchema(customTypeName) : void 0;
|
|
1074
|
+
let writeDescription;
|
|
1075
|
+
if (customType) {
|
|
1076
|
+
const schemaGuidance = SchemaParser.toPromptDescription(customType);
|
|
1077
|
+
const example = SchemaParser.generateExample(customType);
|
|
1078
|
+
writeDescription = `Write a value to "${key}" that must follow this schema:
|
|
1079
|
+
${schemaGuidance}
|
|
1080
|
+
|
|
1081
|
+
Example format:
|
|
1082
|
+
${example}`;
|
|
1083
|
+
} else if (isDocument) {
|
|
1084
|
+
writeDescription = `Rewrite the entire "${key}" document`;
|
|
1085
|
+
} else {
|
|
1086
|
+
writeDescription = `Write a value to the STM key: ${key}`;
|
|
1087
|
+
}
|
|
881
1088
|
tools[`write_${sanitizedKey}`] = {
|
|
882
|
-
description:
|
|
883
|
-
|
|
1089
|
+
description: writeDescription,
|
|
1090
|
+
parameters: {
|
|
884
1091
|
type: "object",
|
|
885
1092
|
properties: {
|
|
886
|
-
value: { type: "string", description: isDocument ? "New document content" : "The value to write" }
|
|
1093
|
+
value: { type: "string", description: customType ? `Value following ${customTypeName} schema` : isDocument ? "New document content" : "The value to write" }
|
|
887
1094
|
},
|
|
888
1095
|
required: ["value"]
|
|
889
1096
|
},
|
|
@@ -906,7 +1113,7 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
906
1113
|
if (isDocument) {
|
|
907
1114
|
tools[`append_${sanitizedKey}`] = {
|
|
908
1115
|
description: `Append text to the end of "${key}" document`,
|
|
909
|
-
|
|
1116
|
+
parameters: {
|
|
910
1117
|
type: "object",
|
|
911
1118
|
properties: {
|
|
912
1119
|
text: { type: "string", description: "Text to append" }
|
|
@@ -931,7 +1138,7 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
931
1138
|
};
|
|
932
1139
|
tools[`insert_${sanitizedKey}`] = {
|
|
933
1140
|
description: `Insert text at a position in "${key}" document`,
|
|
934
|
-
|
|
1141
|
+
parameters: {
|
|
935
1142
|
type: "object",
|
|
936
1143
|
properties: {
|
|
937
1144
|
index: { type: "number", description: "Position to insert at (0 = start)" },
|
|
@@ -954,7 +1161,7 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
954
1161
|
};
|
|
955
1162
|
tools[`edit_${sanitizedKey}`] = {
|
|
956
1163
|
description: `Find and replace text in "${key}" document`,
|
|
957
|
-
|
|
1164
|
+
parameters: {
|
|
958
1165
|
type: "object",
|
|
959
1166
|
properties: {
|
|
960
1167
|
find: { type: "string", description: "Text to find" },
|
|
@@ -991,11 +1198,16 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
991
1198
|
return tools;
|
|
992
1199
|
}
|
|
993
1200
|
/**
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1201
|
+
* Generate a system prompt containing all visible STM keys and their values.
|
|
1202
|
+
* Indicates which tools can be used to modify writable keys.
|
|
1203
|
+
*/
|
|
997
1204
|
static getSystemPrompt(mc) {
|
|
998
1205
|
const lines = [];
|
|
1206
|
+
const registeredTypes = mc.getRegisteredTypes();
|
|
1207
|
+
if (registeredTypes.length > 0) {
|
|
1208
|
+
lines.push(`[create_key tool available - registered types: ${registeredTypes.join(", ")}]`);
|
|
1209
|
+
lines.push("");
|
|
1210
|
+
}
|
|
999
1211
|
for (const key of mc.keys()) {
|
|
1000
1212
|
if (key.startsWith("$")) {
|
|
1001
1213
|
continue;
|
|
@@ -1013,8 +1225,18 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
1013
1225
|
const isWritable = attributes?.systemTags?.includes("LLMWrite");
|
|
1014
1226
|
const isDocument = attributes?.type === "document";
|
|
1015
1227
|
const sanitizedKey = _AIToolBuilder.sanitizeKeyForTool(key);
|
|
1228
|
+
const customTypeName = mc.getKeyType(key);
|
|
1229
|
+
const customType = customTypeName ? mc.getTypeSchema(customTypeName) : void 0;
|
|
1016
1230
|
if (isWritable) {
|
|
1017
|
-
if (
|
|
1231
|
+
if (customType) {
|
|
1232
|
+
const schemaInfo = SchemaParser.toMarkdown(customType);
|
|
1233
|
+
lines.push(
|
|
1234
|
+
`${key} (type: ${customTypeName}): ${displayValue}
|
|
1235
|
+
Schema:
|
|
1236
|
+
${schemaInfo}
|
|
1237
|
+
Tool: write_${sanitizedKey}`
|
|
1238
|
+
);
|
|
1239
|
+
} else if (isDocument) {
|
|
1018
1240
|
lines.push(
|
|
1019
1241
|
`${key}: ${displayValue}. Document tools: write_${sanitizedKey}, append_${sanitizedKey}, edit_${sanitizedKey}`
|
|
1020
1242
|
);
|
|
@@ -1025,15 +1247,19 @@ var AIToolBuilder = class _AIToolBuilder {
|
|
|
1025
1247
|
);
|
|
1026
1248
|
}
|
|
1027
1249
|
} else {
|
|
1028
|
-
|
|
1250
|
+
if (customTypeName) {
|
|
1251
|
+
lines.push(`${key} (type: ${customTypeName}): ${displayValue}`);
|
|
1252
|
+
} else {
|
|
1253
|
+
lines.push(`${key}: ${displayValue}`);
|
|
1254
|
+
}
|
|
1029
1255
|
}
|
|
1030
1256
|
}
|
|
1031
1257
|
return lines.join("\n");
|
|
1032
1258
|
}
|
|
1033
1259
|
/**
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1260
|
+
* Execute a tool call by name with the given value.
|
|
1261
|
+
* Returns the result or null if tool not found.
|
|
1262
|
+
*/
|
|
1037
1263
|
static executeToolCall(mc, toolName, value) {
|
|
1038
1264
|
const match = toolName.match(/^(write|append|insert|edit)_(.+)$/);
|
|
1039
1265
|
if (!match) {
|
|
@@ -1360,7 +1586,7 @@ var MindCache = class {
|
|
|
1360
1586
|
listeners = {};
|
|
1361
1587
|
globalListeners = [];
|
|
1362
1588
|
// Metadata
|
|
1363
|
-
version = "3.
|
|
1589
|
+
version = "3.6.0";
|
|
1364
1590
|
// Internal flag to prevent sync loops when receiving remote updates
|
|
1365
1591
|
// (Less critical with Yjs but kept for API compat)
|
|
1366
1592
|
normalizeSystemTags(tags) {
|
|
@@ -1397,6 +1623,8 @@ var MindCache = class {
|
|
|
1397
1623
|
_history = [];
|
|
1398
1624
|
_historyOptions = { maxEntries: 100, snapshotInterval: 10 };
|
|
1399
1625
|
_historyEnabled = false;
|
|
1626
|
+
// Custom type registry
|
|
1627
|
+
_typeRegistry = /* @__PURE__ */ new Map();
|
|
1400
1628
|
constructor(options) {
|
|
1401
1629
|
this.doc = options?.doc || new Y.Doc();
|
|
1402
1630
|
this.rootMap = this.doc.getMap("mindcache");
|
|
@@ -2353,6 +2581,71 @@ var MindCache = class {
|
|
|
2353
2581
|
systemGetKeysByTag(tag) {
|
|
2354
2582
|
return TagManager.systemGetKeysByTag(this, tag);
|
|
2355
2583
|
}
|
|
2584
|
+
// ============================================
|
|
2585
|
+
// Custom Type Methods
|
|
2586
|
+
// ============================================
|
|
2587
|
+
/**
|
|
2588
|
+
* Register a custom type with a markdown schema definition.
|
|
2589
|
+
*
|
|
2590
|
+
* Schema format:
|
|
2591
|
+
* ```
|
|
2592
|
+
* #TypeName
|
|
2593
|
+
* * fieldName: description of the field
|
|
2594
|
+
* * anotherField: description
|
|
2595
|
+
* ```
|
|
2596
|
+
*
|
|
2597
|
+
* @param name - Type name (e.g., 'Contact')
|
|
2598
|
+
* @param schema - Markdown schema definition
|
|
2599
|
+
* @throws Error if schema format is invalid
|
|
2600
|
+
*/
|
|
2601
|
+
registerType(name, schema) {
|
|
2602
|
+
const typeDef = SchemaParser.parse(schema);
|
|
2603
|
+
typeDef.name = name;
|
|
2604
|
+
this._typeRegistry.set(name, typeDef);
|
|
2605
|
+
}
|
|
2606
|
+
/**
|
|
2607
|
+
* Assign a custom type to a key.
|
|
2608
|
+
* The key must exist and the type must be registered.
|
|
2609
|
+
* Also sets the underlying type to 'json' since custom types are structured JSON data.
|
|
2610
|
+
*
|
|
2611
|
+
* @param key - Key to assign type to
|
|
2612
|
+
* @param typeName - Registered type name
|
|
2613
|
+
* @throws Error if key doesn't exist or type is not registered
|
|
2614
|
+
*/
|
|
2615
|
+
setType(key, typeName) {
|
|
2616
|
+
if (!this.rootMap.has(key)) {
|
|
2617
|
+
throw new Error(`Key "${key}" does not exist`);
|
|
2618
|
+
}
|
|
2619
|
+
if (!this._typeRegistry.has(typeName)) {
|
|
2620
|
+
throw new Error(`Type "${typeName}" is not registered. Use registerType() first.`);
|
|
2621
|
+
}
|
|
2622
|
+
this.set_attributes(key, { type: "json", customType: typeName });
|
|
2623
|
+
}
|
|
2624
|
+
/**
|
|
2625
|
+
* Get a registered type schema definition.
|
|
2626
|
+
*
|
|
2627
|
+
* @param typeName - Type name to look up
|
|
2628
|
+
* @returns The type definition or undefined if not registered
|
|
2629
|
+
*/
|
|
2630
|
+
getTypeSchema(typeName) {
|
|
2631
|
+
return this._typeRegistry.get(typeName);
|
|
2632
|
+
}
|
|
2633
|
+
/**
|
|
2634
|
+
* Get all registered type names.
|
|
2635
|
+
*/
|
|
2636
|
+
getRegisteredTypes() {
|
|
2637
|
+
return Array.from(this._typeRegistry.keys());
|
|
2638
|
+
}
|
|
2639
|
+
/**
|
|
2640
|
+
* Get the custom type assigned to a key.
|
|
2641
|
+
*
|
|
2642
|
+
* @param key - Key to check
|
|
2643
|
+
* @returns Type name or undefined if no custom type assigned
|
|
2644
|
+
*/
|
|
2645
|
+
getKeyType(key) {
|
|
2646
|
+
const attrs = this.get_attributes(key);
|
|
2647
|
+
return attrs?.customType;
|
|
2648
|
+
}
|
|
2356
2649
|
/**
|
|
2357
2650
|
* Helper to get sorted keys (by zIndex).
|
|
2358
2651
|
* Respects context filtering when set.
|
|
@@ -2614,9 +2907,28 @@ var MindCache = class {
|
|
|
2614
2907
|
findKeyFromSanitizedTool(sanitizedKey) {
|
|
2615
2908
|
return AIToolBuilder.findKeyFromSanitizedTool(this, sanitizedKey);
|
|
2616
2909
|
}
|
|
2910
|
+
/**
|
|
2911
|
+
* Generate framework-agnostic tools with raw JSON Schema.
|
|
2912
|
+
* Works with: OpenAI SDK, Anthropic SDK, LangChain, and other frameworks.
|
|
2913
|
+
*
|
|
2914
|
+
* Tool format:
|
|
2915
|
+
* {
|
|
2916
|
+
* description: string,
|
|
2917
|
+
* parameters: { type: 'object', properties: {...}, required: [...] },
|
|
2918
|
+
* execute: async (args) => result
|
|
2919
|
+
* }
|
|
2920
|
+
*
|
|
2921
|
+
* Security: All tools use llm_set_key internally which:
|
|
2922
|
+
* - Only modifies VALUES, never attributes/systemTags
|
|
2923
|
+
* - Prevents LLMs from escalating privileges
|
|
2924
|
+
*/
|
|
2925
|
+
create_tools() {
|
|
2926
|
+
return AIToolBuilder.createTools(this);
|
|
2927
|
+
}
|
|
2617
2928
|
/**
|
|
2618
2929
|
* Generate Vercel AI SDK compatible tools for writable keys.
|
|
2619
|
-
*
|
|
2930
|
+
* Wraps parameters with jsonSchema() for AI SDK v5 compatibility.
|
|
2931
|
+
* Use this with: generateText(), streamText() from 'ai' package.
|
|
2620
2932
|
*
|
|
2621
2933
|
* Security: All tools use llm_set_key internally which:
|
|
2622
2934
|
* - Only modifies VALUES, never attributes/systemTags
|