🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@huyooo/ai-chat-tools-node

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@huyooo/ai-chat-tools-node - npm Package Compare versions

Comparing version
0.3.22
to
0.3.23
+16
dist/media/geminiMediaConfig.d.ts
import type { ExtensionAiProvider } from '@huyooo/ai-chat-core/runtime';
export interface GeminiMediaBaseConfig {
apiKey: string;
}
/** 图片/视频理解工具配置 */
export interface GeminiVisionMediaConfig extends GeminiMediaBaseConfig {
model: string;
}
/** 图片生成工具配置 */
export interface GeminiImageGenMediaConfig extends GeminiMediaBaseConfig {
model: string;
}
/** 校验并规范化 model ID(由接入方显式配置) */
export declare function trimGeminiModel(model: string): string;
/** 同一 apiKey 复用 Gemini REST 客户端 */
export declare function getGeminiMediaClient(config: GeminiMediaBaseConfig): ExtensionAiProvider;
+2
-1

@@ -10,3 +10,4 @@ /**

export { updatePlanTool, UPDATE_PLAN_TOOL_NAME, UPDATE_PLAN_PROMPT } from './plan';
export { analyzeImageTool, generateImageTool, analyzeVideoTool, analyzeImage, generateImage, analyzeVideo, createGeminiDirectProvider } from './media';
export { analyzeImageTool, generateImageTool, analyzeVideoTool, analyzeImage, generateImage, analyzeVideo, } from './media';
export type { GeminiImageGenMediaConfig, GeminiMediaBaseConfig, GeminiVisionMediaConfig, } from './media';
export { showToastTool, openConfirmDialogTool, openMediaFileAppTool, navigateToDirectoryTool } from './ui-actions';

@@ -13,0 +14,0 @@ export { default as planExtension } from './plan/extension';

@@ -9,2 +9,2 @@ import{createModuleLogger as e,defineTool as t}from"@huyooo/ai-chat-core";import{Type as n}from"@sinclair/typebox";import{createReadStream as r}from"node:fs";import{stat as i}from"node:fs/promises";import a from"node:path";import o from"node:os";import{defineExtension as s}from"@huyooo/ai-chat-core/runtime";function c(){return t({name:`get_environment`,category:`system`,tags:[`环境`,`目录`,`平台`],description:`获取当前运行环境信息,包括工作目录和操作系统。执行目录相关命令前先调用此工具确认环境。因为用户可能切换了工作目录,所以每次调用都要确认。`,inputSchema:n.Object({}),execute:async(e,t)=>{let n=(await import(`os`)).default.platform(),r=n===`darwin`?`macOS`:n===`win32`?`Windows`:`Linux`;return{cwd:t.cwd,platform:r,shell:n===`win32`?`powershell`:`bash/zsh`}}})}const l=e(`UpdatePlan`),u=`update_plan`,d=`## 计划跟踪(update_plan)

- 传入完整步骤列表(全量替换),格式:[{ title, status }]
- status 取值:pending / in_progress / done / failed`,f=[`pending`,`in_progress`,`done`,`failed`],p=n.Union([n.Literal(`pending`),n.Literal(`in_progress`),n.Literal(`done`),n.Literal(`failed`)],{description:`当前状态:pending=待执行, in_progress=执行中, done=已完成, failed=失败`});function m(e){let t=String(e??``).trim().toLowerCase();return f.includes(t)?t:`pending`}function h(e){return typeof e==`object`&&!!e}function g(e,t){if(!h(e))return null;let n=e,r=typeof n.id==`string`&&n.id.trim()?n.id.trim():`step-${t+1}`,i=(typeof n.title==`string`?n.title:typeof n.description==`string`?n.description:``).trim(),a=m(n.status);return i?{id:r,title:i,status:a}:null}const _=t({name:u,category:`plan`,tags:[`计划`,`进度`,`任务`],description:`向用户界面同步任务执行进度。调用后用户会看到一个进度卡片,显示每个步骤的当前状态。每次传入完整的步骤列表(全量替换)。`,inputSchema:n.Object({steps:n.Array(n.Object({title:n.String({description:`步骤的简短描述`,minLength:1,pattern:`\\S`}),status:p}),{description:`完整的步骤列表。每个步骤包含描述。`})}),ui:{type:`render`,name:`plan`,singleton:!0},execute:async({steps:e})=>{l.debug({rawSteps:e},`收到 args`);let t=e.map((e,t)=>g(e,t)).filter(e=>e!==null),n={steps:t,status:t.length>0&&t.every(e=>e.status===`done`)?`done`:`running`};return l.debug({result:n},`输出`),n}}),v={".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".png":`image/png`,".webp":`image/webp`,".heic":`image/heic`,".heif":`image/heif`},y={".mp4":`video/mp4`,".mpeg":`video/mpeg`,".mpg":`video/mpg`,".mov":`video/mov`,".avi":`video/avi`,".flv":`video/x-flv`,".webm":`video/webm`,".wmv":`video/wmv`,".3gp":`video/3gpp`};function b(e){let t=v[e];if(!t)throw Error(`不支持的图片格式:${e||`无扩展名`}。请使用 JPEG、PNG、WebP、HEIC 或 HEIF。`);return t}function x(e){let t=y[e];if(!t)throw Error(`不支持的视频格式:${e||`无扩展名`}。请使用 MP4、MPEG、MOV、AVI、FLV、WebM、WMV 或 3GPP。`);return t}async function S(e,t){let n=await(await import(`fs/promises`)).stat(e);if(!n.isFile())throw Error(`${t}路径必须指向普通文件`);if(n.size<=0)throw Error(`${t}文件为空`);return n.size}async function C(e,t,n,r){try{if(r?.aborted)return JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0});let i=b((await import(`path`)).extname(t).toLowerCase());return await S(t,`图片`),(await e.generate({model:`gemini-3-flash`,messages:[{role:`user`,content:n||`请详细描述这张图片的内容`,attachments:[{mimeType:i,filePath:t}]}],signal:r})).text||`无法分析图片`}catch(e){return r?.aborted?JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0}):`图片分析失败: ${e}`}}async function w(e,t,n,r,i){try{if(i?.aborted)return JSON.stringify({success:!1,error:`操作已取消`});let a=await e.generate({model:`gemini-3-pro-image-preview`,messages:[{role:`user`,content:n}],signal:i});for(let e of a.parts)if(e.type===`binary`){let n=Buffer.from(e.data,`base64`),i=e.mimeType||`image/png`,a=i===`image/jpeg`?`.jpg`:i===`image/webp`?`.webp`:`.png`,o=await import(`fs/promises`),s=r||`${t}/generated_${Date.now()}${a}`;return await o.writeFile(s,n),JSON.stringify({success:!0,path:s,format:i})}return JSON.stringify({success:!1,error:`图片生成失败`})}catch(e){return i?.aborted?JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0}):JSON.stringify({success:!1,error:`图片生成失败: ${e}`})}}async function T(e,t,n,r){try{if(r?.aborted)return JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0});let i=x((await import(`path`)).extname(t).toLowerCase());return await S(t,`视频`),(await e.generate({model:`gemini-3-flash`,messages:[{role:`user`,content:n||`请详细描述这个视频的内容`,attachments:[{mimeType:i,filePath:t}]}],signal:r})).text||`无法分析视频`}catch(e){return r?.aborted?JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0}):`视频分析失败: ${e}`}}function E(e){return t({name:`analyze_image`,category:`media`,tags:[`图片`,`分析`,`Gemini`],description:`分析图片内容(识别物体、场景、文字等)`,inputSchema:n.Object({imagePath:n.String({description:`图片文件路径`,minLength:1,pattern:`\\S`}),question:n.Optional(n.String({description:`关于图片的问题(可选)`,minLength:1,pattern:`\\S`}))}),execute:async({imagePath:t,question:n},r)=>({result:await C(e,t,n,r.signal)})})}function D(e){return t({name:`generate_image`,category:`media`,tags:[`图片`,`生成`,`Gemini`],description:`根据文字描述生成图片并保存到本地。返回保存路径。`,inputSchema:n.Object({prompt:n.String({description:`图片描述,使用详细的英文描述效果更好`,minLength:1,pattern:`\\S`}),outputPath:n.Optional(n.String({description:`保存路径(可选)`,minLength:1,pattern:`\\S`}))}),ui:{type:`action`,name:`notification`},execute:async({prompt:t,outputPath:n},r)=>({result:await w(e,r.cwd??process.cwd(),t,n,r.signal),message:`🎨 图片生成完成`})})}function O(e){return t({name:`analyze_video`,category:`media`,tags:[`视频`,`分析`,`Gemini`],description:`分析视频内容(识别场景、动作、物体等)`,inputSchema:n.Object({videoPath:n.String({description:`视频文件路径`,minLength:1,pattern:`\\S`}),question:n.Optional(n.String({description:`关于视频的问题(可选)`,minLength:1,pattern:`\\S`}))}),execute:async({videoPath:t,question:n},r)=>({result:await T(e,t,n,r.signal)})})}const k=`https://generativelanguage.googleapis.com/v1beta`;async function A(e){let t=await e.text();if(!t)return{};try{return JSON.parse(t)}catch{return{raw:t}}}function j(e){let t=e.file;return t&&typeof t==`object`&&!Array.isArray(t)?t:e}async function M(e,t){if(t?.aborted)throw Error(`操作已取消`);await new Promise((n,r)=>{let i=setTimeout(n,e);t?.addEventListener(`abort`,()=>{clearTimeout(i),r(Error(`操作已取消`))},{once:!0})})}async function N(e,t,n){for(let r=0;r<30;r+=1){let r=await fetch(`${k}/${e}?key=${t}`,{signal:n});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`Gemini Files API ${r.status}: ${e}`)}let i=await A(r);if(!i.state||i.state===`ACTIVE`)return i;if(i.state===`FAILED`)throw Error(`Gemini Files API 文件处理失败: ${JSON.stringify(i)}`);await M(2e3,n)}throw Error(`Gemini Files API 文件处理超时`)}async function P(e,t,n,o){let s=await i(t),c=await fetch(`${k.replace(/\/v1beta$/,`/upload/v1beta`)}/files`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Goog-Upload-Protocol":`resumable`,"X-Goog-Upload-Command":`start`,"X-Goog-Upload-Header-Content-Length":String(s.size),"X-Goog-Upload-Header-Content-Type":n,"x-goog-api-key":e},body:JSON.stringify({file:{display_name:a.basename(t)}}),signal:o});if(!c.ok){let e=await c.text().catch(()=>``);throw Error(`Gemini Files API ${c.status}: ${e}`)}let l=c.headers.get(`x-goog-upload-url`);if(!l)throw Error(`Gemini Files API 未返回 x-goog-upload-url`);let u={method:`POST`,headers:{"Content-Length":String(s.size),"Content-Type":n,"X-Goog-Upload-Offset":`0`,"X-Goog-Upload-Command":`upload, finalize`,"x-goog-api-key":e},body:r(t),duplex:`half`,signal:o},d=await fetch(l,u);if(!d.ok){let e=await d.text().catch(()=>``);throw Error(`Gemini Files API ${d.status}: ${e}`)}let f=j(await A(d));if(typeof f.name==`string`&&f.state&&f.state!==`ACTIVE`&&(f=await N(f.name,e,o)),typeof f.uri!=`string`||!f.uri)throw Error(`Gemini Files API 未返回 file.uri: ${JSON.stringify(f)}`);return f.uri}async function F(e,t,n){let r=[];for(let i of t){let t=[{text:i.content}];for(let r of i.attachments??[]){let i=r.fileUri??(r.filePath?await P(e,r.filePath,r.mimeType,n):void 0);if(!i)throw Error(`Gemini 附件必须提供 filePath 或 fileUri`);t.push({fileData:{mimeType:r.mimeType,fileUri:i}})}r.push({role:i.role===`assistant`?`model`:`user`,parts:t})}return r}function I(e){let t=e.candidates?.[0],n=t?.content?.parts??[],r=``,i=[];for(let e of n)e.text?(r+=e.text,i.push({type:`text`,text:e.text})):e.inlineData&&i.push({type:`binary`,mimeType:e.inlineData.mimeType,data:e.inlineData.data});return{text:r,parts:i,finishReason:t?.finishReason===`STOP`?`stop`:void 0,usage:e.usageMetadata?{promptTokens:e.usageMetadata.promptTokenCount,completionTokens:e.usageMetadata.candidatesTokenCount,totalTokens:e.usageMetadata.totalTokenCount}:void 0}}function L(e){return{async generate(t){let n=`${k}/models/${t.model}:generateContent?key=${e}`,r=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contents:await F(e,t.messages,t.signal),generationConfig:{responseModalities:[`TEXT`,`IMAGE`]}}),signal:t.signal});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`Gemini API ${r.status}: ${e}`)}return I(await r.json())}}}function R(){return t({name:`show_toast`,category:`ui`,tags:[`通知`,`Toast`],description:`在用户界面上显示一条 Toast 通知消息,消息会在几秒后自动消失`,inputSchema:n.Object({message:n.String({description:`要显示给用户的通知内容`,minLength:1,pattern:`\\S`})}),ui:{type:`action`,name:`toast`},execute:async({message:e})=>({success:!0,message:e})})}function z(){return t({name:`open_confirm_dialog`,category:`ui`,tags:[`对话框`,`确认`],description:`在用户界面上弹出一个模态确认对话框。`,inputSchema:n.Object({title:n.String({description:`对话框标题,简要说明确认的操作`,minLength:1,pattern:`\\S`}),message:n.String({description:`详细描述需要用户确认的内容`,minLength:1,pattern:`\\S`}),confirmText:n.Optional(n.String({description:`确认按钮文字,默认为"确认"`,minLength:1,pattern:`\\S`})),cancelText:n.Optional(n.String({description:`取消按钮文字,默认为"取消"`,minLength:1,pattern:`\\S`}))}),ui:{type:`action`,name:`confirm_dialog`},execute:async({title:e,message:t,confirmText:n,cancelText:r})=>({success:!0,title:e,message:t,confirmText:n??`确认`,cancelText:r??`取消`})})}const B=n.Union([n.Literal(`image`),n.Literal(`video`),n.Literal(`audio`)],{description:`媒体类型(必填):image/video/audio`});function V(){return t({name:`open_media_file_app`,category:`ui`,tags:[`媒体`,`文件`,`应用`],description:`在用户界面上打开指定媒体文件对应的应用界面。`,inputSchema:n.Object({path:n.String({description:`要打开的媒体文件完整路径`,minLength:1,pattern:`\\S`}),mediaType:B}),ui:{type:`action`,name:`media_file_app`},execute:async({path:e,mediaType:t})=>({success:!0,path:e,mediaType:t})})}function H(e){if(e===`~`)return o.homedir();if(e.startsWith(`~${a.sep}`)||a.sep===`\\`&&e.startsWith(`~/`))return a.join(o.homedir(),e.slice(2));if(!a.isAbsolute(e))throw Error(`目录路径必须是绝对路径,或使用 ~ 表示主目录: ${e}`);return a.normalize(e)}function U(){return t({name:`navigate_to_directory`,category:`ui`,tags:[`导航`,`目录`],description:`控制用户界面左侧的文件浏览器跳转到指定目录,让用户可以直接看到该目录下的文件列表`,inputSchema:n.Object({directory:n.String({description:`要跳转到的目录路径,必须是绝对路径;支持 ~ 表示主目录,如 ~/Desktop`,minLength:1,pattern:`\\S`})}),ui:{type:`action`,name:`navigate`},execute:async({directory:e})=>{if(typeof e!=`string`||e.trim().length===0)throw Error(`directory 必须是非空字符串`);let t=H(e.trim());if(!(await i(t)).isDirectory())throw Error(`不是目录: ${t}`);return{success:!0,directory:t}}})}R(),z(),V(),U();var W=s({activate:()=>[_]}),G=s({activate:()=>[R(),z(),V(),U()]}),K=s({activate:()=>[c()]});export{d as UPDATE_PLAN_PROMPT,u as UPDATE_PLAN_TOOL_NAME,C as analyzeImage,E as analyzeImageTool,T as analyzeVideo,O as analyzeVideoTool,L as createGeminiDirectProvider,K as envExtension,w as generateImage,D as generateImageTool,c as getEnvironmentTool,U as navigateToDirectoryTool,z as openConfirmDialogTool,V as openMediaFileAppTool,W as planExtension,R as showToastTool,G as uiActionsExtension,_ as updatePlanTool};
- status 取值:pending / in_progress / done / failed`,f=[`pending`,`in_progress`,`done`,`failed`],p=n.Union([n.Literal(`pending`),n.Literal(`in_progress`),n.Literal(`done`),n.Literal(`failed`)],{description:`当前状态:pending=待执行, in_progress=执行中, done=已完成, failed=失败`});function m(e){let t=String(e??``).trim().toLowerCase();return f.includes(t)?t:`pending`}function h(e){return typeof e==`object`&&!!e}function g(e,t){if(!h(e))return null;let n=e,r=typeof n.id==`string`&&n.id.trim()?n.id.trim():`step-${t+1}`,i=(typeof n.title==`string`?n.title:typeof n.description==`string`?n.description:``).trim(),a=m(n.status);return i?{id:r,title:i,status:a}:null}const _=t({name:u,category:`plan`,tags:[`计划`,`进度`,`任务`],description:`向用户界面同步任务执行进度。调用后用户会看到一个进度卡片,显示每个步骤的当前状态。每次传入完整的步骤列表(全量替换)。`,inputSchema:n.Object({steps:n.Array(n.Object({title:n.String({description:`步骤的简短描述`,minLength:1,pattern:`\\S`}),status:p}),{description:`完整的步骤列表。每个步骤包含描述。`})}),ui:{type:`render`,name:`plan`,singleton:!0},execute:async({steps:e})=>{l.debug({rawSteps:e},`收到 args`);let t=e.map((e,t)=>g(e,t)).filter(e=>e!==null),n={steps:t,status:t.length>0&&t.every(e=>e.status===`done`)?`done`:`running`};return l.debug({result:n},`输出`),n}}),v=`https://generativelanguage.googleapis.com/v1beta`;async function y(e){let t=await e.text();if(!t)return{};try{return JSON.parse(t)}catch{return{raw:t}}}function b(e){let t=e.file;return t&&typeof t==`object`&&!Array.isArray(t)?t:e}async function x(e,t){if(t?.aborted)throw Error(`操作已取消`);await new Promise((n,r)=>{let i=setTimeout(n,e);t?.addEventListener(`abort`,()=>{clearTimeout(i),r(Error(`操作已取消`))},{once:!0})})}async function S(e,t,n){for(let r=0;r<30;r+=1){let r=await fetch(`${v}/${e}?key=${t}`,{signal:n});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`Gemini Files API ${r.status}: ${e}`)}let i=await y(r);if(!i.state||i.state===`ACTIVE`)return i;if(i.state===`FAILED`)throw Error(`Gemini Files API 文件处理失败: ${JSON.stringify(i)}`);await x(2e3,n)}throw Error(`Gemini Files API 文件处理超时`)}async function C(e,t,n,o){let s=await i(t),c=await fetch(`${v.replace(/\/v1beta$/,`/upload/v1beta`)}/files`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Goog-Upload-Protocol":`resumable`,"X-Goog-Upload-Command":`start`,"X-Goog-Upload-Header-Content-Length":String(s.size),"X-Goog-Upload-Header-Content-Type":n,"x-goog-api-key":e},body:JSON.stringify({file:{display_name:a.basename(t)}}),signal:o});if(!c.ok){let e=await c.text().catch(()=>``);throw Error(`Gemini Files API ${c.status}: ${e}`)}let l=c.headers.get(`x-goog-upload-url`);if(!l)throw Error(`Gemini Files API 未返回 x-goog-upload-url`);let u={method:`POST`,headers:{"Content-Length":String(s.size),"Content-Type":n,"X-Goog-Upload-Offset":`0`,"X-Goog-Upload-Command":`upload, finalize`,"x-goog-api-key":e},body:r(t),duplex:`half`,signal:o},d=await fetch(l,u);if(!d.ok){let e=await d.text().catch(()=>``);throw Error(`Gemini Files API ${d.status}: ${e}`)}let f=b(await y(d));if(typeof f.name==`string`&&f.state&&f.state!==`ACTIVE`&&(f=await S(f.name,e,o)),typeof f.uri!=`string`||!f.uri)throw Error(`Gemini Files API 未返回 file.uri: ${JSON.stringify(f)}`);return f.uri}async function w(e,t,n){let r=[];for(let i of t){let t=[{text:i.content}];for(let r of i.attachments??[]){let i=r.fileUri??(r.filePath?await C(e,r.filePath,r.mimeType,n):void 0);if(!i)throw Error(`Gemini 附件必须提供 filePath 或 fileUri`);t.push({fileData:{mimeType:r.mimeType,fileUri:i}})}r.push({role:i.role===`assistant`?`model`:`user`,parts:t})}return r}function T(e){let t=e.candidates?.[0],n=t?.content?.parts??[],r=``,i=[];for(let e of n)e.text?(r+=e.text,i.push({type:`text`,text:e.text})):e.inlineData&&i.push({type:`binary`,mimeType:e.inlineData.mimeType,data:e.inlineData.data});return{text:r,parts:i,finishReason:t?.finishReason===`STOP`?`stop`:void 0,usage:e.usageMetadata?{promptTokens:e.usageMetadata.promptTokenCount,completionTokens:e.usageMetadata.candidatesTokenCount,totalTokens:e.usageMetadata.totalTokenCount}:void 0}}function E(e){return{async generate(t){let n=`${v}/models/${t.model}:generateContent?key=${e}`,r=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contents:await w(e,t.messages,t.signal),generationConfig:{responseModalities:[`TEXT`,`IMAGE`]}}),signal:t.signal});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`Gemini API ${r.status}: ${e}`)}return T(await r.json())}}}const D=new Map;function O(e){let t=e.trim();if(!t)throw Error(`Gemini apiKey 不能为空`);return t}function k(e){let t=e.trim();if(!t)throw Error(`Gemini model 不能为空`);return t}function A(e){let t=O(e.apiKey),n=D.get(t);if(n)return n;let r=E(t);return D.set(t,r),r}const j={".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".png":`image/png`,".webp":`image/webp`,".heic":`image/heic`,".heif":`image/heif`},M={".mp4":`video/mp4`,".mpeg":`video/mpeg`,".mpg":`video/mpg`,".mov":`video/mov`,".avi":`video/avi`,".flv":`video/x-flv`,".webm":`video/webm`,".wmv":`video/wmv`,".3gp":`video/3gpp`};function N(e){let t=j[e];if(!t)throw Error(`不支持的图片格式:${e||`无扩展名`}。请使用 JPEG、PNG、WebP、HEIC 或 HEIF。`);return t}function P(e){let t=M[e];if(!t)throw Error(`不支持的视频格式:${e||`无扩展名`}。请使用 MP4、MPEG、MOV、AVI、FLV、WebM、WMV 或 3GPP。`);return t}async function F(e,t){let n=await(await import(`fs/promises`)).stat(e);if(!n.isFile())throw Error(`${t}路径必须指向普通文件`);if(n.size<=0)throw Error(`${t}文件为空`);return n.size}async function I(e,t,n,r){try{if(r?.aborted)return JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0});let i=N((await import(`path`)).extname(t).toLowerCase());return await F(t,`图片`),(await A(e).generate({model:k(e.model),messages:[{role:`user`,content:n||`请详细描述这张图片的内容`,attachments:[{mimeType:i,filePath:t}]}],signal:r})).text||`无法分析图片`}catch(e){return r?.aborted?JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0}):`图片分析失败: ${e}`}}async function L(e,t,n,r,i){try{if(i?.aborted)return JSON.stringify({success:!1,error:`操作已取消`});let a=await A(e).generate({model:k(e.model),messages:[{role:`user`,content:n}],signal:i});for(let e of a.parts)if(e.type===`binary`){let n=Buffer.from(e.data,`base64`),i=e.mimeType||`image/png`,a=i===`image/jpeg`?`.jpg`:i===`image/webp`?`.webp`:`.png`,o=await import(`fs/promises`),s=r||`${t}/generated_${Date.now()}${a}`;return await o.writeFile(s,n),JSON.stringify({success:!0,path:s,format:i})}return JSON.stringify({success:!1,error:`图片生成失败`})}catch(e){return i?.aborted?JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0}):JSON.stringify({success:!1,error:`图片生成失败: ${e}`})}}async function R(e,t,n,r){try{if(r?.aborted)return JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0});let i=P((await import(`path`)).extname(t).toLowerCase());return await F(t,`视频`),(await A(e).generate({model:k(e.model),messages:[{role:`user`,content:n||`请详细描述这个视频的内容`,attachments:[{mimeType:i,filePath:t}]}],signal:r})).text||`无法分析视频`}catch(e){return r?.aborted?JSON.stringify({success:!1,error:`操作已取消`,cancelled:!0}):`视频分析失败: ${e}`}}function z(e){return t({name:`analyze_image`,category:`media`,tags:[`图片`,`分析`,`Gemini`],description:`分析图片内容(识别物体、场景、文字等)`,inputSchema:n.Object({imagePath:n.String({description:`图片文件路径`,minLength:1,pattern:`\\S`}),question:n.Optional(n.String({description:`关于图片的问题(可选)`,minLength:1,pattern:`\\S`}))}),execute:async({imagePath:t,question:n},r)=>({result:await I(e,t,n,r.signal)})})}function B(e){return t({name:`generate_image`,category:`media`,tags:[`图片`,`生成`,`Gemini`],description:`根据文字描述生成图片并保存到本地。返回保存路径。`,inputSchema:n.Object({prompt:n.String({description:`图片描述,使用详细的英文描述效果更好`,minLength:1,pattern:`\\S`}),outputPath:n.Optional(n.String({description:`保存路径(可选)`,minLength:1,pattern:`\\S`}))}),ui:{type:`action`,name:`notification`},execute:async({prompt:t,outputPath:n},r)=>({result:await L(e,r.cwd??process.cwd(),t,n,r.signal),message:`🎨 图片生成完成`})})}function V(e){return t({name:`analyze_video`,category:`media`,tags:[`视频`,`分析`,`Gemini`],description:`分析视频内容(识别场景、动作、物体等)`,inputSchema:n.Object({videoPath:n.String({description:`视频文件路径`,minLength:1,pattern:`\\S`}),question:n.Optional(n.String({description:`关于视频的问题(可选)`,minLength:1,pattern:`\\S`}))}),execute:async({videoPath:t,question:n},r)=>({result:await R(e,t,n,r.signal)})})}function H(){return t({name:`show_toast`,category:`ui`,tags:[`通知`,`Toast`],description:`在用户界面上显示一条 Toast 通知消息,消息会在几秒后自动消失`,inputSchema:n.Object({message:n.String({description:`要显示给用户的通知内容`,minLength:1,pattern:`\\S`})}),ui:{type:`action`,name:`toast`},execute:async({message:e})=>({success:!0,message:e})})}function U(){return t({name:`open_confirm_dialog`,category:`ui`,tags:[`对话框`,`确认`],description:`在用户界面上弹出一个模态确认对话框。`,inputSchema:n.Object({title:n.String({description:`对话框标题,简要说明确认的操作`,minLength:1,pattern:`\\S`}),message:n.String({description:`详细描述需要用户确认的内容`,minLength:1,pattern:`\\S`}),confirmText:n.Optional(n.String({description:`确认按钮文字,默认为"确认"`,minLength:1,pattern:`\\S`})),cancelText:n.Optional(n.String({description:`取消按钮文字,默认为"取消"`,minLength:1,pattern:`\\S`}))}),ui:{type:`action`,name:`confirm_dialog`},execute:async({title:e,message:t,confirmText:n,cancelText:r})=>({success:!0,title:e,message:t,confirmText:n??`确认`,cancelText:r??`取消`})})}const W=n.Union([n.Literal(`image`),n.Literal(`video`),n.Literal(`audio`)],{description:`媒体类型(必填):image/video/audio`});function G(){return t({name:`open_media_file_app`,category:`ui`,tags:[`媒体`,`文件`,`应用`],description:`在用户界面上打开指定媒体文件对应的应用界面。`,inputSchema:n.Object({path:n.String({description:`要打开的媒体文件完整路径`,minLength:1,pattern:`\\S`}),mediaType:W}),ui:{type:`action`,name:`media_file_app`},execute:async({path:e,mediaType:t})=>({success:!0,path:e,mediaType:t})})}function K(e){if(e===`~`)return o.homedir();if(e.startsWith(`~${a.sep}`)||a.sep===`\\`&&e.startsWith(`~/`))return a.join(o.homedir(),e.slice(2));if(!a.isAbsolute(e))throw Error(`目录路径必须是绝对路径,或使用 ~ 表示主目录: ${e}`);return a.normalize(e)}function q(){return t({name:`navigate_to_directory`,category:`ui`,tags:[`导航`,`目录`],description:`控制用户界面左侧的文件浏览器跳转到指定目录,让用户可以直接看到该目录下的文件列表`,inputSchema:n.Object({directory:n.String({description:`要跳转到的目录路径,必须是绝对路径;支持 ~ 表示主目录,如 ~/Desktop`,minLength:1,pattern:`\\S`})}),ui:{type:`action`,name:`navigate`},execute:async({directory:e})=>{if(typeof e!=`string`||e.trim().length===0)throw Error(`directory 必须是非空字符串`);let t=K(e.trim());if(!(await i(t)).isDirectory())throw Error(`不是目录: ${t}`);return{success:!0,directory:t}}})}H(),U(),G(),q();var J=s({activate:()=>[_]}),Y=s({activate:()=>[H(),U(),G(),q()]}),X=s({activate:()=>[c()]});export{d as UPDATE_PLAN_PROMPT,u as UPDATE_PLAN_TOOL_NAME,I as analyzeImage,z as analyzeImageTool,R as analyzeVideo,V as analyzeVideoTool,X as envExtension,L as generateImage,B as generateImageTool,c as getEnvironmentTool,q as navigateToDirectoryTool,U as openConfirmDialogTool,G as openMediaFileAppTool,J as planExtension,H as showToastTool,Y as uiActionsExtension,_ as updatePlanTool};
/**
* 分析图片工具(Vite 插件风格)
* 分析图片工具
*/
import type { Tool } from '@huyooo/ai-chat-core';
import type { ExtensionAiProvider } from '@huyooo/ai-chat-core/runtime';
export declare function analyzeImageTool(gemini: ExtensionAiProvider): Tool;
import type { GeminiVisionMediaConfig } from './geminiMediaConfig';
export declare function analyzeImageTool(config: GeminiVisionMediaConfig): Tool;
/**
* 分析视频工具(Vite 插件风格)
* 分析视频工具
*/
import type { Tool } from '@huyooo/ai-chat-core';
import type { ExtensionAiProvider } from '@huyooo/ai-chat-core/runtime';
export declare function analyzeVideoTool(gemini: ExtensionAiProvider): Tool;
import type { GeminiVisionMediaConfig } from './geminiMediaConfig';
export declare function analyzeVideoTool(config: GeminiVisionMediaConfig): Tool;

