@fre4x/gemini 1.0.55 → 1.0.58

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 +296 -317
  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() });
@@ -67553,6 +67581,16 @@ function withApiKey(videoUrl) {
67553
67581
  function getErrorMessage(error48) {
67554
67582
  return error48 instanceof Error ? error48.message : String(error48);
67555
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
+ }
67556
67594
  var FILE_EXT_TO_MIME = {
67557
67595
  ".png": "image/png",
67558
67596
  ".jpg": "image/jpeg",
@@ -67571,127 +67609,91 @@ var FILE_EXT_TO_MIME = {
67571
67609
  ".mov": "video/quicktime",
67572
67610
  ".pdf": "application/pdf"
67573
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
+ });
67574
67647
  var ANALYZE_MEDIA_TOOL = {
67575
67648
  name: "analyze_media",
67576
67649
  description: "Analyze an image or audio file from a URL or file path.",
67577
- inputSchema: {
67578
- type: "object",
67579
- additionalProperties: false,
67580
- properties: {
67581
- prompt: {
67582
- type: "string",
67583
- description: "Optional question or instruction for the media."
67584
- },
67585
- media_source: {
67586
- type: "string",
67587
- minLength: 1,
67588
- description: "URL, file:// path, or local file path."
67589
- },
67590
- mime_type: {
67591
- type: "string",
67592
- description: "Optional MIME type override."
67593
- },
67594
- model: {
67595
- type: "string",
67596
- default: DEFAULT_TEXT_MODEL,
67597
- description: "Gemini model to use for analysis."
67598
- },
67599
- output_dir: {
67600
- type: "string",
67601
- description: "Optional directory to save the analysis result as a .txt file."
67602
- }
67603
- },
67604
- required: ["media_source"]
67605
- }
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
67606
67660
  };
67607
67661
  var LIST_MODELS_TOOL = {
67608
67662
  name: "list_models",
67609
67663
  description: "List available Gemini image and video models.",
67610
- inputSchema: {
67611
- type: "object",
67612
- additionalProperties: false,
67613
- properties: {
67614
- capability: {
67615
- type: "string",
67616
- description: "Filter by capability: image, video, or all.",
67617
- enum: ["all", "image", "video"],
67618
- default: "all"
67619
- }
67620
- },
67621
- required: []
67622
- }
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
67623
67668
  };
67624
67669
  var GENERATE_IMAGE_TOOL = {
67625
67670
  name: "generate_image",
67626
67671
  description: "Generate an image using Imagen and optionally save it to disk.",
67627
- inputSchema: {
67628
- type: "object",
67629
- additionalProperties: false,
67630
- properties: {
67631
- prompt: {
67632
- type: "string",
67633
- minLength: 1,
67634
- description: "Description of the image to generate."
67635
- },
67636
- aspect_ratio: {
67637
- type: "string",
67638
- enum: ["1:1", "16:9", "9:16"],
67639
- default: "1:1",
67640
- description: "Aspect ratio for the image."
67641
- },
67642
- model: {
67643
- type: "string",
67644
- default: DEFAULT_IMAGE_MODEL,
67645
- description: "Imagen model to use."
67646
- },
67647
- output_dir: {
67648
- type: "string",
67649
- description: "Directory to save the image file."
67650
- }
67651
- },
67652
- required: ["prompt"]
67653
- }
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
67654
67679
  };
67655
67680
  var GENERATE_VIDEO_TOOL = {
67656
67681
  name: "generate_video",
67657
67682
  description: "Start an async video generation request using Veo.",
67658
- inputSchema: {
67659
- type: "object",
67660
- additionalProperties: false,
67661
- properties: {
67662
- prompt: {
67663
- type: "string",
67664
- minLength: 1,
67665
- description: "Description of the video to generate."
67666
- },
67667
- model: {
67668
- type: "string",
67669
- default: DEFAULT_VIDEO_MODEL,
67670
- description: "Veo model to use."
67671
- }
67672
- },
67673
- required: ["prompt"]
67674
- }
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
67675
67688
  };
67676
67689
  var GET_VIDEO_STATUS_TOOL = {
67677
67690
  name: "get_video_status",
67678
67691
  description: "Check the status of a video generation request.",
67679
- inputSchema: {
67680
- type: "object",
67681
- additionalProperties: false,
67682
- properties: {
67683
- operation_name: {
67684
- type: "string",
67685
- minLength: 1,
67686
- description: "Operation name returned by generate_video."
67687
- },
67688
- output_dir: {
67689
- type: "string",
67690
- description: "Directory to save the completed video file."
67691
- }
67692
- },
67693
- required: ["operation_name"]
67694
- }
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
67695
67697
  };
67696
67698
  var TOOL_DEFINITIONS = [
67697
67699
  ANALYZE_MEDIA_TOOL,
@@ -67720,8 +67722,9 @@ async function resolveMediaSource(mediaSource, mimeTypeOverride) {
67720
67722
  if (mediaSource.startsWith("http://") || mediaSource.startsWith("https://")) {
67721
67723
  const response = await fetch(mediaSource);
67722
67724
  if (!response.ok) {
67723
- throw new Error(
67724
- `Failed to fetch media source: ${response.status} ${response.statusText}`
67725
+ throw withStatusCode(
67726
+ new Error("Failed to fetch media source."),
67727
+ response.status
67725
67728
  );
67726
67729
  }
67727
67730
  const mimeType2 = mimeTypeOverride || response.headers.get("content-type")?.split(";")[0]?.trim() || inferredMimeType;
@@ -67757,54 +67760,25 @@ async function resolveMediaSource(mediaSource, mimeTypeOverride) {
67757
67760
  label: mediaSource.startsWith("file://") ? mediaSource : `file://${filePath}`
67758
67761
  };
67759
67762
  }
67760
- function validationError(field, message) {
67761
- return createValidationError(field, message);
67762
- }
67763
- function parseArgs(schema, args) {
67764
- const parsed = schema.safeParse(args ?? {});
67765
- if (!parsed.success) {
67766
- const issue2 = parsed.error.issues[0];
67767
- return {
67768
- success: false,
67769
- error: validationError(
67770
- issue2?.path.length ? issue2.path.join(".") : "arguments",
67771
- issue2?.message ?? parsed.error.message
67772
- )
67773
- };
67774
- }
67775
- return { success: true, data: parsed.data };
67776
- }
67777
- function textResult(text) {
67763
+ function textResult(text, structuredContent) {
67778
67764
  return {
67779
- content: [{ type: "text", text }]
67765
+ content: [{ type: "text", text }],
67766
+ structuredContent
67780
67767
  };
67781
67768
  }
67782
67769
  function formatModelLines(models, title) {
67783
67770
  return [title, ...models.map((model) => `- ${model}`), ""];
67784
67771
  }
67785
- async function analyzeMedia(rawArgs) {
67786
- const parsed = parseArgs(
67787
- z3.object({
67788
- prompt: z3.string().min(1).default("Describe this media."),
67789
- media_source: z3.string().min(1),
67790
- mime_type: z3.string().optional(),
67791
- model: z3.string().optional().default(DEFAULT_TEXT_MODEL),
67792
- output_dir: z3.string().optional()
67793
- }).strict(),
67794
- rawArgs
67795
- );
67796
- if (!parsed.success) {
67797
- return parsed.error;
67798
- }
67799
- 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;
67800
67774
  let media;
67801
67775
  try {
67802
67776
  media = await resolveMediaSource(media_source, mime_type);
67803
67777
  } catch (error48) {
67804
- return createValidationError(
67805
- "media_source",
67806
- error48 instanceof Error ? error48.message : String(error48)
67807
- );
67778
+ if (isErrorWithStatusCode(error48)) {
67779
+ return createApiError(error48.message, error48.statusCode);
67780
+ }
67781
+ return createValidationError("media_source", getErrorMessage(error48));
67808
67782
  }
67809
67783
  let responseText;
67810
67784
  if (IS_MOCK) {
@@ -67816,7 +67790,7 @@ Model: ${model}
67816
67790
  Mock response \u2014 no API call made.`;
67817
67791
  } else {
67818
67792
  const response = await getAi().models.generateContent({
67819
- model,
67793
+ model: model || DEFAULT_TEXT_MODEL,
67820
67794
  contents: [
67821
67795
  {
67822
67796
  role: "user",
@@ -67834,68 +67808,70 @@ Mock response \u2014 no API call made.`;
67834
67808
  });
67835
67809
  responseText = response.text || "No analysis generated.";
67836
67810
  }
67811
+ let savedPath;
67837
67812
  if (output_dir) {
67838
67813
  try {
67839
67814
  const fname = `analysis-${Date.now()}.txt`;
67840
- const fpath = path2.join(output_dir, fname);
67815
+ savedPath = path2.join(output_dir, fname);
67841
67816
  await fs3.mkdir(output_dir, { recursive: true });
67842
- await fs3.writeFile(fpath, responseText);
67843
- return textResult(
67844
- `${responseText}
67845
-
67846
- \u2705 Analysis result saved to: ${fpath}`
67847
- );
67817
+ await fs3.writeFile(savedPath, responseText);
67848
67818
  } catch (error48) {
67849
67819
  return textResult(
67850
67820
  `${responseText}
67851
67821
 
67852
- \u26A0\uFE0F Failed to save analysis result: ${getErrorMessage(error48)}`
67822
+ \u26A0\uFE0F Failed to save analysis result: ${getErrorMessage(error48)}`,
67823
+ {
67824
+ analysis: responseText,
67825
+ source: media.label,
67826
+ mimeType: media.mimeType
67827
+ }
67853
67828
  );
67854
67829
  }
67855
67830
  }
67856
- return textResult(responseText);
67857
- }
67858
- async function listModels(rawArgs) {
67859
- const parsed = parseArgs(
67860
- z3.object({
67861
- capability: z3.enum(["all", "image", "video"]).default("all")
67862
- }).strict(),
67863
- 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
+ }
67864
67841
  );
67865
- if (!parsed.success) {
67866
- return parsed.error;
67867
- }
67868
- const { capability } = parsed.data;
67842
+ }
67843
+ async function listModels(args) {
67844
+ const { capability } = args;
67869
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];
67870
67852
  const lines2 = ["## Available Gemini Models", ""];
67871
67853
  if (capability === "all" || capability === "image") {
67872
67854
  lines2.push(
67873
- ...formatModelLines(
67874
- [
67875
- `${DEFAULT_IMAGE_MODEL} \u2B50 (recommended default)`,
67876
- "imagen-4.0-ultra-generate-001 (highest quality)",
67877
- "imagen-4.0-fast-generate-001 (fastest)"
67878
- ],
67879
- "### \u{1F5BC}\uFE0F Image Generation"
67880
- )
67855
+ ...formatModelLines(imageModels2, "### \u{1F5BC}\uFE0F Image Generation")
67881
67856
  );
67882
67857
  }
67883
67858
  if (capability === "all" || capability === "video") {
67884
67859
  lines2.push(
67885
- ...formatModelLines(
67886
- [DEFAULT_VIDEO_MODEL],
67887
- "### \u{1F3AC} Video Generation"
67888
- )
67860
+ ...formatModelLines(videoModels2, "### \u{1F3AC} Video Generation")
67889
67861
  );
67890
67862
  }
67891
- return textResult(lines2.join("\n").trim());
67863
+ return textResult(lines2.join("\n").trim(), {
67864
+ imageModels: capability === "video" ? [] : imageModels2,
67865
+ videoModels: capability === "image" ? [] : videoModels2
67866
+ });
67892
67867
  }
67893
67868
  const resp = await fetch(
67894
67869
  `https://generativelanguage.googleapis.com/v1beta/models?key=${getApiKey()}&pageSize=200`
67895
67870
  );
67896
67871
  if (!resp.ok) {
67897
- throw new Error(
67898
- `Failed to list models: ${resp.status} ${resp.statusText}`
67872
+ return createApiError(
67873
+ "The model listing service is unavailable.",
67874
+ resp.status
67899
67875
  );
67900
67876
  }
67901
67877
  const data = await resp.json();
@@ -67912,57 +67888,70 @@ async function listModels(rawArgs) {
67912
67888
  if (capability === "all" || capability === "video") {
67913
67889
  lines.push(...formatModelLines(videoModels, "### \u{1F3AC} Video Generation"));
67914
67890
  }
67915
- 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
+ });
67916
67895
  }
67917
- async function generateImage(rawArgs) {
67918
- const parsed = parseArgs(
67919
- z3.object({
67920
- prompt: z3.string().min(1),
67921
- aspect_ratio: z3.enum(["1:1", "16:9", "9:16"]).default("1:1"),
67922
- model: z3.string().default(DEFAULT_IMAGE_MODEL),
67923
- output_dir: z3.string().optional()
67924
- }).strict(),
67925
- rawArgs
67926
- );
67927
- if (!parsed.success) {
67928
- return parsed.error;
67929
- }
67930
- const { prompt, aspect_ratio, model, output_dir } = parsed.data;
67896
+ async function generateImage(args) {
67897
+ const { prompt, aspect_ratio, model, output_dir } = args;
67931
67898
  if (IS_MOCK) {
67932
67899
  const mockBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
67933
- const content2 = [
67934
- {
67935
- type: "text",
67936
- text: `\u2705 Image generated successfully (1 image, prompt: "${prompt}").`
67937
- },
67938
- { type: "image", data: mockBase64, mimeType: "image/png" }
67939
- ];
67900
+ let savedPath;
67940
67901
  if (output_dir) {
67941
67902
  try {
67942
67903
  const fname = `image-${Date.now()}.png`;
67943
- const fpath = path2.join(output_dir, fname);
67904
+ savedPath = path2.join(output_dir, fname);
67944
67905
  await fs3.mkdir(output_dir, { recursive: true });
67945
- await fs3.writeFile(fpath, Buffer.from(mockBase64, "base64"));
67946
- content2.push({
67947
- type: "text",
67948
- text: `[Mock] Saved to: ${fpath}`
67949
- });
67906
+ await fs3.writeFile(
67907
+ savedPath,
67908
+ Buffer.from(mockBase64, "base64")
67909
+ );
67950
67910
  } catch (error48) {
67951
- content2.push({
67952
- type: "text",
67953
- text: `\u26A0\uFE0F [Mock] Failed to save image: ${getErrorMessage(error48)}`
67954
- });
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
+ };
67955
67930
  }
67956
67931
  }
67957
- 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
+ };
67958
67948
  }
67959
67949
  const response = await getAi().models.generateImages({
67960
- model,
67950
+ model: model || DEFAULT_IMAGE_MODEL,
67961
67951
  prompt,
67962
67952
  config: { numberOfImages: 1, aspectRatio: aspect_ratio }
67963
67953
  });
67964
67954
  const images = (response.generatedImages ?? []).map((img) => ({
67965
- type: "image",
67966
67955
  data: img.image?.imageBytes ?? "",
67967
67956
  mimeType: "image/png"
67968
67957
  }));
@@ -67971,108 +67960,75 @@ async function generateImage(rawArgs) {
67971
67960
  content: [
67972
67961
  {
67973
67962
  type: "text",
67974
- text: `Image generation returned no results. Possible reasons:
67975
- - Content policy violation in prompt
67976
- - Model unavailable (${model}) in your region/API tier
67977
- - Prompt unsupported or aspect ratio invalid (${aspect_ratio})
67978
-
67979
- Check Imagen access at https://ai.google.dev/`
67963
+ text: `Image generation returned no results. Check Imagen access and policies.`
67980
67964
  }
67981
67965
  ],
67982
67966
  isError: true
67983
67967
  };
67984
67968
  }
67985
- const savedPaths = [];
67986
- let saveErrorText = "";
67969
+ const savedImages = [];
67987
67970
  if (output_dir) {
67988
67971
  try {
67989
67972
  await fs3.mkdir(output_dir, { recursive: true });
67990
- const paths = await Promise.all(
67991
- images.map(async (img, index) => {
67992
- const fname = `image-${Date.now()}-${index + 1}.png`;
67993
- const fpath = path2.join(output_dir, fname);
67994
- await fs3.writeFile(fpath, Buffer.from(img.data, "base64"));
67995
- return fpath;
67996
- })
67997
- );
67998
- 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
+ }
67999
67979
  } catch (error48) {
68000
- saveErrorText = `
68001
-
68002
- \u26A0\uFE0F Failed to save images: ${getErrorMessage(error48)}`;
67980
+ console.error(`Failed to save images: ${getErrorMessage(error48)}`);
67981
+ savedImages.push(...images);
68003
67982
  }
67983
+ } else {
67984
+ savedImages.push(...images);
68004
67985
  }
67986
+ const savedPaths = savedImages.map((img) => img.savedPath).filter(Boolean);
68005
67987
  const content = [
68006
67988
  {
68007
67989
  type: "text",
68008
- 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 ? `
68009
67991
  Saved to:
68010
- ${savedPaths.join("\n")}` : ""}${saveErrorText}`
67992
+ ${savedPaths.join("\n")}` : ""}`
68011
67993
  },
68012
- ...images
67994
+ ...savedImages.map((img) => ({
67995
+ type: "image",
67996
+ data: img.data,
67997
+ mimeType: img.mimeType
67998
+ }))
68013
67999
  ];
68014
- return { content };
68000
+ return { content, structuredContent: { images: savedImages, prompt } };
68015
68001
  }
68016
- async function generateVideo(rawArgs) {
68017
- const parsed = parseArgs(
68018
- z3.object({
68019
- prompt: z3.string().min(1),
68020
- model: z3.string().default(DEFAULT_VIDEO_MODEL)
68021
- }).strict(),
68022
- rawArgs
68023
- );
68024
- if (!parsed.success) {
68025
- return parsed.error;
68026
- }
68027
- const { prompt, model } = parsed.data;
68002
+ async function generateVideo(args) {
68003
+ const { prompt, model } = args;
68028
68004
  if (IS_MOCK) {
68029
- return {
68030
- content: [
68031
- {
68032
- type: "text",
68033
- text: `[Mock] Video generation started.
68034
- Operation name: mock-operations/123456
68035
- Model: ${model}
68005
+ const opName2 = "mock-operations/123456";
68006
+ return textResult(
68007
+ `[Mock] Video generation started.
68036
68008
 
68037
- Call get_video_status with operation_name="mock-operations/123456" to check progress.`
68038
- }
68039
- ]
68040
- };
68009
+ Operation name: ${opName2}
68010
+
68011
+ Call get_video_status to check progress.`,
68012
+ { operationName: opName2, prompt, status: "queued" }
68013
+ );
68041
68014
  }
68042
68015
  const operation = await getAi().models.generateVideos({
68043
- model,
68016
+ model: model || DEFAULT_VIDEO_MODEL,
68044
68017
  prompt,
68045
68018
  config: { numberOfVideos: 1 }
68046
68019
  });
68047
68020
  const opName = operation.name ?? "unknown";
68048
- return {
68049
- content: [
68050
- {
68051
- type: "text",
68052
- text: `Video generation started (async \u2014 typically takes 2\u20135 minutes).
68021
+ return textResult(
68022
+ `Video generation started.
68053
68023
 
68054
68024
  Operation name: ${opName}
68055
68025
 
68056
- Call get_video_status with:
68057
- operation_name="${opName}"
68058
-
68059
- Poll every ~30 seconds until done=true.`
68060
- }
68061
- ]
68062
- };
68063
- }
68064
- async function getVideoStatus(rawArgs) {
68065
- const parsed = parseArgs(
68066
- z3.object({
68067
- operation_name: z3.string().min(1),
68068
- output_dir: z3.string().optional()
68069
- }).strict(),
68070
- rawArgs
68026
+ Call get_video_status every ~30s until complete.`,
68027
+ { operationName: opName, prompt, status: "started" }
68071
68028
  );
68072
- if ("error" in parsed) {
68073
- return parsed.error;
68074
- }
68075
- const { operation_name, output_dir } = parsed.data;
68029
+ }
68030
+ async function getVideoStatus(args) {
68031
+ const { operation_name, output_dir } = args;
68076
68032
  let op;
68077
68033
  if (IS_MOCK) {
68078
68034
  op = {
@@ -68090,7 +68046,8 @@ async function getVideoStatus(rawArgs) {
68090
68046
  }
68091
68047
  if (!op.done) {
68092
68048
  return textResult(
68093
- `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: [] }
68094
68051
  );
