@fre4x/gemini 1.0.54 → 1.0.57

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.
Files changed (2) hide show
  1. package/dist/index.js +303 -319
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -46218,6 +46218,34 @@ function getApiKeyFromEnv() {
46218
46218
  }
46219
46219
 
46220
46220
  // ../packages/shared/dist/errors.js
46221
+ function createApiError(message, statusCode) {
46222
+ let hint = "Check your network connection and retry.";
46223
+ let type = "Service Error";
46224
+ if (statusCode === 429) {
46225
+ type = "Rate Limit";
46226
+ hint = "Request volume is too high. Suggestion: Wait briefly before retrying or reduce concurrent calls.";
46227
+ } else if (statusCode === 401 || statusCode === 403) {
46228
+ type = "Authentication Error";
46229
+ hint = "The request could not be authorized. Suggestion: Verify your API key or token in the environment configuration.";
46230
+ } else if (statusCode && statusCode >= 500) {
46231
+ type = "Upstream Error";
46232
+ hint = "The remote service is experiencing temporary issues. Suggestion: Try again in a few minutes.";
46233
+ } else if (statusCode === 404) {
46234
+ type = "Not Found";
46235
+ hint = "The requested information could not be found. Suggestion: Check if the ID, Ticker, or query parameters are correct.";
46236
+ }
46237
+ return {
46238
+ isError: true,
46239
+ content: [
46240
+ {
46241
+ type: "text",
46242
+ text: `${type}: ${message}
46243
+
46244
+ **Next Action**: ${hint}`
46245
+ }
46246
+ ]
46247
+ };
46248
+ }
46221
46249
  function createValidationError(field, message) {
46222
46250
  return {
46223
46251
  isError: true,
@@ -60261,7 +60289,8 @@ config(en_default());
60261
60289
  var zod_default = external_exports;
60262
60290
 
60263
60291
  // ../packages/shared/dist/pagination.js
60264
- var z2 = external_exports || zod_default || zod_exports;
60292
+ var zodCompat = zod_exports;
60293
+ var z2 = zodCompat.z ?? zodCompat.default?.z ?? zodCompat.default ?? zodCompat;
60265
60294
  var paginationSchema = z2.object({
60266
60295
  limit: z2.number().int().min(1).max(100).default(20).describe("Maximum results to return (1\u2013100, default 20)"),
60267
60296
  offset: z2.number().int().min(0).default(0).describe("Number of results to skip for pagination (default 0)")
@@ -67486,11 +67515,12 @@ var StdioServerTransport = class {
67486
67515
  };
67487
67516
 
67488
67517
  // src/index.ts
67489
- var z3 = external_exports || zod_default || zod_exports;
67518
+ var zodCompat2 = zod_exports;
67519
+ var z3 = zodCompat2.z ?? zodCompat2.default?.z ?? zodCompat2.default ?? zodCompat2;
67490
67520
  var IS_MOCK = process.env.GEMINI_MOCK === "true" || process.env.MOCK === "true";
67491
67521
  var PACKAGE_VERSION = getPackageVersion(import.meta.url);
67492
- var DEFAULT_TEXT_MODEL = "gemini-2.5-flash";
67493
- var DEFAULT_IMAGE_MODEL = "imagen-4.0-generate-001";
67522
+ var DEFAULT_TEXT_MODEL = "gemini-2.0-flash";
67523
+ var DEFAULT_IMAGE_MODEL = "imagen-3.0-generate-001";
67494
67524
  var DEFAULT_VIDEO_MODEL = "veo-2.0-generate-001";
67495
67525
  var ALLOWED_MEDIA_MIME_TYPES = /* @__PURE__ */ new Set([
67496
67526
  "image/png",
@@ -67523,9 +67553,7 @@ function getApiKey() {
67523
67553
  }
67524
67554
  function getAi() {
67525
67555
  if (IS_MOCK) {
67526
- throw new Error(
67527
- "AI SDK not initialized. Ensure GEMINI_API_KEY is set and MOCK mode is off."
67528
- );
67556
+ throw new Error("AI SDK not initialized in MOCK mode.");
67529
67557
  }
67530
67558
  if (!ai) {
67531
67559
  ai = new GoogleGenAI({ apiKey: getApiKey() });
@@ -67550,6 +67578,19 @@ function withApiKey(videoUrl) {
67550
67578
  return `${videoUrl}${separator}key=${encodeURIComponent(apiKey)}`;
67551
67579
  }
67552
67580
  }
67581
+ function getErrorMessage(error48) {
67582
+ return error48 instanceof Error ? error48.message : String(error48);
67583
+ }
67584
+ function withStatusCode(error48, statusCode) {
67585
+ return Object.assign(error48, { statusCode });
67586
+ }
67587
+ function isErrorWithStatusCode(error48) {
67588
+ if (!(error48 instanceof Error)) {
67589
+ return false;
67590
+ }
67591
+ const statusCode = Reflect.get(error48, "statusCode");
67592
+ return typeof statusCode === "number";
67593
+ }
67553
67594
  var FILE_EXT_TO_MIME = {
67554
67595
  ".png": "image/png",
67555
67596
  ".jpg": "image/jpeg",
@@ -67568,127 +67609,91 @@ var FILE_EXT_TO_MIME = {
67568
67609
  ".mov": "video/quicktime",
67569
67610
  ".pdf": "application/pdf"
67570
67611
  };
67612
+ var AnalyzeMediaOutputSchema = z3.object({
67613
+ analysis: z3.string(),
67614
+ source: z3.string(),
67615
+ mimeType: z3.string(),
67616
+ savedPath: z3.string().optional()
67617
+ });
67618
+ var ListModelsOutputSchema = z3.object({
67619
+ imageModels: z3.array(z3.string()),
67620
+ videoModels: z3.array(z3.string())
67621
+ });
67622
+ var GenerateImageOutputSchema = z3.object({
67623
+ images: z3.array(
67624
+ z3.object({
67625
+ data: z3.string(),
67626
+ mimeType: z3.string(),
67627
+ savedPath: z3.string().optional()
67628
+ })
67629
+ ),
67630
+ prompt: z3.string()
67631
+ });
67632
+ var GenerateVideoOutputSchema = z3.object({
67633
+ operationName: z3.string(),
67634
+ prompt: z3.string(),
67635
+ status: z3.string()
67636
+ });
67637
+ var VideoStatusOutputSchema = z3.object({
67638
+ done: z3.boolean(),
67639
+ videos: z3.array(
67640
+ z3.object({
67641
+ url: z3.string(),
67642
+ savedPath: z3.string().optional()
67643
+ })
67644
+ ),
67645
+ error: z3.string().optional()
67646
+ });
67571
67647
  var ANALYZE_MEDIA_TOOL = {
67572
67648
  name: "analyze_media",
67573
67649
  description: "Analyze an image or audio file from a URL or file path.",
67574
- inputSchema: {
67575
- type: "object",
67576
- additionalProperties: false,
67577
- properties: {
67578
- prompt: {
67579
- type: "string",
67580
- description: "Optional question or instruction for the media."
67581
- },
67582
- media_source: {
67583
- type: "string",
67584
- minLength: 1,
67585
- description: "URL, file:// path, or local file path."
67586
- },
67587
- mime_type: {
67588
- type: "string",
67589
- description: "Optional MIME type override."
67590
- },
67591
- model: {
67592
- type: "string",
67593
- default: DEFAULT_TEXT_MODEL,
67594
- description: "Gemini model to use for analysis."
67595
- },
67596
- output_dir: {
67597
- type: "string",
67598
- description: "Optional directory to save the analysis result as a .txt file."
67599
- }
67600
- },
67601
- required: ["media_source"]
67602
- }
67650
+ inputSchema: z3.object({
67651
+ prompt: z3.string().min(1).default("Describe this media.").describe("Optional question or instruction for the media."),
67652
+ media_source: z3.string().min(1).describe("URL, file:// path, or local file path."),
67653
+ mime_type: z3.string().optional().describe("Optional MIME type override."),
67654
+ model: z3.string().optional().default(DEFAULT_TEXT_MODEL).describe("Gemini model to use for analysis."),
67655
+ output_dir: z3.string().optional().describe(
67656
+ "Optional directory to save the analysis result as a .txt file."
67657
+ )
67658
+ }).strict(),
67659
+ outputSchema: AnalyzeMediaOutputSchema
67603
67660
  };
67604
67661
  var LIST_MODELS_TOOL = {
67605
67662
  name: "list_models",
67606
67663
  description: "List available Gemini image and video models.",
67607
- inputSchema: {
67608
- type: "object",
67609
- additionalProperties: false,
67610
- properties: {
67611
- capability: {
67612
- type: "string",
67613
- description: "Filter by capability: image, video, or all.",
67614
- enum: ["all", "image", "video"],
67615
- default: "all"
67616
- }
67617
- },
67618
- required: []
67619
- }
67664
+ inputSchema: z3.object({
67665
+ capability: z3.enum(["all", "image", "video"]).default("all").describe("Filter by capability: image, video, or all.")
67666
+ }).strict(),
67667
+ outputSchema: ListModelsOutputSchema
67620
67668
  };
67621
67669
  var GENERATE_IMAGE_TOOL = {
67622
67670
  name: "generate_image",
67623
67671
  description: "Generate an image using Imagen and optionally save it to disk.",
67624
- inputSchema: {
67625
- type: "object",
67626
- additionalProperties: false,
67627
- properties: {
67628
- prompt: {
67629
- type: "string",
67630
- minLength: 1,
67631
- description: "Description of the image to generate."
67632
- },
67633
- aspect_ratio: {
67634
- type: "string",
67635
- enum: ["1:1", "16:9", "9:16"],
67636
- default: "1:1",
67637
- description: "Aspect ratio for the image."
67638
- },
67639
- model: {
67640
- type: "string",
67641
- default: DEFAULT_IMAGE_MODEL,
67642
- description: "Imagen model to use."
67643
- },
67644
- output_dir: {
67645
- type: "string",
67646
- description: "Directory to save the image file."
67647
- }
67648
- },
67649
- required: ["prompt"]
67650
- }
67672
+ inputSchema: z3.object({
67673
+ prompt: z3.string().min(1).describe("Description of the image to generate."),
67674
+ aspect_ratio: z3.enum(["1:1", "16:9", "9:16"]).default("1:1").describe("Aspect ratio for the image."),
67675
+ model: z3.string().default(DEFAULT_IMAGE_MODEL).describe("Imagen model to use."),
67676
+ output_dir: z3.string().optional().describe("Directory to save the image file.")
67677
+ }).strict(),
67678
+ outputSchema: GenerateImageOutputSchema
67651
67679
  };
67652
67680
  var GENERATE_VIDEO_TOOL = {
67653
67681
  name: "generate_video",
67654
67682
  description: "Start an async video generation request using Veo.",
67655
- inputSchema: {
67656
- type: "object",
67657
- additionalProperties: false,
67658
- properties: {
67659
- prompt: {
67660
- type: "string",
67661
- minLength: 1,
67662
- description: "Description of the video to generate."
67663
- },
67664
- model: {
67665
- type: "string",
67666
- default: DEFAULT_VIDEO_MODEL,
67667
- description: "Veo model to use."
67668
- }
67669
- },
67670
- required: ["prompt"]
67671
- }
67683
+ inputSchema: z3.object({
67684
+ prompt: z3.string().min(1).describe("Description of the video to generate."),
67685
+ model: z3.string().default(DEFAULT_VIDEO_MODEL).describe("Veo model to use.")
67686
+ }).strict(),
67687
+ outputSchema: GenerateVideoOutputSchema
67672
67688
  };
67673
67689
  var GET_VIDEO_STATUS_TOOL = {
67674
67690
  name: "get_video_status",
67675
67691
  description: "Check the status of a video generation request.",
67676
- inputSchema: {
67677
- type: "object",
67678
- additionalProperties: false,
67679
- properties: {
67680
- operation_name: {
67681
- type: "string",
67682
- minLength: 1,
67683
- description: "Operation name returned by generate_video."
67684
- },
67685
- output_dir: {
67686
- type: "string",
67687
- description: "Directory to save the completed video file."
67688
- }
67689
- },
67690
- required: ["operation_name"]
67691
- }
67692
+ inputSchema: z3.object({
67693
+ operation_name: z3.string().min(1).describe("Operation name returned by generate_video."),
67694
+ output_dir: z3.string().optional().describe("Directory to save the completed video file.")
67695
+ }).strict(),
67696
+ outputSchema: VideoStatusOutputSchema
67692
67697
  };
67693
67698
  var TOOL_DEFINITIONS = [
67694
67699
  ANALYZE_MEDIA_TOOL,
@@ -67717,8 +67722,9 @@ async function resolveMediaSource(mediaSource, mimeTypeOverride) {
67717
67722
  if (mediaSource.startsWith("http://") || mediaSource.startsWith("https://")) {
67718
67723
  const response = await fetch(mediaSource);
67719
67724
  if (!response.ok) {
67720
- throw new Error(
67721
- `Failed to fetch media source: ${response.status} ${response.statusText}`
67725
+ throw withStatusCode(
67726
+ new Error("Failed to fetch media source."),
67727
+ response.status
67722
67728
  );
67723
67729
  }
67724
67730
  const mimeType2 = mimeTypeOverride || response.headers.get("content-type")?.split(";")[0]?.trim() || inferredMimeType;
@@ -67754,54 +67760,25 @@ async function resolveMediaSource(mediaSource, mimeTypeOverride) {
67754
67760
  label: mediaSource.startsWith("file://") ? mediaSource : `file://${filePath}`
67755
67761
  };
67756
67762
  }
67757
- function validationError(field, message) {
67758
- return createValidationError(field, message);
67759
- }
67760
- function parseArgs(schema, args) {
67761
- const parsed = schema.safeParse(args ?? {});
67762
- if (!parsed.success) {
67763
- const issue2 = parsed.error.issues[0];
67764
- return {
67765
- success: false,
67766
- error: validationError(
67767
- issue2?.path.length ? issue2.path.join(".") : "arguments",
67768
- issue2?.message ?? parsed.error.message
67769
- )
67770
- };
67771
- }
67772
- return { success: true, data: parsed.data };
67773
- }
67774
- function textResult(text) {
67763
+ function textResult(text, structuredContent) {
67775
67764
  return {
67776
- content: [{ type: "text", text }]
67765
+ content: [{ type: "text", text }],
67766
+ structuredContent
67777
67767
  };
67778
67768
  }
67779
67769
  function formatModelLines(models, title) {
67780
67770
  return [title, ...models.map((model) => `- ${model}`), ""];
67781
67771
  }
67782
- async function analyzeMedia(rawArgs) {
67783
- const parsed = parseArgs(
67784
- z3.object({
67785
- prompt: z3.string().min(1).default("Describe this media."),
67786
- media_source: z3.string().min(1),
67787
- mime_type: z3.string().optional(),
67788
- model: z3.string().optional().default(DEFAULT_TEXT_MODEL),
67789
- output_dir: z3.string().optional()
67790
- }).strict(),
67791
- rawArgs
67792
- );
67793
- if (!parsed.success) {
67794
- return parsed.error;
67795
- }
67796
- const { prompt, media_source, mime_type, model, output_dir } = parsed.data;
67772
+ async function analyzeMedia(args) {
67773
+ const { prompt, media_source, mime_type, model, output_dir } = args;
67797
67774
  let media;
67798
67775
  try {
67799
67776
  media = await resolveMediaSource(media_source, mime_type);
67800
67777
  } catch (error48) {
67801
- return createValidationError(
67802
- "media_source",
67803
- error48 instanceof Error ? error48.message : String(error48)
67804
- );
67778
+ if (isErrorWithStatusCode(error48)) {
67779
+ return createApiError(error48.message, error48.statusCode);
67780
+ }
67781
+ return createValidationError("media_source", getErrorMessage(error48));
67805
67782
  }
67806
67783
  let responseText;
67807
67784
  if (IS_MOCK) {
@@ -67813,7 +67790,7 @@ Model: ${model}
67813
67790
  Mock response \u2014 no API call made.`;
67814
67791
  } else {
67815
67792
  const response = await getAi().models.generateContent({
67816
- model,
67793
+ model: model || DEFAULT_TEXT_MODEL,
67817
67794
  contents: [
67818
67795
  {
67819
67796
  role: "user",
@@ -67831,68 +67808,70 @@ Mock response \u2014 no API call made.`;
67831
67808
  });
67832
67809
  responseText = response.text || "No analysis generated.";
67833
67810
  }
67811
+ let savedPath;
67834
67812
  if (output_dir) {
67835
67813
  try {
67836
67814
  const fname = `analysis-${Date.now()}.txt`;
67837
- const fpath = path2.join(output_dir, fname);
67815
+ savedPath = path2.join(output_dir, fname);
67838
67816
  await fs3.mkdir(output_dir, { recursive: true });
67839
- await fs3.writeFile(fpath, responseText);
67840
- return textResult(
67841
- `${responseText}
67842
-
67843
- \u2705 Analysis result saved to: ${fpath}`
67844
- );
67817
+ await fs3.writeFile(savedPath, responseText);
67845
67818
  } catch (error48) {
67846
67819
  return textResult(
67847
67820
  `${responseText}
67848
67821
 
67849
- \u26A0\uFE0F Failed to save analysis result: ${error48.message}`
67822
+ \u26A0\uFE0F Failed to save analysis result: ${getErrorMessage(error48)}`,
67823
+ {
67824
+ analysis: responseText,
67825
+ source: media.label,
67826
+ mimeType: media.mimeType
67827
+ }
67850
67828
  );
67851
67829
  }
67852
67830
  }
67853
- return textResult(responseText);
67854
- }
67855
- async function listModels(rawArgs) {
67856
- const parsed = parseArgs(
67857
- z3.object({
67858
- capability: z3.enum(["all", "image", "video"]).default("all")
67859
- }).strict(),
67860
- rawArgs
67831
+ return textResult(
67832
+ savedPath ? `${responseText}
67833
+
67834
+ \u2705 Analysis result saved to: ${savedPath}` : responseText,
67835
+ {
67836
+ analysis: responseText,
67837
+ source: media.label,
67838
+ mimeType: media.mimeType,
67839
+ savedPath
67840
+ }
67861
67841
  );
67862
- if (!parsed.success) {
67863
- return parsed.error;
67864
- }
67865
- const { capability } = parsed.data;
67842
+ }
67843
+ async function listModels(args) {
67844
+ const { capability } = args;
67866
67845
  if (IS_MOCK) {
67846
+ const imageModels2 = [
67847
+ DEFAULT_IMAGE_MODEL,
67848
+ "imagen-3.0-ultra-generate-001",
67849
+ "imagen-3.0-fast-generate-001"
67850
+ ];
67851
+ const videoModels2 = [DEFAULT_VIDEO_MODEL];
67867
67852
  const lines2 = ["## Available Gemini Models", ""];
67868
67853
  if (capability === "all" || capability === "image") {
67869
67854
  lines2.push(
67870
- ...formatModelLines(
67871
- [
67872
- `${DEFAULT_IMAGE_MODEL} \u2B50 (recommended default)`,
67873
- "imagen-4.0-ultra-generate-001 (highest quality)",
67874
- "imagen-4.0-fast-generate-001 (fastest)"
67875
- ],
67876
- "### \u{1F5BC}\uFE0F Image Generation"
67877
- )
67855
+ ...formatModelLines(imageModels2, "### \u{1F5BC}\uFE0F Image Generation")
67878
67856
  );
67879
67857
  }
67880
67858
  if (capability === "all" || capability === "video") {
67881
67859
  lines2.push(
67882
- ...formatModelLines(
67883
- [DEFAULT_VIDEO_MODEL],
67884
- "### \u{1F3AC} Video Generation"
67885
- )
67860
+ ...formatModelLines(videoModels2, "### \u{1F3AC} Video Generation")
67886
67861
  );
67887
67862
  }
67888
- return textResult(lines2.join("\n").trim());
67863
+ return textResult(lines2.join("\n").trim(), {
67864
+ imageModels: capability === "video" ? [] : imageModels2,
67865
+ videoModels: capability === "image" ? [] : videoModels2
67866
+ });
67889
67867
  }
67890
67868
  const resp = await fetch(
67891
67869
  `https://generativelanguage.googleapis.com/v1beta/models?key=${getApiKey()}&pageSize=200`
67892
67870
  );
67893
67871
  if (!resp.ok) {
67894
- throw new Error(
67895
- `Failed to list models: ${resp.status} ${resp.statusText}`
67872
+ return createApiError(
67873
+ "The model listing service is unavailable.",
67874
+ resp.status
67896
67875
  );
67897
67876
  }
67898
67877
  const data = await resp.json();
@@ -67909,57 +67888,70 @@ async function listModels(rawArgs) {
67909
67888
  if (capability === "all" || capability === "video") {
67910
67889
  lines.push(...formatModelLines(videoModels, "### \u{1F3AC} Video Generation"));
67911
67890
  }
67912
- return textResult(lines.join("\n").trim() || "No models found.");
67891
+ return textResult(lines.join("\n").trim() || "No models found.", {
67892
+ imageModels: capability === "video" ? [] : imageModels,
67893
+ videoModels: capability === "image" ? [] : videoModels
67894
+ });
67913
67895
  }
67914
- async function generateImage(rawArgs) {
67915
- const parsed = parseArgs(
67916
- z3.object({
67917
- prompt: z3.string().min(1),
67918
- aspect_ratio: z3.enum(["1:1", "16:9", "9:16"]).default("1:1"),
67919
- model: z3.string().default(DEFAULT_IMAGE_MODEL),
67920
- output_dir: z3.string().optional()
67921
- }).strict(),
67922
- rawArgs
67923
- );
67924
- if (!parsed.success) {
67925
- return parsed.error;
67926
- }
67927
- const { prompt, aspect_ratio, model, output_dir } = parsed.data;
67896
+ async function generateImage(args) {
67897
+ const { prompt, aspect_ratio, model, output_dir } = args;
67928
67898
  if (IS_MOCK) {
67929
67899
  const mockBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
67930
- const content2 = [
67931
- {
67932
- type: "text",
67933
- text: `\u2705 Image generated successfully (1 image, prompt: "${prompt}").`
67934
- },
67935
- { type: "image", data: mockBase64, mimeType: "image/png" }
67936
- ];
67900
+ let savedPath;
67937
67901
  if (output_dir) {
67938
67902
  try {
67939
67903
  const fname = `image-${Date.now()}.png`;
67940
- const fpath = path2.join(output_dir, fname);
67904
+ savedPath = path2.join(output_dir, fname);
67941
67905
  await fs3.mkdir(output_dir, { recursive: true });
67942
- await fs3.writeFile(fpath, Buffer.from(mockBase64, "base64"));
67943
- content2.push({
67944
- type: "text",
67945
- text: `[Mock] Saved to: ${fpath}`
67946
- });
67906
+ await fs3.writeFile(
67907
+ savedPath,
67908
+ Buffer.from(mockBase64, "base64")
67909
+ );
67947
67910
  } catch (error48) {
67948
- content2.push({
67949
- type: "text",
67950
- text: `\u26A0\uFE0F [Mock] Failed to save image: ${error48.message}`
67951
- });
67911
+ return {
67912
+ content: [
67913
+ {
67914
+ type: "text",
67915
+ text: `\u2705 Image generated successfully.
67916
+
67917
+ \u26A0\uFE0F Failed to save image: ${getErrorMessage(error48)}`
67918
+ },
67919
+ {
67920
+ type: "image",
67921
+ data: mockBase64,
67922
+ mimeType: "image/png"
67923
+ }
67924
+ ],
67925
+ structuredContent: {
67926
+ images: [{ data: mockBase64, mimeType: "image/png" }],
67927
+ prompt
67928
+ }
67929
+ };
67952
67930
  }
67953
67931
  }
67954
- return { content: content2 };
67932
+ return {
67933
+ content: [
67934
+ {
67935
+ type: "text",
67936
+ text: `\u2705 Image generated successfully.${savedPath ? `
67937
+ Saved to: ${savedPath}` : ""}`
67938
+ },
67939
+ { type: "image", data: mockBase64, mimeType: "image/png" }
67940
+ ],
67941
+ structuredContent: {
67942
+ images: [
67943
+ { data: mockBase64, mimeType: "image/png", savedPath }
67944
+ ],
67945
+ prompt
67946
+ }
67947
+ };
67955
67948
  }
67956
67949
  const response = await getAi().models.generateImages({
67957
- model,
67950
+ model: model || DEFAULT_IMAGE_MODEL,
67958
67951
  prompt,
67959
67952
  config: { numberOfImages: 1, aspectRatio: aspect_ratio }
67960
67953
  });
67961
67954
  const images = (response.generatedImages ?? []).map((img) => ({
67962
- type: "image",
67963
67955
  data: img.image?.imageBytes ?? "",
67964
67956
  mimeType: "image/png"
67965
67957
  }));
@@ -67968,108 +67960,75 @@ async function generateImage(rawArgs) {
67968
67960
  content: [
67969
67961
  {
67970
67962
  type: "text",
67971
- text: `Image generation returned no results. Possible reasons:
67972
- - Content policy violation in prompt
67973
- - Model unavailable (${model}) in your region/API tier
67974
- - Prompt unsupported or aspect ratio invalid (${aspect_ratio})
67975
-
67976
- Check Imagen access at https://ai.google.dev/`
67963
+ text: `Image generation returned no results. Check Imagen access and policies.`
67977
67964
  }
67978
67965
  ],
67979
67966
  isError: true
67980
67967
  };
67981
67968
  }
67982
- const savedPaths = [];
67983
- let saveErrorText = "";
67969
+ const savedImages = [];
67984
67970
  if (output_dir) {
67985
67971
  try {
67986
67972
  await fs3.mkdir(output_dir, { recursive: true });
67987
- const paths = await Promise.all(
67988
- images.map(async (img, index) => {
67989
- const fname = `image-${Date.now()}-${index + 1}.png`;
67990
- const fpath = path2.join(output_dir, fname);
67991
- await fs3.writeFile(fpath, Buffer.from(img.data, "base64"));
67992
- return fpath;
67993
- })
67994
- );
67995
- savedPaths.push(...paths);
67973
+ for (const [index, img] of images.entries()) {
67974
+ const fname = `image-${Date.now()}-${index + 1}.png`;
67975
+ const fpath = path2.join(output_dir, fname);
67976
+ await fs3.writeFile(fpath, Buffer.from(img.data, "base64"));
67977
+ savedImages.push({ ...img, savedPath: fpath });
67978
+ }
67996
67979
  } catch (error48) {
67997
- saveErrorText = `
67998
-
67999
- \u26A0\uFE0F Failed to save images: ${error48.message}`;
67980
+ console.error(`Failed to save images: ${getErrorMessage(error48)}`);
67981
+ savedImages.push(...images);
68000
67982
  }
67983
+ } else {
67984
+ savedImages.push(...images);
68001
67985
  }
67986
+ const savedPaths = savedImages.map((img) => img.savedPath).filter(Boolean);
68002
67987
  const content = [
68003
67988
  {
68004
67989
  type: "text",
68005
- text: `\u2705 Image generated successfully (${images.length} image${images.length > 1 ? "s" : ""}, prompt: "${prompt}").${savedPaths.length > 0 ? `
67990
+ text: `\u2705 Image generated successfully.${savedPaths.length > 0 ? `
68006
67991
  Saved to:
68007
- ${savedPaths.join("\n")}` : ""}${saveErrorText}`
67992
+ ${savedPaths.join("\n")}` : ""}`
68008
67993
  },
68009
- ...images
67994
+ ...savedImages.map((img) => ({
67995
+ type: "image",
67996
+ data: img.data,
67997
+ mimeType: img.mimeType
67998
+ }))
68010
67999
  ];
68011
- return { content };
68000
+ return { content, structuredContent: { images: savedImages, prompt } };
68012
68001
  }
68013
- async function generateVideo(rawArgs) {
68014
- const parsed = parseArgs(
68015
- z3.object({
68016
- prompt: z3.string().min(1),
68017
- model: z3.string().default(DEFAULT_VIDEO_MODEL)
68018
- }).strict(),
68019
- rawArgs
68020
- );
68021
- if (!parsed.success) {
68022
- return parsed.error;
68023
- }
68024
- const { prompt, model } = parsed.data;
68002
+ async function generateVideo(args) {
68003
+ const { prompt, model } = args;
68025
68004
  if (IS_MOCK) {
68026
- return {
68027
- content: [
68028
- {
68029
- type: "text",
68030
- text: `[Mock] Video generation started.
68031
- Operation name: mock-operations/123456
68032
- Model: ${model}
68005
+ const opName2 = "mock-operations/123456";
68006
+ return textResult(
68007
+ `[Mock] Video generation started.
68033
68008
 
68034
- Call get_video_status with operation_name="mock-operations/123456" to check progress.`
68035
- }
68036
- ]
68037
- };
68009
+ Operation name: ${opName2}
68010
+
68011
+ Call get_video_status to check progress.`,
68012
+ { operationName: opName2, prompt, status: "queued" }
68013
+ );
68038
68014
  }
68039
68015
  const operation = await getAi().models.generateVideos({
68040
- model,
68016
+ model: model || DEFAULT_VIDEO_MODEL,
68041
68017
  prompt,
68042
68018
  config: { numberOfVideos: 1 }
68043
68019
  });
68044
68020
  const opName = operation.name ?? "unknown";
68045
- return {
68046
- content: [
68047
- {
68048
- type: "text",
68049
- text: `Video generation started (async \u2014 typically takes 2\u20135 minutes).
68021
+ return textResult(
68022
+ `Video generation started.
68050
68023
 
68051
68024
  Operation name: ${opName}
68052
68025
 
68053
- Call get_video_status with:
68054
- operation_name="${opName}"
68055
-
68056
- Poll every ~30 seconds until done=true.`
68057
- }
68058
- ]
68059
- };
68060
- }
68061
- async function getVideoStatus(rawArgs) {
68062
- const parsed = parseArgs(
68063
- z3.object({
68064
- operation_name: z3.string().min(1),
68065
- output_dir: z3.string().optional()
68066
- }).strict(),
68067
- rawArgs
68026
+ Call get_video_status every ~30s until complete.`,
68027
+ { operationName: opName, prompt, status: "started" }
68068
68028
  );
68069
- if ("error" in parsed) {
68070
- return parsed.error;
68071
- }
68072
- const { operation_name, output_dir } = parsed.data;
68029
+ }
68030
+ async function getVideoStatus(args) {
68031
+ const { operation_name, output_dir } = args;
68073
68032
  let op;
68074
68033
  if (IS_MOCK) {
68075
68034
  op = {
@@ -68087,7 +68046,8 @@ async function getVideoStatus(rawArgs) {
68087
68046
  }
68088
68047
  if (!op.done) {
68089
68048
  return textResult(
68090
- `Operation ${operation_name} is still in progress. Check back in ~30 seconds.`
68049
+ `Operation ${operation_name} is still in progress. Check back in ~30 seconds.`,
68050
+ { done: false, videos: [] }
68091
68051
  );
68092
68052
  }
68093
68053
  if (op.error) {
@@ -68095,20 +68055,30 @@ async function getVideoStatus(rawArgs) {
68095
68055
  content: [
68096
68056
  {
68097
68057
  type: "text",
68098
- text: `Video generation failed: ${op.error.message ?? JSON.stringify(op.error)}`
68058
+ text: `Video generation failed: ${op.error.message || "Unknown upstream error"}`
68099
68059
  }
68100
68060
  ],
68061
+ structuredContent: {
68062
+ done: true,
68063
+ error: op.error.message,
68064
+ videos: []
68065
+ },
68101
68066
  isError: true
68102
68067
  };
68103
68068
  }
68104
- const videos = (op.response?.generatedVideos ?? []).map((v) => v.video?.uri ?? "").filter(Boolean);
68069
+ const videos = (op.response?.generatedVideos ?? []).map((video) => video.video?.uri ?? "").filter(Boolean);
68105
68070
  if (videos.length === 0) {
68106
- return textResult(
68107
- `Complete but no video URLs found:
68108
- ${JSON.stringify(op.response, null, 2)}`
68109
- );
68071
+ return {
68072
+ content: [
68073
+ {
68074
+ type: "text",
68075
+ text: "Operation complete but no video URLs found."
68076
+ }
68077
+ ],
68078
+ structuredContent: { done: true, videos: [] }
68079
+ };
68110
68080
  }
68111
- const savedPaths = [];
68081
+ const videoResults = [];
68112
68082
  const videoContents = [];
68113
68083
  await Promise.all(
68114
68084
  videos.map(async (url2, index) => {
@@ -68118,9 +68088,7 @@ ${JSON.stringify(op.response, null, 2)}`
68118
68088
  } else {
68119
68089
  const videoResp = await fetch(withApiKey(url2));
68120
68090
  if (!videoResp.ok) {
68121
- throw new Error(
68122
- `Failed to download video: ${videoResp.status}`
68123
- );
68091
+ throw new Error(`Failed to download video.`);
68124
68092
  }
68125
68093
  const arrayBuffer = await videoResp.arrayBuffer();
68126
68094
  buffer = Buffer.from(arrayBuffer);
@@ -68133,53 +68101,66 @@ ${JSON.stringify(op.response, null, 2)}`
68133
68101
  blob: buffer.toString("base64")
68134
68102
  }
68135
68103
  });
68104
+ let savedPath;
68136
68105
  if (output_dir) {
68137
68106
  try {
68138
68107
  const fname = `video-${Date.now()}-${index + 1}.mp4`;
68139
- const fpath = path2.join(output_dir, fname);
68108
+ savedPath = path2.join(output_dir, fname);
68140
68109
  await fs3.mkdir(output_dir, { recursive: true });
68141
- await fs3.writeFile(fpath, buffer);
68142
- savedPaths.push(fpath);
68110
+ await fs3.writeFile(savedPath, buffer);
68143
68111
  } catch (error48) {
68144
- console.error(`Failed to save video: ${error48.message}`);
68112
+ console.error(
68113
+ `Failed to save video: ${getErrorMessage(error48)}`
68114
+ );
68145
68115
  }
68146
68116
  }
68117
+ videoResults.push({ url: url2, savedPath });
68147
68118
  })
68148
68119
  );
68149
- const lines = [
68120
+ const savedPaths = videoResults.map((v) => v.savedPath).filter(Boolean);
68121
+ const summaryLines = [
68150
68122
  `Video generation complete!
68151
68123
 
68152
68124
  Download URLs:
68153
68125
  ${videos.join("\n")}`
68154
68126
  ];
68155
68127
  if (savedPaths.length > 0) {
68156
- lines.push(`
68128
+ summaryLines.push(`
68129
+
68157
68130
  Saved to:
68158
68131
  ${savedPaths.join("\n")}`);
68159
- } else if (output_dir) {
68160
- lines.push(`
68161
- \u26A0\uFE0F Failed to save videos to disk.`);
68162
68132
  }
68163
68133
  return {
68164
68134
  content: [
68165
- { type: "text", text: lines.join("") },
68135
+ { type: "text", text: summaryLines.join("") },
68166
68136
  ...videoContents
68167
- ]
68137
+ ],
68138
+ structuredContent: { done: true, videos: videoResults }
68168
68139
  };
68169
68140
  }
68170
68141
  async function handleToolCall(name, args) {
68171
68142
  try {
68172
68143
  switch (name) {
68173
68144
  case "analyze_media":
68174
- return await analyzeMedia(args);
68145
+ return await analyzeMedia(
68146
+ ANALYZE_MEDIA_TOOL.inputSchema.parse(args)
68147
+ );
68175
68148
  case "list_models":
68176
- return await listModels(args);
68149
+ return await listModels(
68150
+ LIST_MODELS_TOOL.inputSchema.parse(args)
68151
+ );
68177
68152
  case "generate_image":
68178
- return await generateImage(args);
68153
+ return await generateImage(
68154
+ GENERATE_IMAGE_TOOL.inputSchema.parse(args)
68155
+ );
68179
68156
  case "generate_video":
68180
- return await generateVideo(args);
68157
+ return await generateVideo(
68158
+ GENERATE_VIDEO_TOOL.inputSchema.parse(args)
68159
+ );
68181
68160
  case "get_video_status":
68182
- return await getVideoStatus(args);
68161
+ return await getVideoStatus(
68162
+ GET_VIDEO_STATUS_TOOL.inputSchema.parse(args)
68163
+ );
68183
68164
  default:
68184
68165
  throw new Error(`Tool not found: ${name}`);
68185
68166
  }
@@ -68190,6 +68171,9 @@ async function handleToolCall(name, args) {
68190
68171
  error48.issues[0]?.message || error48.message
68191
68172
  );
68192
68173
  }
68174
+ if (isErrorWithStatusCode(error48)) {
68175
+ return createApiError(error48.message, error48.statusCode);
68176
+ }
68193
68177
  return createInternalError(error48);
68194
68178
  }
68195
68179
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fre4x/gemini",
3
- "version": "1.0.54",
3
+ "version": "1.0.57",
4
4
  "description": "A Gemini MCP server providing multimodal analysis and image/video generation.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",