@@ -6,18 +6,9 @@ /**

*/
import type { ExtensionAiProvider } from '@huyooo/ai-chat-core/runtime';
/** Gemini 图片/视频理解模型 */
export declare const GEMINI_IMAGE_MODEL = "gemini-3-flash";
/** Gemini 图片生成模型 */
export declare const GEMINI_IMAGE_GEN_MODEL = "gemini-3-pro-image-preview";
/**
* 分析图片
*/
export declare function analyzeImage(gemini: ExtensionAiProvider, imagePath: string, question?: string, signal?: AbortSignal): Promise<string>;
/**
* 生成图片
*/
export declare function generateImage(gemini: ExtensionAiProvider, cwd: string, prompt: string, outputPath?: string, signal?: AbortSignal): Promise<string>;
/**
* 分析视频
*/
export declare function analyzeVideo(gemini: ExtensionAiProvider, videoPath: string, question?: string, signal?: AbortSignal): Promise<string>;
import type { GeminiImageGenMediaConfig, GeminiVisionMediaConfig } from './geminiMediaConfig';
export type { GeminiImageGenMediaConfig, GeminiMediaBaseConfig, GeminiVisionMediaConfig, } from './geminiMediaConfig';
/** 分析图片 */
export declare function analyzeImage(config: GeminiVisionMediaConfig, imagePath: string, question?: string, signal?: AbortSignal): Promise<string>;
/** 生成图片 */
export declare function generateImage(config: GeminiImageGenMediaConfig, cwd: string, prompt: string, outputPath?: string, signal?: AbortSignal): Promise<string>;
/** 分析视频 */
export declare function analyzeVideo(config: GeminiVisionMediaConfig, videoPath: string, question?: string, signal?: AbortSignal): Promise<string>;
/**
* 生成图片工具(Vite 插件风格)
* 生成图片工具
*/
import type { Tool } from '@huyooo/ai-chat-core';
import type { ExtensionAiProvider } from '@huyooo/ai-chat-core/runtime';
export declare function generateImageTool(gemini: ExtensionAiProvider): Tool;
import type { GeminiImageGenMediaConfig } from './geminiMediaConfig';
export declare function generateImageTool(config: GeminiImageGenMediaConfig): Tool;
/**
* 媒体工具导出(Gemini 图片/视频)
*/
export { analyzeImage, generateImage, analyzeVideo } from './gemini';
export { analyzeImage, analyzeVideo, generateImage, } from './gemini';
export type { GeminiImageGenMediaConfig, GeminiMediaBaseConfig, GeminiVisionMediaConfig, } from './gemini';
export { analyzeImageTool } from './analyze-image';
export { generateImageTool } from './generate-image';
export { analyzeVideoTool } from './analyze-video';
export { createGeminiDirectProvider } from './geminiDirectProvider';
{
"name": "@huyooo/ai-chat-tools-node",
"version": "0.3.22",
"version": "0.3.23",
"description": "AI Chat Node.js 工具集(execute-command、media、ui-actions 等纯 Node 工具)",

@@ -29,3 +29,3 @@ "type": "module",

"peerDependencies": {
"@huyooo/ai-chat-core": ">=0.3.22"
"@huyooo/ai-chat-core": ">=0.3.23"
},

@@ -36,3 +36,3 @@ "dependencies": {

"devDependencies": {
"@huyooo/ai-chat-core": "^0.3.22",
"@huyooo/ai-chat-core": "^0.3.23",
"@types/node": "^22.0.0",

@@ -39,0 +39,0 @@ "tsdown": "^0.21.0",