68095
68052
  }
68096
68053
  if (op.error) {
@@ -68098,20 +68055,30 @@ async function getVideoStatus(rawArgs) {
68098
68055
  content: [
68099
68056
  {
68100
68057
  type: "text",
68101
- text: `Video generation failed: ${op.error.message ?? JSON.stringify(op.error)}`
68058
+ text: `Video generation failed: ${op.error.message || "Unknown upstream error"}`
68102
68059
  }
68103
68060
  ],
68061
+ structuredContent: {
68062
+ done: true,
68063
+ error: op.error.message,
68064
+ videos: []
68065
+ },
68104
68066
  isError: true
68105
68067
  };
68106
68068
  }
68107
68069
  const videos = (op.response?.generatedVideos ?? []).map((video) => video.video?.uri ?? "").filter(Boolean);
68108
68070
  if (videos.length === 0) {
68109
- return textResult(
68110
- `Complete but no video URLs found:
68111
- ${JSON.stringify(op.response, null, 2)}`
68112
- );
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
+ };
68113
68080
  }
68114
- const savedPaths = [];
68081
+ const videoResults = [];
68115
68082
  const videoContents = [];
68116
68083
  await Promise.all(
68117
68084
  videos.map(async (url2, index) => {
@@ -68121,9 +68088,7 @@ ${JSON.stringify(op.response, null, 2)}`
68121
68088
  } else {
68122
68089
  const videoResp = await fetch(withApiKey(url2));
68123
68090
  if (!videoResp.ok) {
68124
- throw new Error(
68125
- `Failed to download video: ${videoResp.status}`
68126
- );
68091
+ throw new Error(`Failed to download video.`);
68127
68092
  }
68128
68093
  const arrayBuffer = await videoResp.arrayBuffer();
68129
68094
  buffer = Buffer.from(arrayBuffer);
@@ -68136,55 +68101,66 @@ ${JSON.stringify(op.response, null, 2)}`
68136
68101
  blob: buffer.toString("base64")
68137
68102
  }
68138
68103
  });
