@goonnguyen/human-mcp 2.6.0 → 2.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/dist/index.js +588 -323
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -132386,10 +132386,10 @@ var require_view = __commonJS((exports, module) => {
|
|
|
132386
132386
|
var debug = require_src3()("express:view");
|
|
132387
132387
|
var path5 = __require("node:path");
|
|
132388
132388
|
var fs5 = __require("node:fs");
|
|
132389
|
-
var
|
|
132389
|
+
var dirname2 = path5.dirname;
|
|
132390
132390
|
var basename = path5.basename;
|
|
132391
132391
|
var extname2 = path5.extname;
|
|
132392
|
-
var
|
|
132392
|
+
var join2 = path5.join;
|
|
132393
132393
|
var resolve = path5.resolve;
|
|
132394
132394
|
module.exports = View;
|
|
132395
132395
|
function View(name, options) {
|
|
@@ -132425,7 +132425,7 @@ var require_view = __commonJS((exports, module) => {
|
|
|
132425
132425
|
for (var i = 0;i < roots.length && !path6; i++) {
|
|
132426
132426
|
var root = roots[i];
|
|
132427
132427
|
var loc = resolve(root, name);
|
|
132428
|
-
var dir =
|
|
132428
|
+
var dir = dirname2(loc);
|
|
132429
132429
|
var file = basename(loc);
|
|
132430
132430
|
path6 = this.resolve(dir, file);
|
|
132431
132431
|
}
|
|
@@ -132451,12 +132451,12 @@ var require_view = __commonJS((exports, module) => {
|
|
|
132451
132451
|
};
|
|
132452
132452
|
View.prototype.resolve = function resolve(dir, file) {
|
|
132453
132453
|
var ext = this.ext;
|
|
132454
|
-
var path6 =
|
|
132454
|
+
var path6 = join2(dir, file);
|
|
132455
132455
|
var stat = tryStat(path6);
|
|
132456
132456
|
if (stat && stat.isFile()) {
|
|
132457
132457
|
return path6;
|
|
132458
132458
|
}
|
|
132459
|
-
path6 =
|
|
132459
|
+
path6 = join2(dir, basename(file, ext), "index" + ext);
|
|
132460
132460
|
stat = tryStat(path6);
|
|
132461
132461
|
if (stat && stat.isFile()) {
|
|
132462
132462
|
return path6;
|
|
@@ -136217,7 +136217,7 @@ var require_send = __commonJS((exports, module) => {
|
|
|
136217
136217
|
var Stream = __require("stream");
|
|
136218
136218
|
var util3 = __require("util");
|
|
136219
136219
|
var extname2 = path5.extname;
|
|
136220
|
-
var
|
|
136220
|
+
var join2 = path5.join;
|
|
136221
136221
|
var normalize = path5.normalize;
|
|
136222
136222
|
var resolve = path5.resolve;
|
|
136223
136223
|
var sep = path5.sep;
|
|
@@ -136389,7 +136389,7 @@ var require_send = __commonJS((exports, module) => {
|
|
|
136389
136389
|
return res;
|
|
136390
136390
|
}
|
|
136391
136391
|
parts = path6.split(sep);
|
|
136392
|
-
path6 = normalize(
|
|
136392
|
+
path6 = normalize(join2(root, path6));
|
|
136393
136393
|
} else {
|
|
136394
136394
|
if (UP_PATH_REGEXP.test(path6)) {
|
|
136395
136395
|
debug('malicious path "%s"', path6);
|
|
@@ -136529,7 +136529,7 @@ var require_send = __commonJS((exports, module) => {
|
|
|
136529
136529
|
return self2.onStatError(err);
|
|
136530
136530
|
return self2.error(404);
|
|
136531
136531
|
}
|
|
136532
|
-
var p =
|
|
136532
|
+
var p = join2(path6, self2._index[i]);
|
|
136533
136533
|
debug('stat "%s"', p);
|
|
136534
136534
|
fs5.stat(p, function(err2, stat) {
|
|
136535
136535
|
if (err2)
|
|
@@ -167234,6 +167234,35 @@ var VideoGenerationInputSchema = exports_external.object({
|
|
|
167234
167234
|
camera_movement: exports_external.enum(["static", "pan_left", "pan_right", "zoom_in", "zoom_out", "dolly_forward", "dolly_backward"]).optional(),
|
|
167235
167235
|
seed: exports_external.number().int().min(0).optional()
|
|
167236
167236
|
});
|
|
167237
|
+
var ImageEditingInputSchema = exports_external.object({
|
|
167238
|
+
operation: exports_external.enum([
|
|
167239
|
+
"inpaint",
|
|
167240
|
+
"outpaint",
|
|
167241
|
+
"style_transfer",
|
|
167242
|
+
"object_manipulation",
|
|
167243
|
+
"multi_image_compose"
|
|
167244
|
+
]).describe("Type of image editing operation to perform"),
|
|
167245
|
+
input_image: exports_external.string().describe("Base64 encoded image or file path to the input image"),
|
|
167246
|
+
prompt: exports_external.string().min(1, "Prompt cannot be empty").describe("Text description of the desired edit"),
|
|
167247
|
+
mask_image: exports_external.string().optional().describe("Base64 encoded mask image for inpainting (white = edit area, black = keep)"),
|
|
167248
|
+
mask_prompt: exports_external.string().optional().describe("Text description of the area to mask for editing"),
|
|
167249
|
+
expand_direction: exports_external.enum(["all", "left", "right", "top", "bottom", "horizontal", "vertical"]).optional().describe("Direction to expand the image"),
|
|
167250
|
+
expansion_ratio: exports_external.number().min(0.1).max(3).optional().default(1.5).describe("How much to expand the image (1.0 = no expansion)"),
|
|
167251
|
+
style_image: exports_external.string().optional().describe("Base64 encoded reference image for style transfer"),
|
|
167252
|
+
style_strength: exports_external.number().min(0.1).max(1).optional().default(0.7).describe("Strength of style application"),
|
|
167253
|
+
target_object: exports_external.string().optional().describe("Description of the object to manipulate"),
|
|
167254
|
+
manipulation_type: exports_external.enum(["move", "resize", "remove", "replace", "duplicate"]).optional().describe("Type of object manipulation"),
|
|
167255
|
+
target_position: exports_external.string().optional().describe("New position for the object (e.g., 'center', 'top-left')"),
|
|
167256
|
+
secondary_images: exports_external.array(exports_external.string()).optional().describe("Array of base64 encoded images for composition"),
|
|
167257
|
+
composition_layout: exports_external.enum(["blend", "collage", "overlay", "side_by_side"]).optional().describe("How to combine multiple images"),
|
|
167258
|
+
blend_mode: exports_external.enum(["normal", "multiply", "screen", "overlay", "soft_light"]).optional().describe("Blending mode for image composition"),
|
|
167259
|
+
negative_prompt: exports_external.string().optional().describe("What to avoid in the edited image"),
|
|
167260
|
+
strength: exports_external.number().min(0.1).max(1).optional().default(0.8).describe("Strength of the editing effect"),
|
|
167261
|
+
guidance_scale: exports_external.number().min(1).max(20).optional().default(7.5).describe("How closely to follow the prompt"),
|
|
167262
|
+
seed: exports_external.number().int().min(0).optional().describe("Random seed for reproducible results"),
|
|
167263
|
+
output_format: exports_external.enum(["base64", "url"]).optional().default("base64").describe("Output format for the edited image"),
|
|
167264
|
+
quality: exports_external.enum(["draft", "standard", "high"]).optional().default("standard").describe("Quality level of the editing")
|
|
167265
|
+
});
|
|
167237
167266
|
|
|
167238
167267
|
// src/utils/file-storage.ts
|
|
167239
167268
|
import { writeFileSync, mkdirSync } from "fs";
|
|
@@ -167610,6 +167639,264 @@ function estimateVideoSize(duration, aspectRatio) {
|
|
|
167610
167639
|
return `${width}x${height}`;
|
|
167611
167640
|
}
|
|
167612
167641
|
|
|
167642
|
+
// src/tools/hands/processors/image-editor.ts
|
|
167643
|
+
function processImageDataUri(dataUri) {
|
|
167644
|
+
const matches = dataUri.match(/^data:([^;]+);base64,(.+)$/);
|
|
167645
|
+
if (!matches || !matches[1] || !matches[2]) {
|
|
167646
|
+
throw new Error("Invalid data URI format");
|
|
167647
|
+
}
|
|
167648
|
+
return {
|
|
167649
|
+
mimeType: matches[1],
|
|
167650
|
+
data: matches[2]
|
|
167651
|
+
};
|
|
167652
|
+
}
|
|
167653
|
+
async function editImage(geminiClient, options, config) {
|
|
167654
|
+
const startTime = Date.now();
|
|
167655
|
+
try {
|
|
167656
|
+
const processedInputImage = await processImageForEditing(options.inputImage);
|
|
167657
|
+
const editingPrompt = buildEditingPrompt(options);
|
|
167658
|
+
logger2.info(`Image editing operation: ${options.operation}`);
|
|
167659
|
+
logger2.info(`Editing prompt: "${editingPrompt}"`);
|
|
167660
|
+
const model = geminiClient.getModel("detailed");
|
|
167661
|
+
const requestContent = await buildRequestContent(options, processedInputImage, editingPrompt);
|
|
167662
|
+
const response = await model.generateContent(requestContent);
|
|
167663
|
+
const result = response.response;
|
|
167664
|
+
const candidates = result.candidates;
|
|
167665
|
+
if (!candidates || candidates.length === 0) {
|
|
167666
|
+
throw new Error("No image candidates returned from Gemini API");
|
|
167667
|
+
}
|
|
167668
|
+
const candidate = candidates[0];
|
|
167669
|
+
if (!candidate || !candidate.content || !candidate.content.parts) {
|
|
167670
|
+
throw new Error("Invalid response format from Gemini API");
|
|
167671
|
+
}
|
|
167672
|
+
let imageData = null;
|
|
167673
|
+
let mimeType = "image/jpeg";
|
|
167674
|
+
for (const part of candidate.content.parts) {
|
|
167675
|
+
if ("inlineData" in part && part.inlineData) {
|
|
167676
|
+
imageData = part.inlineData.data;
|
|
167677
|
+
mimeType = part.inlineData.mimeType || "image/jpeg";
|
|
167678
|
+
break;
|
|
167679
|
+
}
|
|
167680
|
+
}
|
|
167681
|
+
if (!imageData) {
|
|
167682
|
+
throw new Error("No image data found in Gemini response");
|
|
167683
|
+
}
|
|
167684
|
+
const processingTime = Date.now() - startTime;
|
|
167685
|
+
let resultData;
|
|
167686
|
+
let format;
|
|
167687
|
+
let filePath;
|
|
167688
|
+
let fileName;
|
|
167689
|
+
let fileUrl;
|
|
167690
|
+
let fileSize;
|
|
167691
|
+
const shouldSaveFile = options.saveToFile !== false;
|
|
167692
|
+
const shouldUploadToR2 = options.uploadToR2 === true;
|
|
167693
|
+
if (shouldSaveFile && config) {
|
|
167694
|
+
try {
|
|
167695
|
+
const savedFile = await saveBase64ToFile(imageData, mimeType, config, {
|
|
167696
|
+
prefix: options.filePrefix || `edited-${options.operation}`,
|
|
167697
|
+
directory: options.saveDirectory,
|
|
167698
|
+
uploadToR2: shouldUploadToR2
|
|
167699
|
+
});
|
|
167700
|
+
filePath = savedFile.filePath;
|
|
167701
|
+
fileName = savedFile.fileName;
|
|
167702
|
+
fileUrl = savedFile.url;
|
|
167703
|
+
fileSize = savedFile.size;
|
|
167704
|
+
logger2.info(`Edited image saved to file: ${filePath}`);
|
|
167705
|
+
if (options.outputFormat === "url") {
|
|
167706
|
+
resultData = fileUrl || filePath || `data:${mimeType};base64,${imageData}`;
|
|
167707
|
+
format = fileUrl ? "url" : "file_path";
|
|
167708
|
+
} else {
|
|
167709
|
+
resultData = `data:${mimeType};base64,${imageData}`;
|
|
167710
|
+
format = "base64_data_uri";
|
|
167711
|
+
}
|
|
167712
|
+
} catch (error) {
|
|
167713
|
+
logger2.warn(`Failed to save edited image file: ${error}. Falling back to base64 only.`);
|
|
167714
|
+
resultData = `data:${mimeType};base64,${imageData}`;
|
|
167715
|
+
format = "base64_data_uri";
|
|
167716
|
+
}
|
|
167717
|
+
} else {
|
|
167718
|
+
if (options.outputFormat === "base64") {
|
|
167719
|
+
resultData = `data:${mimeType};base64,${imageData}`;
|
|
167720
|
+
format = "base64_data_uri";
|
|
167721
|
+
} else {
|
|
167722
|
+
resultData = `data:${mimeType};base64,${imageData}`;
|
|
167723
|
+
format = "base64_data_uri";
|
|
167724
|
+
logger2.warn("URL output format requested but file saving disabled. Returning base64 data URI");
|
|
167725
|
+
}
|
|
167726
|
+
}
|
|
167727
|
+
return {
|
|
167728
|
+
editedImageData: resultData,
|
|
167729
|
+
format,
|
|
167730
|
+
operation: options.operation,
|
|
167731
|
+
processingTime,
|
|
167732
|
+
originalSize: estimateImageSize2(processedInputImage.data),
|
|
167733
|
+
editedSize: estimateImageSize2(imageData),
|
|
167734
|
+
filePath,
|
|
167735
|
+
fileName,
|
|
167736
|
+
fileUrl,
|
|
167737
|
+
fileSize,
|
|
167738
|
+
metadata: {
|
|
167739
|
+
prompt: options.prompt,
|
|
167740
|
+
operation: options.operation,
|
|
167741
|
+
strength: options.strength,
|
|
167742
|
+
guidanceScale: options.guidanceScale,
|
|
167743
|
+
seed: options.seed
|
|
167744
|
+
}
|
|
167745
|
+
};
|
|
167746
|
+
} catch (error) {
|
|
167747
|
+
const processingTime = Date.now() - startTime;
|
|
167748
|
+
logger2.error(`Image editing failed after ${processingTime}ms:`, error);
|
|
167749
|
+
if (error instanceof Error) {
|
|
167750
|
+
if (error.message.includes("API key")) {
|
|
167751
|
+
throw new Error("Invalid or missing Google AI API key. Please check your GOOGLE_GEMINI_API_KEY environment variable.");
|
|
167752
|
+
}
|
|
167753
|
+
if (error.message.includes("quota") || error.message.includes("rate limit")) {
|
|
167754
|
+
throw new Error("API quota exceeded or rate limit reached. Please try again later.");
|
|
167755
|
+
}
|
|
167756
|
+
if (error.message.includes("safety") || error.message.includes("policy")) {
|
|
167757
|
+
throw new Error("Image editing blocked due to safety policies. Please modify your request and try again.");
|
|
167758
|
+
}
|
|
167759
|
+
throw new Error(`Image editing failed: ${error.message}`);
|
|
167760
|
+
}
|
|
167761
|
+
throw new Error("Image editing failed due to an unexpected error");
|
|
167762
|
+
}
|
|
167763
|
+
}
|
|
167764
|
+
async function processImageForEditing(inputImage) {
|
|
167765
|
+
try {
|
|
167766
|
+
if (inputImage.startsWith("data:")) {
|
|
167767
|
+
const result = processImageDataUri(inputImage);
|
|
167768
|
+
return {
|
|
167769
|
+
data: result.data,
|
|
167770
|
+
mimeType: result.mimeType
|
|
167771
|
+
};
|
|
167772
|
+
}
|
|
167773
|
+
if (inputImage.startsWith("/") || inputImage.startsWith("./")) {
|
|
167774
|
+
throw new Error("File path input not yet implemented. Please use base64 data URI format.");
|
|
167775
|
+
}
|
|
167776
|
+
return {
|
|
167777
|
+
data: inputImage,
|
|
167778
|
+
mimeType: "image/jpeg"
|
|
167779
|
+
};
|
|
167780
|
+
} catch (error) {
|
|
167781
|
+
throw new Error(`Failed to process input image: ${error instanceof Error ? error.message : error}`);
|
|
167782
|
+
}
|
|
167783
|
+
}
|
|
167784
|
+
function buildEditingPrompt(options) {
|
|
167785
|
+
let prompt = options.prompt;
|
|
167786
|
+
switch (options.operation) {
|
|
167787
|
+
case "inpaint":
|
|
167788
|
+
prompt = `Edit the specified area of this image: ${prompt}`;
|
|
167789
|
+
if (options.maskPrompt) {
|
|
167790
|
+
prompt += `. Focus on the area described as: ${options.maskPrompt}`;
|
|
167791
|
+
}
|
|
167792
|
+
break;
|
|
167793
|
+
case "outpaint":
|
|
167794
|
+
prompt = `Expand this image ${options.expandDirection || "in all directions"}: ${prompt}`;
|
|
167795
|
+
if (options.expansionRatio && options.expansionRatio !== 1.5) {
|
|
167796
|
+
prompt += `. Expansion ratio: ${options.expansionRatio}x`;
|
|
167797
|
+
}
|
|
167798
|
+
break;
|
|
167799
|
+
case "style_transfer":
|
|
167800
|
+
prompt = `Apply the following style to this image: ${prompt}`;
|
|
167801
|
+
if (options.styleStrength && options.styleStrength !== 0.7) {
|
|
167802
|
+
prompt += `. Style strength: ${options.styleStrength}`;
|
|
167803
|
+
}
|
|
167804
|
+
break;
|
|
167805
|
+
case "object_manipulation":
|
|
167806
|
+
if (options.targetObject) {
|
|
167807
|
+
prompt = `${options.manipulationType || "modify"} the ${options.targetObject} in this image: ${prompt}`;
|
|
167808
|
+
if (options.targetPosition) {
|
|
167809
|
+
prompt += `. Position: ${options.targetPosition}`;
|
|
167810
|
+
}
|
|
167811
|
+
}
|
|
167812
|
+
break;
|
|
167813
|
+
case "multi_image_compose":
|
|
167814
|
+
prompt = `Compose multiple images together: ${prompt}`;
|
|
167815
|
+
if (options.compositionLayout) {
|
|
167816
|
+
prompt += `. Layout: ${options.compositionLayout}`;
|
|
167817
|
+
}
|
|
167818
|
+
if (options.blendMode) {
|
|
167819
|
+
prompt += `. Blend mode: ${options.blendMode}`;
|
|
167820
|
+
}
|
|
167821
|
+
break;
|
|
167822
|
+
}
|
|
167823
|
+
if (options.quality === "high") {
|
|
167824
|
+
prompt += ". High quality, detailed result.";
|
|
167825
|
+
} else if (options.quality === "draft") {
|
|
167826
|
+
prompt += ". Quick draft version.";
|
|
167827
|
+
}
|
|
167828
|
+
if (options.negativePrompt) {
|
|
167829
|
+
prompt += ` Avoid: ${options.negativePrompt}`;
|
|
167830
|
+
}
|
|
167831
|
+
return prompt;
|
|
167832
|
+
}
|
|
167833
|
+
async function buildRequestContent(options, processedInputImage, editingPrompt) {
|
|
167834
|
+
const content = [
|
|
167835
|
+
{
|
|
167836
|
+
text: editingPrompt
|
|
167837
|
+
},
|
|
167838
|
+
{
|
|
167839
|
+
inlineData: {
|
|
167840
|
+
data: processedInputImage.data,
|
|
167841
|
+
mimeType: processedInputImage.mimeType
|
|
167842
|
+
}
|
|
167843
|
+
}
|
|
167844
|
+
];
|
|
167845
|
+
if (options.operation === "inpaint" && options.maskImage) {
|
|
167846
|
+
try {
|
|
167847
|
+
const processedMask = await processImageForEditing(options.maskImage);
|
|
167848
|
+
content.push({
|
|
167849
|
+
inlineData: {
|
|
167850
|
+
data: processedMask.data,
|
|
167851
|
+
mimeType: processedMask.mimeType
|
|
167852
|
+
}
|
|
167853
|
+
});
|
|
167854
|
+
} catch (error) {
|
|
167855
|
+
logger2.warn(`Failed to process mask image: ${error}. Proceeding without mask.`);
|
|
167856
|
+
}
|
|
167857
|
+
}
|
|
167858
|
+
if (options.operation === "style_transfer" && options.styleImage) {
|
|
167859
|
+
try {
|
|
167860
|
+
const processedStyle = await processImageForEditing(options.styleImage);
|
|
167861
|
+
content.push({
|
|
167862
|
+
inlineData: {
|
|
167863
|
+
data: processedStyle.data,
|
|
167864
|
+
mimeType: processedStyle.mimeType
|
|
167865
|
+
}
|
|
167866
|
+
});
|
|
167867
|
+
} catch (error) {
|
|
167868
|
+
logger2.warn(`Failed to process style image: ${error}. Proceeding without style reference.`);
|
|
167869
|
+
}
|
|
167870
|
+
}
|
|
167871
|
+
if (options.operation === "multi_image_compose" && options.secondaryImages) {
|
|
167872
|
+
for (const secondaryImage of options.secondaryImages) {
|
|
167873
|
+
try {
|
|
167874
|
+
const processedSecondary = await processImageForEditing(secondaryImage);
|
|
167875
|
+
content.push({
|
|
167876
|
+
inlineData: {
|
|
167877
|
+
data: processedSecondary.data,
|
|
167878
|
+
mimeType: processedSecondary.mimeType
|
|
167879
|
+
}
|
|
167880
|
+
});
|
|
167881
|
+
} catch (error) {
|
|
167882
|
+
logger2.warn(`Failed to process secondary image: ${error}. Skipping this image.`);
|
|
167883
|
+
}
|
|
167884
|
+
}
|
|
167885
|
+
}
|
|
167886
|
+
return content;
|
|
167887
|
+
}
|
|
167888
|
+
function estimateImageSize2(base64Data) {
|
|
167889
|
+
const dataLength = base64Data.length;
|
|
167890
|
+
const estimatedBytes = dataLength * 3 / 4;
|
|
167891
|
+
if (estimatedBytes < 1e5) {
|
|
167892
|
+
return "512x512";
|
|
167893
|
+
} else if (estimatedBytes < 400000) {
|
|
167894
|
+
return "1024x1024";
|
|
167895
|
+
} else {
|
|
167896
|
+
return "1024x1024+";
|
|
167897
|
+
}
|
|
167898
|
+
}
|
|
167899
|
+
|
|
167613
167900
|
// src/tools/hands/index.ts
|
|
167614
167901
|
async function registerHandsTool(server, config) {
|
|
167615
167902
|
const geminiClient = new GeminiClient(config);
|
|
@@ -167700,6 +167987,177 @@ async function registerHandsTool(server, config) {
|
|
|
167700
167987
|
};
|
|
167701
167988
|
}
|
|
167702
167989
|
});
|
|
167990
|
+
server.registerTool("gemini_edit_image", {
|
|
167991
|
+
title: "Gemini Image Editing Tool",
|
|
167992
|
+
description: "Edit images using AI with various operations like inpainting, outpainting, style transfer, object manipulation, and composition",
|
|
167993
|
+
inputSchema: {
|
|
167994
|
+
operation: exports_external.enum([
|
|
167995
|
+
"inpaint",
|
|
167996
|
+
"outpaint",
|
|
167997
|
+
"style_transfer",
|
|
167998
|
+
"object_manipulation",
|
|
167999
|
+
"multi_image_compose"
|
|
168000
|
+
]).describe("Type of image editing operation to perform"),
|
|
168001
|
+
input_image: exports_external.string().describe("Base64 encoded image or file path to the input image"),
|
|
168002
|
+
prompt: exports_external.string().min(1, "Prompt cannot be empty").describe("Text description of the desired edit"),
|
|
168003
|
+
mask_image: exports_external.string().optional().describe("Base64 encoded mask image for inpainting (white = edit area, black = keep)"),
|
|
168004
|
+
mask_prompt: exports_external.string().optional().describe("Text description of the area to mask for editing"),
|
|
168005
|
+
expand_direction: exports_external.enum(["all", "left", "right", "top", "bottom", "horizontal", "vertical"]).optional().describe("Direction to expand the image"),
|
|
168006
|
+
expansion_ratio: exports_external.number().min(0.1).max(3).optional().default(1.5).describe("How much to expand the image (1.0 = no expansion)"),
|
|
168007
|
+
style_image: exports_external.string().optional().describe("Base64 encoded reference image for style transfer"),
|
|
168008
|
+
style_strength: exports_external.number().min(0.1).max(1).optional().default(0.7).describe("Strength of style application"),
|
|
168009
|
+
target_object: exports_external.string().optional().describe("Description of the object to manipulate"),
|
|
168010
|
+
manipulation_type: exports_external.enum(["move", "resize", "remove", "replace", "duplicate"]).optional().describe("Type of object manipulation"),
|
|
168011
|
+
target_position: exports_external.string().optional().describe("New position for the object (e.g., 'center', 'top-left')"),
|
|
168012
|
+
secondary_images: exports_external.array(exports_external.string()).optional().describe("Array of base64 encoded images for composition"),
|
|
168013
|
+
composition_layout: exports_external.enum(["blend", "collage", "overlay", "side_by_side"]).optional().describe("How to combine multiple images"),
|
|
168014
|
+
blend_mode: exports_external.enum(["normal", "multiply", "screen", "overlay", "soft_light"]).optional().describe("Blending mode for image composition"),
|
|
168015
|
+
negative_prompt: exports_external.string().optional().describe("What to avoid in the edited image"),
|
|
168016
|
+
strength: exports_external.number().min(0.1).max(1).optional().default(0.8).describe("Strength of the editing effect"),
|
|
168017
|
+
guidance_scale: exports_external.number().min(1).max(20).optional().default(7.5).describe("How closely to follow the prompt"),
|
|
168018
|
+
seed: exports_external.number().int().min(0).optional().describe("Random seed for reproducible results"),
|
|
168019
|
+
output_format: exports_external.enum(["base64", "url"]).optional().default("base64").describe("Output format for the edited image"),
|
|
168020
|
+
quality: exports_external.enum(["draft", "standard", "high"]).optional().default("standard").describe("Quality level of the editing")
|
|
168021
|
+
}
|
|
168022
|
+
}, async (args) => {
|
|
168023
|
+
try {
|
|
168024
|
+
return await handleImageEditing(geminiClient, args, config);
|
|
168025
|
+
} catch (error) {
|
|
168026
|
+
const mcpError = handleError(error);
|
|
168027
|
+
logger2.error(`Tool gemini_edit_image error:`, mcpError);
|
|
168028
|
+
return {
|
|
168029
|
+
content: [{
|
|
168030
|
+
type: "text",
|
|
168031
|
+
text: `Error: ${mcpError.message}`
|
|
168032
|
+
}],
|
|
168033
|
+
isError: true
|
|
168034
|
+
};
|
|
168035
|
+
}
|
|
168036
|
+
});
|
|
168037
|
+
server.registerTool("gemini_inpaint_image", {
|
|
168038
|
+
title: "Gemini Image Inpainting Tool",
|
|
168039
|
+
description: "Fill or modify specific areas of an image based on a text prompt and mask",
|
|
168040
|
+
inputSchema: {
|
|
168041
|
+
input_image: exports_external.string().describe("Base64 encoded image or file path to the input image"),
|
|
168042
|
+
prompt: exports_external.string().min(1, "Prompt cannot be empty").describe("Text description of what to paint in the masked area"),
|
|
168043
|
+
mask_image: exports_external.string().optional().describe("Base64 encoded mask image (white = edit area, black = keep)"),
|
|
168044
|
+
mask_prompt: exports_external.string().optional().describe("Text description of the area to mask for editing"),
|
|
168045
|
+
negative_prompt: exports_external.string().optional().describe("What to avoid in the edited area"),
|
|
168046
|
+
strength: exports_external.number().min(0.1).max(1).optional().default(0.8).describe("Strength of the editing effect"),
|
|
168047
|
+
guidance_scale: exports_external.number().min(1).max(20).optional().default(7.5).describe("How closely to follow the prompt"),
|
|
168048
|
+
seed: exports_external.number().int().min(0).optional().describe("Random seed for reproducible results"),
|
|
168049
|
+
output_format: exports_external.enum(["base64", "url"]).optional().default("base64").describe("Output format"),
|
|
168050
|
+
quality: exports_external.enum(["draft", "standard", "high"]).optional().default("standard").describe("Quality level")
|
|
168051
|
+
}
|
|
168052
|
+
}, async (args) => {
|
|
168053
|
+
try {
|
|
168054
|
+
const inpaintArgs = { ...args, operation: "inpaint" };
|
|
168055
|
+
return await handleImageEditing(geminiClient, inpaintArgs, config);
|
|
168056
|
+
} catch (error) {
|
|
168057
|
+
const mcpError = handleError(error);
|
|
168058
|
+
logger2.error(`Tool gemini_inpaint_image error:`, mcpError);
|
|
168059
|
+
return {
|
|
168060
|
+
content: [{
|
|
168061
|
+
type: "text",
|
|
168062
|
+
text: `Error: ${mcpError.message}`
|
|
168063
|
+
}],
|
|
168064
|
+
isError: true
|
|
168065
|
+
};
|
|
168066
|
+
}
|
|
168067
|
+
});
|
|
168068
|
+
server.registerTool("gemini_outpaint_image", {
|
|
168069
|
+
title: "Gemini Image Outpainting Tool",
|
|
168070
|
+
description: "Expand an image beyond its original borders in specified directions",
|
|
168071
|
+
inputSchema: {
|
|
168072
|
+
input_image: exports_external.string().describe("Base64 encoded image or file path to the input image"),
|
|
168073
|
+
prompt: exports_external.string().min(1, "Prompt cannot be empty").describe("Text description of what to add in the expanded areas"),
|
|
168074
|
+
expand_direction: exports_external.enum(["all", "left", "right", "top", "bottom", "horizontal", "vertical"]).optional().default("all").describe("Direction to expand the image"),
|
|
168075
|
+
expansion_ratio: exports_external.number().min(0.1).max(3).optional().default(1.5).describe("How much to expand the image (1.0 = no expansion)"),
|
|
168076
|
+
negative_prompt: exports_external.string().optional().describe("What to avoid in the expanded areas"),
|
|
168077
|
+
strength: exports_external.number().min(0.1).max(1).optional().default(0.8).describe("Strength of the editing effect"),
|
|
168078
|
+
guidance_scale: exports_external.number().min(1).max(20).optional().default(7.5).describe("How closely to follow the prompt"),
|
|
168079
|
+
seed: exports_external.number().int().min(0).optional().describe("Random seed for reproducible results"),
|
|
168080
|
+
output_format: exports_external.enum(["base64", "url"]).optional().default("base64").describe("Output format"),
|
|
168081
|
+
quality: exports_external.enum(["draft", "standard", "high"]).optional().default("standard").describe("Quality level")
|
|
168082
|
+
}
|
|
168083
|
+
}, async (args) => {
|
|
168084
|
+
try {
|
|
168085
|
+
const outpaintArgs = { ...args, operation: "outpaint" };
|
|
168086
|
+
return await handleImageEditing(geminiClient, outpaintArgs, config);
|
|
168087
|
+
} catch (error) {
|
|
168088
|
+
const mcpError = handleError(error);
|
|
168089
|
+
logger2.error(`Tool gemini_outpaint_image error:`, mcpError);
|
|
168090
|
+
return {
|
|
168091
|
+
content: [{
|
|
168092
|
+
type: "text",
|
|
168093
|
+
text: `Error: ${mcpError.message}`
|
|
168094
|
+
}],
|
|
168095
|
+
isError: true
|
|
168096
|
+
};
|
|
168097
|
+
}
|
|
168098
|
+
});
|
|
168099
|
+
server.registerTool("gemini_style_transfer_image", {
|
|
168100
|
+
title: "Gemini Style Transfer Tool",
|
|
168101
|
+
description: "Transfer the style from one image to another using AI",
|
|
168102
|
+
inputSchema: {
|
|
168103
|
+
input_image: exports_external.string().describe("Base64 encoded image or file path to the input image"),
|
|
168104
|
+
prompt: exports_external.string().min(1, "Prompt cannot be empty").describe("Text description of the desired style"),
|
|
168105
|
+
style_image: exports_external.string().optional().describe("Base64 encoded reference image for style transfer"),
|
|
168106
|
+
style_strength: exports_external.number().min(0.1).max(1).optional().default(0.7).describe("Strength of style application"),
|
|
168107
|
+
negative_prompt: exports_external.string().optional().describe("What style elements to avoid"),
|
|
168108
|
+
guidance_scale: exports_external.number().min(1).max(20).optional().default(7.5).describe("How closely to follow the prompt"),
|
|
168109
|
+
seed: exports_external.number().int().min(0).optional().describe("Random seed for reproducible results"),
|
|
168110
|
+
output_format: exports_external.enum(["base64", "url"]).optional().default("base64").describe("Output format"),
|
|
168111
|
+
quality: exports_external.enum(["draft", "standard", "high"]).optional().default("standard").describe("Quality level")
|
|
168112
|
+
}
|
|
168113
|
+
}, async (args) => {
|
|
168114
|
+
try {
|
|
168115
|
+
const styleArgs = { ...args, operation: "style_transfer" };
|
|
168116
|
+
return await handleImageEditing(geminiClient, styleArgs, config);
|
|
168117
|
+
} catch (error) {
|
|
168118
|
+
const mcpError = handleError(error);
|
|
168119
|
+
logger2.error(`Tool gemini_style_transfer_image error:`, mcpError);
|
|
168120
|
+
return {
|
|
168121
|
+
content: [{
|
|
168122
|
+
type: "text",
|
|
168123
|
+
text: `Error: ${mcpError.message}`
|
|
168124
|
+
}],
|
|
168125
|
+
isError: true
|
|
168126
|
+
};
|
|
168127
|
+
}
|
|
168128
|
+
});
|
|
168129
|
+
server.registerTool("gemini_compose_images", {
|
|
168130
|
+
title: "Gemini Image Composition Tool",
|
|
168131
|
+
description: "Combine multiple images into a single composition using AI",
|
|
168132
|
+
inputSchema: {
|
|
168133
|
+
input_image: exports_external.string().describe("Base64 encoded primary image"),
|
|
168134
|
+
secondary_images: exports_external.array(exports_external.string()).describe("Array of base64 encoded secondary images to compose"),
|
|
168135
|
+
prompt: exports_external.string().min(1, "Prompt cannot be empty").describe("Text description of how to compose the images"),
|
|
168136
|
+
composition_layout: exports_external.enum(["blend", "collage", "overlay", "side_by_side"]).optional().default("blend").describe("How to combine the images"),
|
|
168137
|
+
blend_mode: exports_external.enum(["normal", "multiply", "screen", "overlay", "soft_light"]).optional().default("normal").describe("Blending mode for image composition"),
|
|
168138
|
+
negative_prompt: exports_external.string().optional().describe("What to avoid in the composition"),
|
|
168139
|
+
strength: exports_external.number().min(0.1).max(1).optional().default(0.8).describe("Strength of the composition effect"),
|
|
168140
|
+
guidance_scale: exports_external.number().min(1).max(20).optional().default(7.5).describe("How closely to follow the prompt"),
|
|
168141
|
+
seed: exports_external.number().int().min(0).optional().describe("Random seed for reproducible results"),
|
|
168142
|
+
output_format: exports_external.enum(["base64", "url"]).optional().default("base64").describe("Output format"),
|
|
168143
|
+
quality: exports_external.enum(["draft", "standard", "high"]).optional().default("standard").describe("Quality level")
|
|
168144
|
+
}
|
|
168145
|
+
}, async (args) => {
|
|
168146
|
+
try {
|
|
168147
|
+
const composeArgs = { ...args, operation: "multi_image_compose" };
|
|
168148
|
+
return await handleImageEditing(geminiClient, composeArgs, config);
|
|
168149
|
+
} catch (error) {
|
|
168150
|
+
const mcpError = handleError(error);
|
|
168151
|
+
logger2.error(`Tool gemini_compose_images error:`, mcpError);
|
|
168152
|
+
return {
|
|
168153
|
+
content: [{
|
|
168154
|
+
type: "text",
|
|
168155
|
+
text: `Error: ${mcpError.message}`
|
|
168156
|
+
}],
|
|
168157
|
+
isError: true
|
|
168158
|
+
};
|
|
168159
|
+
}
|
|
168160
|
+
});
|
|
167703
168161
|
}
|
|
167704
168162
|
async function handleImageGeneration(geminiClient, args, config) {
|
|
167705
168163
|
const input = ImageGenerationInputSchema.parse(args);
|
|
@@ -167895,6 +168353,128 @@ async function handleImageToVideoGeneration(geminiClient, args, config) {
|
|
|
167895
168353
|
isError: false
|
|
167896
168354
|
};
|
|
167897
168355
|
}
|
|
168356
|
+
async function handleImageEditing(geminiClient, args, config) {
|
|
168357
|
+
const input = ImageEditingInputSchema.parse(args);
|
|
168358
|
+
const {
|
|
168359
|
+
operation,
|
|
168360
|
+
input_image,
|
|
168361
|
+
prompt,
|
|
168362
|
+
mask_image,
|
|
168363
|
+
mask_prompt,
|
|
168364
|
+
expand_direction,
|
|
168365
|
+
expansion_ratio,
|
|
168366
|
+
style_image,
|
|
168367
|
+
style_strength,
|
|
168368
|
+
target_object,
|
|
168369
|
+
manipulation_type,
|
|
168370
|
+
target_position,
|
|
168371
|
+
secondary_images,
|
|
168372
|
+
composition_layout,
|
|
168373
|
+
blend_mode,
|
|
168374
|
+
negative_prompt,
|
|
168375
|
+
strength,
|
|
168376
|
+
guidance_scale,
|
|
168377
|
+
seed,
|
|
168378
|
+
output_format,
|
|
168379
|
+
quality
|
|
168380
|
+
} = input;
|
|
168381
|
+
logger2.info(`Editing image with operation: "${operation}" and prompt: "${prompt}"`);
|
|
168382
|
+
const editingOptions = {
|
|
168383
|
+
operation,
|
|
168384
|
+
inputImage: input_image,
|
|
168385
|
+
prompt,
|
|
168386
|
+
maskImage: mask_image,
|
|
168387
|
+
maskPrompt: mask_prompt,
|
|
168388
|
+
expandDirection: expand_direction,
|
|
168389
|
+
expansionRatio: expansion_ratio || 1.5,
|
|
168390
|
+
styleImage: style_image,
|
|
168391
|
+
styleStrength: style_strength || 0.7,
|
|
168392
|
+
targetObject: target_object,
|
|
168393
|
+
manipulationType: manipulation_type,
|
|
168394
|
+
targetPosition: target_position,
|
|
168395
|
+
secondaryImages: secondary_images,
|
|
168396
|
+
compositionLayout: composition_layout,
|
|
168397
|
+
blendMode: blend_mode,
|
|
168398
|
+
negativePrompt: negative_prompt,
|
|
168399
|
+
strength: strength || 0.8,
|
|
168400
|
+
guidanceScale: guidance_scale || 7.5,
|
|
168401
|
+
seed,
|
|
168402
|
+
outputFormat: output_format || "base64",
|
|
168403
|
+
quality: quality || "standard",
|
|
168404
|
+
fetchTimeout: config.server.fetchTimeout,
|
|
168405
|
+
saveToFile: true,
|
|
168406
|
+
uploadToR2: config.cloudflare?.accessKey ? true : false,
|
|
168407
|
+
filePrefix: `edited-${operation}`
|
|
168408
|
+
};
|
|
168409
|
+
const result = await editImage(geminiClient, editingOptions, config);
|
|
168410
|
+
if (result.editedImageData.startsWith("data:")) {
|
|
168411
|
+
const matches = result.editedImageData.match(/data:([^;]+);base64,(.+)/);
|
|
168412
|
+
if (matches && matches[1] && matches[2]) {
|
|
168413
|
+
const mimeType = matches[1];
|
|
168414
|
+
const base64Data = matches[2];
|
|
168415
|
+
return {
|
|
168416
|
+
content: [
|
|
168417
|
+
{
|
|
168418
|
+
type: "image",
|
|
168419
|
+
data: base64Data,
|
|
168420
|
+
mimeType
|
|
168421
|
+
},
|
|
168422
|
+
{
|
|
168423
|
+
type: "text",
|
|
168424
|
+
text: `✅ Image edited successfully using ${operation} operation
|
|
168425
|
+
|
|
168426
|
+
**Editing Details:**
|
|
168427
|
+
- Operation: ${operation}
|
|
168428
|
+
- Prompt: "${prompt}"
|
|
168429
|
+
- Format: ${result.format}
|
|
168430
|
+
- Original Size: ${result.originalSize}
|
|
168431
|
+
- Edited Size: ${result.editedSize}
|
|
168432
|
+
- Processing Time: ${result.processingTime}ms
|
|
168433
|
+
- Quality: ${quality}
|
|
168434
|
+
- Timestamp: ${new Date().toISOString()}${result.filePath ? `
|
|
168435
|
+
|
|
168436
|
+
**File Information:**
|
|
168437
|
+
- File Path: ${result.filePath}
|
|
168438
|
+
- File Name: ${result.fileName}
|
|
168439
|
+
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168440
|
+
- Public URL: ${result.fileUrl}` : ""}${result.metadata ? `
|
|
168441
|
+
|
|
168442
|
+
**Operation Metadata:**
|
|
168443
|
+
- Strength: ${result.metadata.strength}
|
|
168444
|
+
- Guidance Scale: ${result.metadata.guidanceScale}
|
|
168445
|
+
- Seed: ${result.metadata.seed || "random"}` : ""}`
|
|
168446
|
+
}
|
|
168447
|
+
],
|
|
168448
|
+
isError: false
|
|
168449
|
+
};
|
|
168450
|
+
}
|
|
168451
|
+
}
|
|
168452
|
+
return {
|
|
168453
|
+
content: [
|
|
168454
|
+
{
|
|
168455
|
+
type: "text",
|
|
168456
|
+
text: `✅ Image edited successfully!
|
|
168457
|
+
|
|
168458
|
+
**Editing Details:**
|
|
168459
|
+
- Operation: ${operation}
|
|
168460
|
+
- Prompt: "${prompt}"
|
|
168461
|
+
- Format: ${result.format}
|
|
168462
|
+
- Original Size: ${result.originalSize}
|
|
168463
|
+
- Edited Size: ${result.editedSize}
|
|
168464
|
+
- Processing Time: ${result.processingTime}ms${result.filePath ? `
|
|
168465
|
+
|
|
168466
|
+
**File Information:**
|
|
168467
|
+
- File Path: ${result.filePath}
|
|
168468
|
+
- File Name: ${result.fileName}
|
|
168469
|
+
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168470
|
+
- Public URL: ${result.fileUrl}` : ""}
|
|
168471
|
+
|
|
168472
|
+
**Edited Image Data:** ${result.editedImageData.substring(0, 100)}...`
|
|
168473
|
+
}
|
|
168474
|
+
],
|
|
168475
|
+
isError: false
|
|
168476
|
+
};
|
|
168477
|
+
}
|
|
167898
168478
|
|
|
167899
168479
|
// src/tools/mouth/schemas.ts
|
|
167900
168480
|
var VoiceNames = [
|
|
@@ -169356,320 +169936,6 @@ ${session.finalAnswer}
|
|
|
169356
169936
|
return output;
|
|
169357
169937
|
}
|
|
169358
169938
|
|
|
169359
|
-
// src/tools/brain/native/memory.ts
|
|
169360
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
169361
|
-
import { existsSync } from "fs";
|
|
169362
|
-
import { join as join2, dirname as dirname2 } from "path";
|
|
169363
|
-
class MemoryManager {
|
|
169364
|
-
memoryPath;
|
|
169365
|
-
graph;
|
|
169366
|
-
constructor(memoryPath) {
|
|
169367
|
-
this.memoryPath = memoryPath || join2(process.cwd(), "data", "memory.json");
|
|
169368
|
-
this.graph = {
|
|
169369
|
-
entities: [],
|
|
169370
|
-
relations: [],
|
|
169371
|
-
metadata: {
|
|
169372
|
-
version: "1.0.0",
|
|
169373
|
-
createdAt: Date.now(),
|
|
169374
|
-
updatedAt: Date.now(),
|
|
169375
|
-
totalEntities: 0,
|
|
169376
|
-
totalRelations: 0
|
|
169377
|
-
}
|
|
169378
|
-
};
|
|
169379
|
-
}
|
|
169380
|
-
async initialize() {
|
|
169381
|
-
try {
|
|
169382
|
-
const dir = dirname2(this.memoryPath);
|
|
169383
|
-
if (!existsSync(dir)) {
|
|
169384
|
-
await mkdir(dir, { recursive: true });
|
|
169385
|
-
}
|
|
169386
|
-
if (existsSync(this.memoryPath)) {
|
|
169387
|
-
await this.loadMemory();
|
|
169388
|
-
} else {
|
|
169389
|
-
await this.saveMemory();
|
|
169390
|
-
}
|
|
169391
|
-
} catch (error) {
|
|
169392
|
-
logger2.warn("Failed to initialize memory:", error);
|
|
169393
|
-
}
|
|
169394
|
-
}
|
|
169395
|
-
async loadMemory() {
|
|
169396
|
-
try {
|
|
169397
|
-
const data = await readFile(this.memoryPath, "utf-8");
|
|
169398
|
-
this.graph = JSON.parse(data);
|
|
169399
|
-
if (!this.graph.metadata) {
|
|
169400
|
-
this.graph.metadata = {
|
|
169401
|
-
version: "1.0.0",
|
|
169402
|
-
createdAt: Date.now(),
|
|
169403
|
-
updatedAt: Date.now(),
|
|
169404
|
-
totalEntities: this.graph.entities.length,
|
|
169405
|
-
totalRelations: this.graph.relations.length
|
|
169406
|
-
};
|
|
169407
|
-
}
|
|
169408
|
-
} catch (error) {
|
|
169409
|
-
logger2.error("Failed to load memory:", error);
|
|
169410
|
-
throw new Error("Memory file corrupted or unreadable");
|
|
169411
|
-
}
|
|
169412
|
-
}
|
|
169413
|
-
async saveMemory() {
|
|
169414
|
-
try {
|
|
169415
|
-
this.graph.metadata.updatedAt = Date.now();
|
|
169416
|
-
this.graph.metadata.totalEntities = this.graph.entities.length;
|
|
169417
|
-
this.graph.metadata.totalRelations = this.graph.relations.length;
|
|
169418
|
-
await writeFile(this.memoryPath, JSON.stringify(this.graph, null, 2));
|
|
169419
|
-
} catch (error) {
|
|
169420
|
-
logger2.error("Failed to save memory:", error);
|
|
169421
|
-
throw new Error("Unable to persist memory");
|
|
169422
|
-
}
|
|
169423
|
-
}
|
|
169424
|
-
async createEntity(name, entityType, observations = []) {
|
|
169425
|
-
const existing = this.graph.entities.find((e) => e.name === name);
|
|
169426
|
-
if (existing) {
|
|
169427
|
-
throw new Error(`Entity '${name}' already exists`);
|
|
169428
|
-
}
|
|
169429
|
-
const entity = {
|
|
169430
|
-
name,
|
|
169431
|
-
entityType,
|
|
169432
|
-
observations,
|
|
169433
|
-
createdAt: Date.now(),
|
|
169434
|
-
updatedAt: Date.now()
|
|
169435
|
-
};
|
|
169436
|
-
this.graph.entities.push(entity);
|
|
169437
|
-
await this.saveMemory();
|
|
169438
|
-
return entity;
|
|
169439
|
-
}
|
|
169440
|
-
async addObservation(entityName, observation) {
|
|
169441
|
-
const entity = this.graph.entities.find((e) => e.name === entityName);
|
|
169442
|
-
if (!entity) {
|
|
169443
|
-
throw new Error(`Entity '${entityName}' not found`);
|
|
169444
|
-
}
|
|
169445
|
-
entity.observations.push(observation);
|
|
169446
|
-
entity.updatedAt = Date.now();
|
|
169447
|
-
await this.saveMemory();
|
|
169448
|
-
return entity;
|
|
169449
|
-
}
|
|
169450
|
-
async createRelation(from, to, relationType) {
|
|
169451
|
-
const fromEntity = this.graph.entities.find((e) => e.name === from);
|
|
169452
|
-
const toEntity = this.graph.entities.find((e) => e.name === to);
|
|
169453
|
-
if (!fromEntity) {
|
|
169454
|
-
throw new Error(`Source entity '${from}' not found`);
|
|
169455
|
-
}
|
|
169456
|
-
if (!toEntity) {
|
|
169457
|
-
throw new Error(`Target entity '${to}' not found`);
|
|
169458
|
-
}
|
|
169459
|
-
const existing = this.graph.relations.find((r) => r.from === from && r.to === to && r.relationType === relationType);
|
|
169460
|
-
if (existing) {
|
|
169461
|
-
throw new Error(`Relation '${from}' -> '${to}' (${relationType}) already exists`);
|
|
169462
|
-
}
|
|
169463
|
-
const relation = {
|
|
169464
|
-
from,
|
|
169465
|
-
to,
|
|
169466
|
-
relationType,
|
|
169467
|
-
createdAt: Date.now()
|
|
169468
|
-
};
|
|
169469
|
-
this.graph.relations.push(relation);
|
|
169470
|
-
await this.saveMemory();
|
|
169471
|
-
return relation;
|
|
169472
|
-
}
|
|
169473
|
-
async searchEntities(query, limit = 10) {
|
|
169474
|
-
const lowerQuery = query.toLowerCase();
|
|
169475
|
-
return this.graph.entities.filter((entity) => entity.name.toLowerCase().includes(lowerQuery) || entity.entityType.toLowerCase().includes(lowerQuery) || entity.observations.some((obs) => obs.toLowerCase().includes(lowerQuery))).slice(0, limit);
|
|
169476
|
-
}
|
|
169477
|
-
async getEntity(name) {
|
|
169478
|
-
return this.graph.entities.find((e) => e.name === name) || null;
|
|
169479
|
-
}
|
|
169480
|
-
async getRelatedEntities(entityName) {
|
|
169481
|
-
const incoming = this.graph.relations.filter((r) => r.to === entityName);
|
|
169482
|
-
const outgoing = this.graph.relations.filter((r) => r.from === entityName);
|
|
169483
|
-
return { incoming, outgoing };
|
|
169484
|
-
}
|
|
169485
|
-
getStats() {
|
|
169486
|
-
const types2 = [...new Set(this.graph.entities.map((e) => e.entityType))];
|
|
169487
|
-
return {
|
|
169488
|
-
entities: this.graph.entities.length,
|
|
169489
|
-
relations: this.graph.relations.length,
|
|
169490
|
-
types: types2
|
|
169491
|
-
};
|
|
169492
|
-
}
|
|
169493
|
-
}
|
|
169494
|
-
var memoryManager;
|
|
169495
|
-
async function registerMemoryTools(server, config) {
|
|
169496
|
-
logger2.info("Registering native memory tools...");
|
|
169497
|
-
memoryManager = new MemoryManager;
|
|
169498
|
-
await memoryManager.initialize();
|
|
169499
|
-
server.registerTool("mcp__memory__store", {
|
|
169500
|
-
title: "Store information in memory",
|
|
169501
|
-
description: "Create entities, relations, and observations in the knowledge graph",
|
|
169502
|
-
inputSchema: {
|
|
169503
|
-
action: exports_external.enum(["create_entity", "add_observation", "create_relation"]).describe("The action to perform"),
|
|
169504
|
-
entityName: exports_external.string().describe("Name of the entity"),
|
|
169505
|
-
entityType: exports_external.string().optional().describe("Type of entity (e.g., person, concept, project)"),
|
|
169506
|
-
observation: exports_external.string().optional().describe("Observation to add to entity"),
|
|
169507
|
-
targetEntity: exports_external.string().optional().describe("Target entity for relation"),
|
|
169508
|
-
relationType: exports_external.string().optional().describe("Type of relation (e.g., 'works_with', 'part_of', 'causes')")
|
|
169509
|
-
}
|
|
169510
|
-
}, async (args) => {
|
|
169511
|
-
try {
|
|
169512
|
-
const action = args.action;
|
|
169513
|
-
const entityName = args.entityName;
|
|
169514
|
-
let result;
|
|
169515
|
-
switch (action) {
|
|
169516
|
-
case "create_entity":
|
|
169517
|
-
const entityType = args.entityType || "general";
|
|
169518
|
-
result = await memoryManager.createEntity(entityName, entityType);
|
|
169519
|
-
break;
|
|
169520
|
-
case "add_observation":
|
|
169521
|
-
const observation = args.observation;
|
|
169522
|
-
if (!observation) {
|
|
169523
|
-
throw new Error("Observation is required");
|
|
169524
|
-
}
|
|
169525
|
-
result = await memoryManager.addObservation(entityName, observation);
|
|
169526
|
-
break;
|
|
169527
|
-
case "create_relation":
|
|
169528
|
-
const targetEntity = args.targetEntity;
|
|
169529
|
-
const relationType = args.relationType;
|
|
169530
|
-
if (!targetEntity || !relationType) {
|
|
169531
|
-
throw new Error("targetEntity and relationType are required for relations");
|
|
169532
|
-
}
|
|
169533
|
-
result = await memoryManager.createRelation(entityName, targetEntity, relationType);
|
|
169534
|
-
break;
|
|
169535
|
-
default:
|
|
169536
|
-
throw new Error(`Unknown action: ${action}`);
|
|
169537
|
-
}
|
|
169538
|
-
return {
|
|
169539
|
-
content: [{
|
|
169540
|
-
type: "text",
|
|
169541
|
-
text: `✅ ${action.replace("_", " ").toUpperCase()} completed successfully
|
|
169542
|
-
|
|
169543
|
-
${JSON.stringify(result, null, 2)}`
|
|
169544
|
-
}],
|
|
169545
|
-
isError: false
|
|
169546
|
-
};
|
|
169547
|
-
} catch (error) {
|
|
169548
|
-
const mcpError = handleError(error);
|
|
169549
|
-
logger2.error("Memory store tool error:", mcpError);
|
|
169550
|
-
return {
|
|
169551
|
-
content: [{
|
|
169552
|
-
type: "text",
|
|
169553
|
-
text: `❌ Error: ${mcpError.message}`
|
|
169554
|
-
}],
|
|
169555
|
-
isError: true
|
|
169556
|
-
};
|
|
169557
|
-
}
|
|
169558
|
-
});
|
|
169559
|
-
server.registerTool("mcp__memory__recall", {
|
|
169560
|
-
title: "Recall information from memory",
|
|
169561
|
-
description: "Search and retrieve entities, relations, and observations",
|
|
169562
|
-
inputSchema: {
|
|
169563
|
-
action: exports_external.enum(["search", "get_entity", "get_relations", "get_stats"]).describe("The recall action to perform"),
|
|
169564
|
-
query: exports_external.string().optional().describe("Search query"),
|
|
169565
|
-
entityName: exports_external.string().optional().describe("Name of specific entity to retrieve"),
|
|
169566
|
-
limit: exports_external.number().int().default(10).optional().describe("Maximum number of results")
|
|
169567
|
-
}
|
|
169568
|
-
}, async (args) => {
|
|
169569
|
-
try {
|
|
169570
|
-
const action = args.action;
|
|
169571
|
-
let result;
|
|
169572
|
-
switch (action) {
|
|
169573
|
-
case "search":
|
|
169574
|
-
const query = args.query;
|
|
169575
|
-
if (!query) {
|
|
169576
|
-
throw new Error("Query is required for search");
|
|
169577
|
-
}
|
|
169578
|
-
const limit = args.limit || 10;
|
|
169579
|
-
result = await memoryManager.searchEntities(query, limit);
|
|
169580
|
-
break;
|
|
169581
|
-
case "get_entity":
|
|
169582
|
-
const entityName = args.entityName;
|
|
169583
|
-
if (!entityName) {
|
|
169584
|
-
throw new Error("entityName is required");
|
|
169585
|
-
}
|
|
169586
|
-
result = await memoryManager.getEntity(entityName);
|
|
169587
|
-
break;
|
|
169588
|
-
case "get_relations":
|
|
169589
|
-
const entityNameForRelations = args.entityName;
|
|
169590
|
-
if (!entityNameForRelations) {
|
|
169591
|
-
throw new Error("entityName is required for relations");
|
|
169592
|
-
}
|
|
169593
|
-
result = await memoryManager.getRelatedEntities(entityNameForRelations);
|
|
169594
|
-
break;
|
|
169595
|
-
case "get_stats":
|
|
169596
|
-
result = memoryManager.getStats();
|
|
169597
|
-
break;
|
|
169598
|
-
default:
|
|
169599
|
-
throw new Error(`Unknown action: ${action}`);
|
|
169600
|
-
}
|
|
169601
|
-
return {
|
|
169602
|
-
content: [{
|
|
169603
|
-
type: "text",
|
|
169604
|
-
text: formatMemoryResult(action, result)
|
|
169605
|
-
}],
|
|
169606
|
-
isError: false
|
|
169607
|
-
};
|
|
169608
|
-
} catch (error) {
|
|
169609
|
-
const mcpError = handleError(error);
|
|
169610
|
-
logger2.error("Memory recall tool error:", mcpError);
|
|
169611
|
-
return {
|
|
169612
|
-
content: [{
|
|
169613
|
-
type: "text",
|
|
169614
|
-
text: `❌ Error: ${mcpError.message}`
|
|
169615
|
-
}],
|
|
169616
|
-
isError: true
|
|
169617
|
-
};
|
|
169618
|
-
}
|
|
169619
|
-
});
|
|
169620
|
-
logger2.info("Native memory tools registered successfully");
|
|
169621
|
-
}
|
|
169622
|
-
function formatMemoryResult(action, result) {
|
|
169623
|
-
switch (action) {
|
|
169624
|
-
case "search":
|
|
169625
|
-
if (!result || result.length === 0) {
|
|
169626
|
-
return "\uD83D\uDD0D No entities found matching the search criteria.";
|
|
169627
|
-
}
|
|
169628
|
-
return `\uD83D\uDD0D **Search Results** (${result.length} found)
|
|
169629
|
-
|
|
169630
|
-
` + result.map((entity) => `**${entity.name}** (${entity.entityType})
|
|
169631
|
-
` + `Observations: ${entity.observations.length}
|
|
169632
|
-
` + `${entity.observations.slice(0, 2).map((obs) => `• ${obs}`).join(`
|
|
169633
|
-
`)}` + (entity.observations.length > 2 ? `
|
|
169634
|
-
• ...` : "")).join(`
|
|
169635
|
-
|
|
169636
|
-
`);
|
|
169637
|
-
case "get_entity":
|
|
169638
|
-
if (!result) {
|
|
169639
|
-
return "\uD83D\uDEAB Entity not found.";
|
|
169640
|
-
}
|
|
169641
|
-
return `\uD83D\uDCCB **Entity: ${result.name}**
|
|
169642
|
-
|
|
169643
|
-
` + `**Type:** ${result.entityType}
|
|
169644
|
-
` + `**Created:** ${new Date(result.createdAt).toLocaleString()}
|
|
169645
|
-
` + `**Updated:** ${new Date(result.updatedAt).toLocaleString()}
|
|
169646
|
-
|
|
169647
|
-
` + `**Observations (${result.observations.length}):**
|
|
169648
|
-
` + result.observations.map((obs) => `• ${obs}`).join(`
|
|
169649
|
-
`);
|
|
169650
|
-
case "get_relations":
|
|
169651
|
-
const { incoming, outgoing } = result;
|
|
169652
|
-
return `\uD83D\uDD17 **Relations for Entity**
|
|
169653
|
-
|
|
169654
|
-
` + `**Incoming (${incoming.length}):**
|
|
169655
|
-
` + (incoming.length > 0 ? incoming.map((rel) => `• ${rel.from} --[${rel.relationType}]--> entity`).join(`
|
|
169656
|
-
`) : "• None") + `
|
|
169657
|
-
|
|
169658
|
-
` + `**Outgoing (${outgoing.length}):**
|
|
169659
|
-
` + (outgoing.length > 0 ? outgoing.map((rel) => `• entity --[${rel.relationType}]--> ${rel.to}`).join(`
|
|
169660
|
-
`) : "• None");
|
|
169661
|
-
case "get_stats":
|
|
169662
|
-
return `\uD83D\uDCCA **Memory Statistics**
|
|
169663
|
-
|
|
169664
|
-
` + `**Entities:** ${result.entities}
|
|
169665
|
-
` + `**Relations:** ${result.relations}
|
|
169666
|
-
` + `**Entity Types:** ${result.types.join(", ")}
|
|
169667
|
-
`;
|
|
169668
|
-
default:
|
|
169669
|
-
return JSON.stringify(result, null, 2);
|
|
169670
|
-
}
|
|
169671
|
-
}
|
|
169672
|
-
|
|
169673
169939
|
// src/tools/brain/native/simple-reasoning.ts
|
|
169674
169940
|
var REASONING_PATTERNS = {
|
|
169675
169941
|
problem_solving: {
|
|
@@ -170443,7 +170709,6 @@ Generate specific, actionable recommendations for next steps.
|
|
|
170443
170709
|
async function registerBrainTools(server, config) {
|
|
170444
170710
|
logger2.info("Registering optimized Brain tools (native + enhanced hybrid)...");
|
|
170445
170711
|
await registerSequentialThinkingTool(server, config);
|
|
170446
|
-
await registerMemoryTools(server, config);
|
|
170447
170712
|
await registerSimpleReasoningTools(server, config);
|
|
170448
170713
|
await registerEnhancedReflectionTool(server, config);
|
|
170449
170714
|
logger2.info("✅ Brain tools optimization complete:");
|