@goonnguyen/human-mcp 2.8.0 → 2.8.2
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 +168 -141
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -167922,29 +167922,48 @@ async function editImage(geminiClient, options, config) {
|
|
|
167922
167922
|
const editingPrompt = buildEditingPrompt(options);
|
|
167923
167923
|
logger2.info(`Image editing operation: ${options.operation}`);
|
|
167924
167924
|
logger2.info(`Editing prompt: "${editingPrompt}"`);
|
|
167925
|
-
const model = geminiClient.
|
|
167925
|
+
const model = geminiClient.getImageGenerationModel();
|
|
167926
167926
|
const requestContent = await buildRequestContent(options, processedInputImage, editingPrompt);
|
|
167927
167927
|
const response = await model.generateContent(requestContent);
|
|
167928
167928
|
const result = response.response;
|
|
167929
167929
|
const candidates = result.candidates;
|
|
167930
|
+
logger2.debug(`Gemini API response structure: ${JSON.stringify({
|
|
167931
|
+
hasCandidates: !!candidates,
|
|
167932
|
+
candidatesLength: candidates?.length,
|
|
167933
|
+
firstCandidate: candidates?.[0] ? {
|
|
167934
|
+
hasContent: !!candidates[0].content,
|
|
167935
|
+
hasParts: !!candidates[0].content?.parts,
|
|
167936
|
+
partsLength: candidates[0].content?.parts?.length
|
|
167937
|
+
} : null
|
|
167938
|
+
})}`);
|
|
167930
167939
|
if (!candidates || candidates.length === 0) {
|
|
167931
|
-
|
|
167940
|
+
logger2.error("No candidates in Gemini response. Full response:", JSON.stringify(result, null, 2));
|
|
167941
|
+
throw new Error("No image candidates returned from Gemini API. This may indicate the API doesn't support image editing yet, or the request format is incorrect.");
|
|
167932
167942
|
}
|
|
167933
167943
|
const candidate = candidates[0];
|
|
167934
|
-
if (!candidate || !candidate.content
|
|
167935
|
-
|
|
167944
|
+
if (!candidate || !candidate.content) {
|
|
167945
|
+
logger2.error("Invalid candidate structure:", JSON.stringify(candidate, null, 2));
|
|
167946
|
+
throw new Error("Invalid response format from Gemini API: missing candidate content");
|
|
167947
|
+
}
|
|
167948
|
+
if (!candidate.content.parts || candidate.content.parts.length === 0) {
|
|
167949
|
+
logger2.error("No parts in candidate content:", JSON.stringify(candidate.content, null, 2));
|
|
167950
|
+
throw new Error("Invalid response format from Gemini API: missing content parts. Note: Gemini image editing may not be available in the current API version.");
|
|
167936
167951
|
}
|
|
167937
167952
|
let imageData = null;
|
|
167938
167953
|
let mimeType = "image/jpeg";
|
|
167954
|
+
logger2.debug(`Searching for image data in ${candidate.content.parts.length} parts`);
|
|
167939
167955
|
for (const part of candidate.content.parts) {
|
|
167956
|
+
logger2.debug(`Part type: ${JSON.stringify(Object.keys(part))}`);
|
|
167940
167957
|
if ("inlineData" in part && part.inlineData) {
|
|
167941
167958
|
imageData = part.inlineData.data;
|
|
167942
167959
|
mimeType = part.inlineData.mimeType || "image/jpeg";
|
|
167960
|
+
logger2.info(`Found image data: ${imageData.length} bytes, type: ${mimeType}`);
|
|
167943
167961
|
break;
|
|
167944
167962
|
}
|
|
167945
167963
|
}
|
|
167946
167964
|
if (!imageData) {
|
|
167947
|
-
|
|
167965
|
+
logger2.error("No image data found in response parts:", JSON.stringify(candidate.content.parts, null, 2));
|
|
167966
|
+
throw new Error("No image data found in Gemini response. The API may have returned text instead of an edited image.");
|
|
167948
167967
|
}
|
|
167949
167968
|
const processingTime = Date.now() - startTime;
|
|
167950
167969
|
let resultData;
|
|
@@ -168161,6 +168180,68 @@ function estimateImageSize2(base64Data) {
|
|
|
168161
168180
|
// src/tools/hands/index.ts
|
|
168162
168181
|
init_logger();
|
|
168163
168182
|
init_errors();
|
|
168183
|
+
|
|
168184
|
+
// src/utils/response-formatter.ts
|
|
168185
|
+
function formatMediaResponse(result, config, contextText) {
|
|
168186
|
+
const isHttpTransport = config.transport.type === "http" || config.transport.type === "both" && config.transport.http?.enabled;
|
|
168187
|
+
if (isHttpTransport && result.url) {
|
|
168188
|
+
const response = [];
|
|
168189
|
+
response.push({
|
|
168190
|
+
type: "resource",
|
|
168191
|
+
resource: {
|
|
168192
|
+
uri: result.url,
|
|
168193
|
+
mimeType: result.mimeType || "image/png",
|
|
168194
|
+
text: contextText || `Generated media available at: ${result.url}`
|
|
168195
|
+
}
|
|
168196
|
+
});
|
|
168197
|
+
const details = [];
|
|
168198
|
+
if (result.size) {
|
|
168199
|
+
details.push(`Size: ${(result.size / 1024).toFixed(2)} KB`);
|
|
168200
|
+
}
|
|
168201
|
+
if (result.width && result.height) {
|
|
168202
|
+
details.push(`Dimensions: ${result.width}x${result.height}`);
|
|
168203
|
+
}
|
|
168204
|
+
response.push({
|
|
168205
|
+
type: "text",
|
|
168206
|
+
text: `✅ Media generated successfully!
|
|
168207
|
+
|
|
168208
|
+
URL: ${result.url}${details.length > 0 ? `
|
|
168209
|
+
` + details.join(", ") : ""}`
|
|
168210
|
+
});
|
|
168211
|
+
return response;
|
|
168212
|
+
}
|
|
168213
|
+
if (result.base64) {
|
|
168214
|
+
return [
|
|
168215
|
+
{
|
|
168216
|
+
type: "image",
|
|
168217
|
+
data: result.base64,
|
|
168218
|
+
mimeType: result.mimeType || "image/png"
|
|
168219
|
+
},
|
|
168220
|
+
{
|
|
168221
|
+
type: "text",
|
|
168222
|
+
text: contextText || (result.url ? `Image URL: ${result.url}` : "Image generated successfully")
|
|
168223
|
+
}
|
|
168224
|
+
];
|
|
168225
|
+
}
|
|
168226
|
+
if (result.url) {
|
|
168227
|
+
return [
|
|
168228
|
+
{
|
|
168229
|
+
type: "text",
|
|
168230
|
+
text: `${contextText || "Media generated successfully"}
|
|
168231
|
+
|
|
168232
|
+
URL: ${result.url}`
|
|
168233
|
+
}
|
|
168234
|
+
];
|
|
168235
|
+
}
|
|
168236
|
+
return [
|
|
168237
|
+
{
|
|
168238
|
+
type: "text",
|
|
168239
|
+
text: contextText || "Media generated successfully"
|
|
168240
|
+
}
|
|
168241
|
+
];
|
|
168242
|
+
}
|
|
168243
|
+
|
|
168244
|
+
// src/tools/hands/index.ts
|
|
168164
168245
|
async function registerHandsTool(server, config) {
|
|
168165
168246
|
const geminiClient = new GeminiClient(config);
|
|
168166
168247
|
server.registerTool("gemini_gen_image", {
|
|
@@ -168440,21 +168521,16 @@ async function handleImageGeneration(geminiClient, args, config) {
|
|
|
168440
168521
|
filePrefix: "gemini-image"
|
|
168441
168522
|
};
|
|
168442
168523
|
const result = await generateImage(geminiClient, generationOptions, config);
|
|
168524
|
+
let base64Data;
|
|
168525
|
+
let mimeType;
|
|
168443
168526
|
if (result.imageData.startsWith("data:")) {
|
|
168444
168527
|
const matches = result.imageData.match(/data:([^;]+);base64,(.+)/);
|
|
168445
168528
|
if (matches && matches[1] && matches[2]) {
|
|
168446
|
-
|
|
168447
|
-
|
|
168448
|
-
|
|
168449
|
-
|
|
168450
|
-
|
|
168451
|
-
type: "image",
|
|
168452
|
-
data: base64Data,
|
|
168453
|
-
mimeType
|
|
168454
|
-
},
|
|
168455
|
-
{
|
|
168456
|
-
type: "text",
|
|
168457
|
-
text: `✅ Image generated successfully using ${result.model}
|
|
168529
|
+
mimeType = matches[1];
|
|
168530
|
+
base64Data = matches[2];
|
|
168531
|
+
}
|
|
168532
|
+
}
|
|
168533
|
+
const contextText = `✅ Image generated successfully using ${result.model}
|
|
168458
168534
|
|
|
168459
168535
|
**Generation Details:**
|
|
168460
168536
|
- Prompt: "${prompt}"
|
|
@@ -168468,35 +168544,16 @@ async function handleImageGeneration(geminiClient, args, config) {
|
|
|
168468
168544
|
- File Path: ${result.filePath}
|
|
168469
168545
|
- File Name: ${result.fileName}
|
|
168470
168546
|
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168471
|
-
- Public URL: ${result.fileUrl}` : ""}
|
|
168472
|
-
|
|
168473
|
-
|
|
168474
|
-
|
|
168475
|
-
|
|
168476
|
-
|
|
168477
|
-
|
|
168547
|
+
- Public URL: ${result.fileUrl}` : ""}`;
|
|
168548
|
+
const formattedResponse = formatMediaResponse({
|
|
168549
|
+
url: result.fileUrl,
|
|
168550
|
+
filePath: result.filePath,
|
|
168551
|
+
base64: base64Data,
|
|
168552
|
+
mimeType,
|
|
168553
|
+
size: result.fileSize
|
|
168554
|
+
}, config, contextText);
|
|
168478
168555
|
return {
|
|
168479
|
-
content:
|
|
168480
|
-
{
|
|
168481
|
-
type: "text",
|
|
168482
|
-
text: `✅ Image generated successfully!
|
|
168483
|
-
|
|
168484
|
-
**Generation Details:**
|
|
168485
|
-
- Prompt: "${prompt}"
|
|
168486
|
-
- Model: ${result.model}
|
|
168487
|
-
- Format: ${result.format}
|
|
168488
|
-
- Size: ${result.size}
|
|
168489
|
-
- Generation Time: ${result.generationTime}ms${result.filePath ? `
|
|
168490
|
-
|
|
168491
|
-
**File Information:**
|
|
168492
|
-
- File Path: ${result.filePath}
|
|
168493
|
-
- File Name: ${result.fileName}
|
|
168494
|
-
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168495
|
-
- Public URL: ${result.fileUrl}` : ""}
|
|
168496
|
-
|
|
168497
|
-
**Image Data:** ${result.imageData.substring(0, 100)}...`
|
|
168498
|
-
}
|
|
168499
|
-
],
|
|
168556
|
+
content: formattedResponse,
|
|
168500
168557
|
isError: false
|
|
168501
168558
|
};
|
|
168502
168559
|
}
|
|
@@ -168521,34 +168578,32 @@ async function handleVideoGeneration(geminiClient, args, config) {
|
|
|
168521
168578
|
filePrefix: "gemini-video"
|
|
168522
168579
|
};
|
|
168523
168580
|
const result = await generateVideo(geminiClient, generationOptions, config);
|
|
168581
|
+
const contextText = `✅ Video generated successfully!
|
|
168582
|
+
|
|
168583
|
+
**Generation Details:**
|
|
168584
|
+
- Prompt: "${prompt}"
|
|
168585
|
+
- Model: ${result.model}
|
|
168586
|
+
- Format: ${result.format}
|
|
168587
|
+
- Duration: ${result.duration}
|
|
168588
|
+
- Aspect Ratio: ${result.aspectRatio}
|
|
168589
|
+
- FPS: ${result.fps}
|
|
168590
|
+
- Generation Time: ${result.generationTime}ms
|
|
168591
|
+
- Operation ID: ${result.operationId}
|
|
168592
|
+
- Timestamp: ${new Date().toISOString()}${result.filePath ? `
|
|
168593
|
+
|
|
168594
|
+
**File Information:**
|
|
168595
|
+
- File Path: ${result.filePath}
|
|
168596
|
+
- File Name: ${result.fileName}
|
|
168597
|
+
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168598
|
+
- Public URL: ${result.fileUrl}` : ""}`;
|
|
168599
|
+
const formattedResponse = formatMediaResponse({
|
|
168600
|
+
url: result.fileUrl,
|
|
168601
|
+
filePath: result.filePath,
|
|
168602
|
+
mimeType: `video/${result.format}`,
|
|
168603
|
+
size: result.fileSize
|
|
168604
|
+
}, config, contextText);
|
|
168524
168605
|
return {
|
|
168525
|
-
content:
|
|
168526
|
-
{
|
|
168527
|
-
type: "text",
|
|
168528
|
-
text: JSON.stringify({
|
|
168529
|
-
success: true,
|
|
168530
|
-
video: result.filePath ? `File saved to: ${result.filePath}` : result.videoData.substring(0, 100) + "...",
|
|
168531
|
-
format: result.format,
|
|
168532
|
-
model: result.model,
|
|
168533
|
-
prompt,
|
|
168534
|
-
operation_id: result.operationId,
|
|
168535
|
-
file_info: result.filePath ? {
|
|
168536
|
-
file_path: result.filePath,
|
|
168537
|
-
file_name: result.fileName,
|
|
168538
|
-
file_size: result.fileSize,
|
|
168539
|
-
public_url: result.fileUrl
|
|
168540
|
-
} : null,
|
|
168541
|
-
metadata: {
|
|
168542
|
-
timestamp: new Date().toISOString(),
|
|
168543
|
-
generation_time: result.generationTime,
|
|
168544
|
-
duration: result.duration,
|
|
168545
|
-
aspect_ratio: result.aspectRatio,
|
|
168546
|
-
fps: result.fps,
|
|
168547
|
-
size: result.size
|
|
168548
|
-
}
|
|
168549
|
-
}, null, 2)
|
|
168550
|
-
}
|
|
168551
|
-
],
|
|
168606
|
+
content: formattedResponse,
|
|
168552
168607
|
isError: false
|
|
168553
168608
|
};
|
|
168554
168609
|
}
|
|
@@ -168584,35 +168639,32 @@ async function handleImageToVideoGeneration(geminiClient, args, config) {
|
|
|
168584
168639
|
filePrefix: "gemini-image-to-video"
|
|
168585
168640
|
};
|
|
168586
168641
|
const result = await generateImageToVideo(geminiClient, prompt, image_input, generationOptions, config);
|
|
168642
|
+
const contextText = `✅ Video generated from image successfully!
|
|
168643
|
+
|
|
168644
|
+
**Generation Details:**
|
|
168645
|
+
- Prompt: "${prompt}"
|
|
168646
|
+
- Model: ${result.model}
|
|
168647
|
+
- Format: ${result.format}
|
|
168648
|
+
- Duration: ${result.duration}
|
|
168649
|
+
- Aspect Ratio: ${result.aspectRatio}
|
|
168650
|
+
- FPS: ${result.fps}
|
|
168651
|
+
- Generation Time: ${result.generationTime}ms
|
|
168652
|
+
- Operation ID: ${result.operationId}
|
|
168653
|
+
- Timestamp: ${new Date().toISOString()}${result.filePath ? `
|
|
168654
|
+
|
|
168655
|
+
**File Information:**
|
|
168656
|
+
- File Path: ${result.filePath}
|
|
168657
|
+
- File Name: ${result.fileName}
|
|
168658
|
+
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168659
|
+
- Public URL: ${result.fileUrl}` : ""}`;
|
|
168660
|
+
const formattedResponse = formatMediaResponse({
|
|
168661
|
+
url: result.fileUrl,
|
|
168662
|
+
filePath: result.filePath,
|
|
168663
|
+
mimeType: `video/${result.format}`,
|
|
168664
|
+
size: result.fileSize
|
|
168665
|
+
}, config, contextText);
|
|
168587
168666
|
return {
|
|
168588
|
-
content:
|
|
168589
|
-
{
|
|
168590
|
-
type: "text",
|
|
168591
|
-
text: JSON.stringify({
|
|
168592
|
-
success: true,
|
|
168593
|
-
video: result.filePath ? `File saved to: ${result.filePath}` : result.videoData.substring(0, 100) + "...",
|
|
168594
|
-
format: result.format,
|
|
168595
|
-
model: result.model,
|
|
168596
|
-
prompt,
|
|
168597
|
-
image_input,
|
|
168598
|
-
operation_id: result.operationId,
|
|
168599
|
-
file_info: result.filePath ? {
|
|
168600
|
-
file_path: result.filePath,
|
|
168601
|
-
file_name: result.fileName,
|
|
168602
|
-
file_size: result.fileSize,
|
|
168603
|
-
public_url: result.fileUrl
|
|
168604
|
-
} : null,
|
|
168605
|
-
metadata: {
|
|
168606
|
-
timestamp: new Date().toISOString(),
|
|
168607
|
-
generation_time: result.generationTime,
|
|
168608
|
-
duration: result.duration,
|
|
168609
|
-
aspect_ratio: result.aspectRatio,
|
|
168610
|
-
fps: result.fps,
|
|
168611
|
-
size: result.size
|
|
168612
|
-
}
|
|
168613
|
-
}, null, 2)
|
|
168614
|
-
}
|
|
168615
|
-
],
|
|
168667
|
+
content: formattedResponse,
|
|
168616
168668
|
isError: false
|
|
168617
168669
|
};
|
|
168618
168670
|
}
|
|
@@ -168670,21 +168722,16 @@ async function handleImageEditing(geminiClient, args, config) {
|
|
|
168670
168722
|
filePrefix: `edited-${operation}`
|
|
168671
168723
|
};
|
|
168672
168724
|
const result = await editImage(geminiClient, editingOptions, config);
|
|
168725
|
+
let base64Data;
|
|
168726
|
+
let mimeType;
|
|
168673
168727
|
if (result.editedImageData.startsWith("data:")) {
|
|
168674
168728
|
const matches = result.editedImageData.match(/data:([^;]+);base64,(.+)/);
|
|
168675
168729
|
if (matches && matches[1] && matches[2]) {
|
|
168676
|
-
|
|
168677
|
-
|
|
168678
|
-
|
|
168679
|
-
|
|
168680
|
-
|
|
168681
|
-
type: "image",
|
|
168682
|
-
data: base64Data,
|
|
168683
|
-
mimeType
|
|
168684
|
-
},
|
|
168685
|
-
{
|
|
168686
|
-
type: "text",
|
|
168687
|
-
text: `✅ Image edited successfully using ${operation} operation
|
|
168730
|
+
mimeType = matches[1];
|
|
168731
|
+
base64Data = matches[2];
|
|
168732
|
+
}
|
|
168733
|
+
}
|
|
168734
|
+
const contextText = `✅ Image edited successfully using ${operation} operation
|
|
168688
168735
|
|
|
168689
168736
|
**Editing Details:**
|
|
168690
168737
|
- Operation: ${operation}
|
|
@@ -168705,36 +168752,16 @@ async function handleImageEditing(geminiClient, args, config) {
|
|
|
168705
168752
|
**Operation Metadata:**
|
|
168706
168753
|
- Strength: ${result.metadata.strength}
|
|
168707
168754
|
- Guidance Scale: ${result.metadata.guidanceScale}
|
|
168708
|
-
- Seed: ${result.metadata.seed || "random"}` : ""}
|
|
168709
|
-
|
|
168710
|
-
|
|
168711
|
-
|
|
168712
|
-
|
|
168713
|
-
|
|
168714
|
-
|
|
168755
|
+
- Seed: ${result.metadata.seed || "random"}` : ""}`;
|
|
168756
|
+
const formattedResponse = formatMediaResponse({
|
|
168757
|
+
url: result.fileUrl,
|
|
168758
|
+
filePath: result.filePath,
|
|
168759
|
+
base64: base64Data,
|
|
168760
|
+
mimeType,
|
|
168761
|
+
size: result.fileSize
|
|
168762
|
+
}, config, contextText);
|
|
168715
168763
|
return {
|
|
168716
|
-
content:
|
|
168717
|
-
{
|
|
168718
|
-
type: "text",
|
|
168719
|
-
text: `✅ Image edited successfully!
|
|
168720
|
-
|
|
168721
|
-
**Editing Details:**
|
|
168722
|
-
- Operation: ${operation}
|
|
168723
|
-
- Prompt: "${prompt}"
|
|
168724
|
-
- Format: ${result.format}
|
|
168725
|
-
- Original Size: ${result.originalSize}
|
|
168726
|
-
- Edited Size: ${result.editedSize}
|
|
168727
|
-
- Processing Time: ${result.processingTime}ms${result.filePath ? `
|
|
168728
|
-
|
|
168729
|
-
**File Information:**
|
|
168730
|
-
- File Path: ${result.filePath}
|
|
168731
|
-
- File Name: ${result.fileName}
|
|
168732
|
-
- File Size: ${result.fileSize} bytes` : ""}${result.fileUrl ? `
|
|
168733
|
-
- Public URL: ${result.fileUrl}` : ""}
|
|
168734
|
-
|
|
168735
|
-
**Edited Image Data:** ${result.editedImageData.substring(0, 100)}...`
|
|
168736
|
-
}
|
|
168737
|
-
],
|
|
168764
|
+
content: formattedResponse,
|
|
168738
168765
|
isError: false
|
|
168739
168766
|
};
|
|
168740
168767
|
}
|