68104
+ let savedPath;
68139
68105
  if (output_dir) {
68140
68106
  try {
68141
68107
  const fname = `video-${Date.now()}-${index + 1}.mp4`;
68142
- const fpath = path2.join(output_dir, fname);
68108
+ savedPath = path2.join(output_dir, fname);
68143
68109
  await fs3.mkdir(output_dir, { recursive: true });
68144
- await fs3.writeFile(fpath, buffer);
68145
- savedPaths.push(fpath);
68110
+ await fs3.writeFile(savedPath, buffer);
68146
68111
  } catch (error48) {
68147
68112
  console.error(
68148
68113
  `Failed to save video: ${getErrorMessage(error48)}`
68149
68114
  );
68150
68115
  }
68151
68116
  }
68117
+ videoResults.push({ url: url2, savedPath });
68152
68118
  })
68153
68119
  );
68154
- const lines = [
68120
+ const savedPaths = videoResults.map((v) => v.savedPath).filter(Boolean);
68121
+ const summaryLines = [
68155
68122
  `Video generation complete!
68156
68123
 
68157
68124
  Download URLs:
68158
68125
  ${videos.join("\n")}`
68159
68126
  ];
68160
68127
  if (savedPaths.length > 0) {
68161
- lines.push(`
68128
+ summaryLines.push(`
68129
+
68162
68130
  Saved to:
68163
68131
  ${savedPaths.join("\n")}`);
68164
- } else if (output_dir) {
68165
- lines.push(`
68166
- \u26A0\uFE0F Failed to save videos to disk.`);
68167
68132
  }
68168
68133
  return {
68169
68134
  content: [
68170
- { type: "text", text: lines.join("") },
68135
+ { type: "text", text: summaryLines.join("") },
68171
68136
  ...videoContents
68172
- ]
68137
+ ],
68138
+ structuredContent: { done: true, videos: videoResults }
68173
68139
  };
68174
68140
  }
68175
68141
  async function handleToolCall(name, args) {
68176
68142
  try {
68177
68143
  switch (name) {
68178
68144
  case "analyze_media":
68179
- return await analyzeMedia(args);
68145
+ return await analyzeMedia(
68146
+ ANALYZE_MEDIA_TOOL.inputSchema.parse(args)
68147
+ );
68180
68148
  case "list_models":
68181
- return await listModels(args);
68149
+ return await listModels(
68150
+ LIST_MODELS_TOOL.inputSchema.parse(args)
68151
+ );
68182
68152
  case "generate_image":
68183
- return await generateImage(args);
68153
+ return await generateImage(
68154
+ GENERATE_IMAGE_TOOL.inputSchema.parse(args)
68155
+ );
68184
68156
  case "generate_video":
68185
- return await generateVideo(args);
68157
+ return await generateVideo(
68158
+ GENERATE_VIDEO_TOOL.inputSchema.parse(args)
68159
+ );
68186
68160
  case "get_video_status":
68187
- return await getVideoStatus(args);
68161
+ return await getVideoStatus(
68162
+ GET_VIDEO_STATUS_TOOL.inputSchema.parse(args)
68163
+ );
68188
68164
  default:
68189
68165
  throw new Error(`Tool not found: ${name}`);
68190
68166
  }
@@ -68195,6 +68171,9 @@ async function handleToolCall(name, args) {
68195
68171
  error48.issues[0]?.message || error48.message
68196
68172
  );
68197
68173
  }
68174
+ if (isErrorWithStatusCode(error48)) {
68175
+ return createApiError(error48.message, error48.statusCode);
68176
+ }
68198
68177
  return createInternalError(error48);
68199
68178
  }
68200
68179
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fre4x/gemini",
3
- "version": "1.0.55",
3
+ "version": "1.0.58",
4
4
  "description": "A Gemini MCP server providing multimodal analysis and image/video generation.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",