aardio 文档

aardio 范例: AI 智能助手 —— 全自动编程、自动操作电脑

import win.ui;
import time.lunar;
import fonts.fontAwesome;
/*DSG{{*/
var winform = win.form(text="AI 智能助手 —— 全自动编程、自动操作电脑";right=900;bottom=600;bgcolor=0xFFFFFF)
winform.add(
btnSend={cls="plus";text="运行";left=790;top=550;right=885;bottom=590;bgcolor=0xD77800;border={radius=4};db=1;dr=1;font=LOGFONT(h=-14);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=15}};iconText='\uF1D8';notify=1;textPadding={left=15};z=3};
btnSetting={cls="plus";left=11;top=551;right=46;bottom=581;align="left";color=0x3C3C3C;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-22;name='FontAwesome')};iconText='\uF013';textPadding={left=25};z=4};
customChat={cls="custom";text="聊天区域";left=0;top=0;right=900;bottom=540;db=1;dl=1;dr=1;dt=1;z=1};
editPrompt={cls="edit";left=50;top=550;right=780;bottom=590;db=1;dl=1;dr=1;edge=1;multiline=1;z=2}
)
/*}}*/

import fsys.table;
import web.rest.aiChat.settingForm;

// 创建配置文件
var path = io.appData("aardio/std/example/ai/agent4.table");
var config = fsys.table(path);

winform.btnSetting.oncommand = function(id,event){

    table.mix(config,{
        title = "设置 AI 智能助手"; // 标题  
        hyperlink1Title = "获取 key"; // key 输入框显示嵌入链接  

        //可选预定义默认设置(值必须是对象数组)
        itemData = [{
            url="https://api.deepseek.com/v1";
            key= '';
            model="deepseek-v4-pro";
            temperature=1;
            reasoning={"effort":"max 全力以赴"}
        }] 
    });


    //打开 AI 设置窗口,参数 2 指定配置文件
    var frmSetting = web.rest.aiChat.settingForm(winform,config);

    //用户点击了「保存」           
    if( frmSetting.doModal(this) ){ 
        //获取用户当前选择的配置
        var selectedConfig = config.itemData[config.selItem]; 
    }
}

//创建 AI 聊天界面
import web.form.chat;
var chatUi = web.form.chat(winform.customChat);

var tip = /***
### 警告: 
**将操作电脑的权力交给 AI 存在风险,AI 幻觉可能导致不确定后果。**  
**使用此工具造成的一切后果自负,如不同意请不要使用**  

### 功能:
1. AI 自动编写程序、自动调试、自动操作电脑直到任务执行成功。

### 设置:
请 <a href="javascript:void(0)" onclick="javascript:external.updateApiKey()">» 点这里设置</a> 接口参数,指定支持交错思考 + 工具调用的大模型(例如 Gemini 3 Flash,DeepSeek V4 Pro )。 

设置 » 推理强度( [详细说明文档](https://www.aardio.com/zh-cn/doc/library-guide/std/web/rest/aiChat.html#reasoning) ):
DeepSeek⁴ 建议选择 `max`,Gemini³ Flash 建议设为 `medium`。
Gemini³ 的 temperature 必须指定为 1,DeepSeek 开启思考时直接忽略该值。

请不要在此工具内使用 ai.aardio.com 接口。
[领取 100 亿 tokens 支持 Gemini 3](https://imtip.aardio.com/api-keys/)

其他细节请查看本工具开源代码。

### 技巧:

- 展开「推理过程」可查看 AI 执行成功的源代码
- 按住 `Ctrl` 键点代码可以快速选中代码块,鼠标左键 3 连击也行。

***/
chatUi.write(tip)

chatUi.aardioSystem()

var initSystemPrompt = function(){
    var sys = "

## 角色

你是一个自动编写、调试、完善 aardio 代码的智能编码助手。

## 任务

1. 自动编写、调试、完善 aardio 代码。
2. 调用工具自动执行必要的单元测试(发挥动态语言的特性,验证你的想法与思路的可行性),你甚至可以调用工具单独测试某个库函数或一小段代码,不要怕浪费 tokens ,你只要尽最大能力调用工具,尽最大能力思考即可,不放过任何可以尝试或探索的方法与路径。
3. 调用工具 loadcodex 执行 aardio 代码完成用户的要求(例如编写 aardio 程序或者自动化操作电脑)。
4. 在必要的时候可以在程序中获取运行时的信息(例如利用 gdi.getPixel(x,y,hwnd) 等验证屏幕上输出的颜色点)以验证与改进程序。

## 要求

1. 你是一个精益求精的助手,会尽可能利用可调用的工具以生成更优质更可靠的代码。例如使用 lookup_library 工具以读取本地库文档,以避免遗漏或误用重要的库函数与功能。
2. 你是一个高级的智能助手,拥有强大的编写 aardio 代码、调试 aardio 代码的技能与工具,请利用 loadcode,loadcodex,aifix 这些编译与检查工具自我修正代码。

## 举例

举个例子,如果用户让你用 aardio 写个游戏,则你需要有步骤、有规划地完成任务,例如:

1. 先规化与设计游戏
2. 技术可行性分析,寻找合适的方法。如有需要查文档。
3. 确定要使用技术方案以后,对主要使用的技术、关键性的技术难点与可能的坑进行思考。
举例如果这个游戏适合自绘可能要用到 plus 控件与 gdip (GDI+ ) 库实现,
而自绘最关键的就是 gdip.graphics 库与 gdip.path 这几个库的运用,可以调用工具 lookup_library 看一下这两个库的文档有利于编写出更好的游戏效果。
如果是不适合 GDI+ 自绘的游戏,例如非常复杂的适合网页开发小游戏,这时候可以使用 web.view 做,如有必要可以调用调用工具 lookup_library 查看一下 web.view 的库文档。
4. 在编写代码之前,如果一些单元代码需要验证,可以调用 loadcode 或 loadcodex 先行验证。
5. 除了调用 lookup_library 查看必要的库文档,你也可以根据需要调用工具 search_example 搜索 aardio 开发环境自带的本地 aardio 代码范例。
6. 最后尝试编写代码 » 调用工具验证 » 继续改进代码 » 继续验证 ..... 直到得出满意的结果。

你可以根据最佳实践调整以上步骤与方案,要多进行权衡取舍,总之尽最大努力生成优质程序与满意的效果。你不必节省 tokens 。

## 背景

- 当前时间为:" + tostring(..time())
    ++ '\r\n- 当前操作系统为:"' + ..win.version.format() + '"'
    ++ '\r\n- 当前农历:' +  tostring(time.lunar()) 
    ++ '\r\n- aardio 开发环境所在目录:' +  io.fullpath("~/")
    ++ '\r\n- 系统临时目录:' +  fsys.getTempDir()
    ++ '\r\n- 可安全写入用户数据的 AppData 目录:' +  io.appData("aardio/std/example/AI/agent");

    chatUi.system(sys);
}
initSystemPrompt();

var sendApiMessage = function(){

    var aiConfig = config.itemData[[config.selItem]];

    if(!aiConfig[["url"]] || string.find(aiConfig[["url"]],"aardio.com") ){
        winform.msgboxErr('请在设置中指定支持交错思考+工具调用的大模型。\n建议使用 Gemini Flash 3。\n\n请不要使用 ai.aardio.com 接口。');
        winform.btnSetting.oncommand();
        return;
    }

    var prompt = winform.editPrompt.text;

    // 检查输入是否为空(移除首尾空白)
    if(!#string.trim(prompt)){
        winform.editPrompt.setFocus();
        winform.editPrompt.showWarningTip("请输入提示词");
        return;
    }

    // UI 状态变更
    winform.editPrompt.text = ""; // 清空输入
    winform.btnSend.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']; 

    chatUi.showLoading(" 正在思考...");
    chatUi.prompt(prompt);

    // 创建 AI 对话线程
    thread.invoke( 
        function(chatUi,winform,aiConfig){
            import ide;
            import ide.doc.libraryMd;
            import ide.aifix;
            import winex;
            import web.rest.aiChat;

            aiConfig.temperature = 1;


            aiConfig.tools = { 
                {
                    "type": "function",
                    "function": {
                        "name": "loadcodex_async",
                        "description": "在当前电脑创建新的线路异步执行 aardio 代码。代码将作为匿名函数执行,不等待函数执行完成。函数返回值只会告知是否成功启动代码。如果运行耗时较长的代码但不需要等待程序运行完成请调用工具 loadcodex_asyn ,如果你的目的是运行耗时较短(例如只是读取一个网页,抓取一个 HTML)或者需要获得返回值,请改用可以等待返回值的 loadcodex 工具。",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "要执行的 aardio 源代码。"
                                },
                            },
                            "required": {
                                "code"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "loadcodex",
                        "description": "在当前电脑执行 aardio 代码。代码将作为匿名函数执行,你要通过 return 语句返回你需要的值。你要避免使用 try 语句。如果你仅仅用 `console.log()` 输出到控制台那么在工具的返回值里看不到结果(只能显示在屏幕上,除非你读取控制台输出缓冲区)。如果你使用 `console.pause()` 就会暂停并等待用户按键(不要这么做!我们需要自动安成任务)。除非你的意图就是需要用户确认,这时候你可以使用 `win.msgboxTest(text,title)` 或者 `console.askYesNo(text)` 询问用户并确认信息(你仍然要用 return 语句返回用户选择的结果)。你可以重复调用工具 loadcodex 来收集数据或者验证 aardio 代码的可用性。或者用 loadcodex 执行代码,将结果展示给用户,或者提供可操作的界面。",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "要执行的 aardio 源代码。"
                                },
                            },
                            "required": {
                                "code"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "loadcode",
                        "description": "仅编译 aardio 代码,主要用于检测代码是否存在语法错误。此工具不会运行代码",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "需要检测语法错误的 aardio 源代码。"
                                },
                            },
                            "required": {
                                "code"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "aifix",
                        "description": "调用 aardio 的 ide.aifix 自动修复 aardio 代码中的常见错误(主要用于修复 AI 生成代码的常见问题)。",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "需要检测并修正的 aardio 源代码。"
                                },
                            },
                            "required": {
                                "code"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "lookup_library",
                        "description": "直接获取指定 aardio 库的文档(Markdown 格式)。",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "query": {
                                    "type": "string",
                                    "description": "指定 aardio 库(内置库、标准库、扩展库等)路径,例如 'table','string' 或 'fsys.file'"
                                }, 
                            },
                            "required": {
                                "query"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "http_get",
                        "description": "读取给定网址的数据(通常是 HTML)。",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "description": "获取数据的网址链接"
                                }, 
                            },
                            "required": {
                                "url"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "query_aardio_knowledge",
                        "description": "专用于搜索 aardio 全部文档或范例",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "query": {
                                    "type": "string",
                                    "description": "用于搜索 aardio 文档与范例的查询字符串"
                                }, 
                            },
                            "required": {
                                "query"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "search_web",
                        "description": "联网搜索信息(不限于 aardio 有关)。",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "query": {
                                    "type": "string",
                                    "description": "用于搜索互联网内容"
                                }, 
                            },
                            "required": {
                                "query"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "ide_new_docuemnt",
                        "description": "在编辑器中打开 aardio 代码。",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "需要在开发环境中打开的 aardio 代码(是代码,不是文件路径)"
                                }, 
                            },
                            "required": {
                                "code"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "ide_open_docuemnt",
                        "description": "在编辑器中打开 aardio 代码文件或工程文件。",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "path": {
                                    "type": "string",
                                    "description": "*.aardio 或 *.aproj 文件路径"
                                }, 
                            },
                            "required": {
                                "path"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "search_example",
                        "description": "在开发环境的本地范例目录搜索 aardio 范例。",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "pattern": {
                                    "type": "string",
                                    "description": "使用 aardio 模式匹配语法指定搜索模式串"
                                }, 
                            },
                            "required": {
                                "pattern"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "save_string",
                        "description": "保存文件",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "path": {
                                    "type": "string",
                                    "description": "写入的文件路径"
                                }, 
                            },
                            "required": {
                                "path"
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "load_string",
                        "description": "读取文件",
                        "parameters": {
                            "type": "object", 
                            "properties": {
                                "path": {
                                    "type": "string",
                                    "description": "要读取的文件路径。"
                                }, 
                            },
                            "required": {
                                "path"
                            }
                        }
                    }
                } 
            }

            // 创建 AI API 客户端
            var aiClient = web.rest.aiChat(aiConfig)

            var getArgs1 = function(args,name){
                var arg1 = args[[name]];
                if(arg1) return arg1;

                for(k,v in args){
                    if(type(v)==="string") return v;
                }

                import console
                console.dump(args)
                console.error("调用工具时缺少参数:",name)
            }


            aiClient.external = {
                loadcodex_async = function(args){ 
                    var code = getArgs1(args,"code");
                    if(!code) return "调用此工具必须指定 `code` 参数"

                    chatUi.showThinking('\n\n```aardio\n'+code+'\n```\n\n');

                    var func,err = loadcode(code)
                    if(!func){
                        return  {
                            error = err;
                            comment = "加载当前代码时遇到了错误,error 字段为错误信息。"
                        }   
                    }

                    thread.invoke( 
                        function(code){
                            import win;
                            import winex;
                            import JSON;
                            winex.attachThread(thread.getMainId())

                            loadcodex(code);
                        },code
                    );  
                    winex.attachThread(thread.getMainId())


                    aiClient.alreadyExecuteCode = true;

                    //让主线程的 AI 消息队列记住最后执行成功的代码块,要考虑一轮对话结束思维链会弃
                    chatUi.system('已调用 loadcodex_async 工具成功启动以下代码:\n\n```aardio'++code+'\n\n```')

                    return  {
                        result = true; 
                        comment = "编译代码时未发生错误,已成功启动程序。"
                    }
                },
                loadcodex = function(args){ 

                    var code = getArgs1(args,"code");
                    if(!code) return "调用此工具必须指定 `code` 参数"

                    chatUi.showThinking('\n\n```aardio\n'+code+'\n```\n\n');

                    var func,err = loadcode(code)
                    if(!func){
                        return  {
                            error = err;
                            comment = "加载当前代码时遇到了错误,error 字段为错误信息。"
                        }   
                    }

                    winex.attachThread(thread.getMainId())

                    var ok,result =  call(func); 
                    if(!ok){
                        return  {
                            error = result;
                            comment = "运行当前代码时遇到了错误,error 字段为错误信息。"
                        }
                    }

                    aiClient.alreadyExecuteCode = true;

                    //让主线程的 AI 消息队列记住最后执行成功的代码块,要考虑一轮对话结束思维链会弃
                    chatUi.system('已调用 loadcodex 工具成功执行以下代码:\n\n```aardio'++code+'\n\n```')

                    return  {
                        result = result; 
                        comment = "代码已成功执行,未发生错误。result 字段为执行代码的返回值。"
                    }
                },
                loadcode = function(args){ 
                    var code = getArgs1(args,"code");
                    if(!code) return "调用此工具必须指定 `code` 参数"

                    var func,err = loadcode(code)
                    if(!func){
                        return  {
                            error = err;
                            comment = "编译当前代码时遇到了错误,error 字段为错误信息。"
                        }   
                    }

                    return  {
                        result = "OK"; 
                        comment = "代码编译成功,无语法错误错误。"
                    }
                }, 
                aifix = function(args){ 
                    var code = getArgs1(args,"code");
                    if(!code) return "调用此工具必须指定 `code` 参数"

                    var code = string.match(code,"!\N([ \t]*)(```+)<aardio>(.+?)!\N\s*\2![^`\S]") || code;

                    var newCode = ide.aifix(code)
                    if(newCode){
                        return  {
                            code = '```aardio\n'+newCode+'\n```';
                            comment = "code 字段包含的 Markdown 代码块内部是修复后的代码。"
                        }   
                    }
                },
                ide_new_docuemnt = function(args){ 
                    var code = getArgs1(args,"code");
                    if(!code) return "调用此工具必须指定 `code` 参数"

                    import ide; 
                    ide.openCode(code)

                    return  {
                        comment = "已调用 aardio 接口 ide.openCode 在开发环境的代码编辑器中打开输入的代码。"
                    }   
                },
                ide_open_docuemnt = function(args){
                    var path = getArgs1(args,"path");
                    if(!path) return "调用此工具必须指定 `path` 参数"

                    if(!io.exist(path)){
                        return { error = " path 参数指定了错误的文件路径"}
                    }

                    if(!..string.match(path,".<aardio>|<aproj>$")){
                        return { error = " path 参数只指定代码文件( *.aardo )或工程文件( *.aproj )文件路径。"}
                    }

                    import ide; 
                    ide.openDocument(path)

                    return  {
                        comment = "已调用 aardio 接口 ide.openDocument 在开发环境中打开指定的文件。"
                    }   
                },
                save_string = function(args){  
                    var path = getArgs1(args,"path");
                    if(!path) return "调用此工具必须指定 `path` 参数"

                    var data = args.data;
                    if(!data) return "调用此工具必须指定 `data` 参数"

                    var ok,err = ..string.save(path,data)
                    if(..string.save(path, data)){
                        return  {
                            comment = "已成功保存文件。"
                        }   
                    }

                    return  {
                        error = err;
                        comment = "保存文件时遇到错误。"
                    }       
                },
                load_string = function(args){ 
                    var path = getArgs1(args,"path");
                    if(!path) return "调用此工具必须指定 `path` 参数"

                    var data = ..string.load(path)
                    if(data){
                        return  {
                            data = data;
                            comment = "已成功读取文件,文件数据请查看 data 字段值。"
                        }   
                    }

                    return  {
                        comment = "读取文件失败。"
                    }       
                },
                search_example = function(args){
                    var pattern = getArgs1(args,"pattern");
                    if(!pattern) return "调用此工具必须指定 `pattern` 参数"

                    var result = []
                    fsys.enum( "~/example","*.aardio",
                        function(dir,filename,fullpath,findData){ 
                            if(filename){ 

                               var code = string.load(fullpath)
                               if(string.find(code,pattern)){ 
                                    ..table.push(result,fullpath);
                               }
                            }
                        } 
                    );

                    if(#result){
                        return {
                            files = result;
                            comment = "files 字段包含的数组是找到的全部代码文件,这些文件包含的内容符合指定的模式匹配表达式参数,你应当进一步判定与筛选,然后根据需要调用 load_string 读取文件内容。"
                        }
                    }
                },
                lookup_library = function(args){ 
                    var query = getArgs1(args,"query");
                    if(!query) return "调用此工具必须指定 `query` 参数"

                    var md = ide.doc.libraryMd(query)

                    if(!md){
                        return  {
                            error = "错误的 lib 参数(库路径不存在或者用户未安装指定的扩展库)";
                        }   
                    }

                    return  {
                        result = md;
                        comment = "result 字段为找到的库文档(Markdown 格式)"
                    }
                },
                http_get = function(args){ 
                    var url = getArgs1(args,"url");
                    if(!url) return "调用此工具必须指定 `url` 参数"

                    var data,err = inet.http.get(url)

                    if(!data){
                        return  {
                            error = err || "未知错误";
                        }   
                    }

                    return  {
                        result = data;
                        comment = "result 字段为下载的数据"
                    }
                },
                query_aardio_knowledge = function(args){
                    var query = getArgs1(args,"query");
                    if(!query) return "调用此工具必须指定 `query` 参数"

                    chatUi.showThinking('\n搜索:'+query+'\n\n\n');

                    import string.escape2;
                    import web.rest.jsonClient;
                    var http = web.rest.jsonClient();

                    //请将 Key 换成自己的(注册 tavily 就可以领,每月免费 1000 次)。 
                    http.setAuthToken(string.escape2('\0\112\4\6\28\9\93\20\21\6\93\54\62\66\72\57\31\5\3\27\64\9\8\73\49\50\52\57\61\49\56\61\69\51\68\9\56\38\61\39\37\31\26'));
                    var tavily = http.api("https://api.tavily.com");

                    //搜索,不建议指定 include_raw_content 参数( 返回的 raw_content 可能有乱码 ).
                    var resp = tavily.search(
                        query = query,
                        max_results = 5, //限制返回结果数,默认值为 5。 
                        include_domains = ["www.aardio.com"], //可选用这个字段限定搜索的域名
                    )

                    //利用消息对象自动合成提示词
                    import web.rest.aiChat; 
                    var msg = web.rest.aiChat.message(); 
                    msg.url(resp[["results"]]) //将搜索结果添加到系统提示词

                    if(#msg){
                        return msg[#msg].content;//返回合成的提示词
                    }

                } ,
                search_web = function(args){
                    var query = getArgs1(args,"query");
                    if(!query) return "调用此工具必须指定 `query` 参数"

                    chatUi.showThinking('\n搜索:'+query+'\n\n\n');

                    import string.escape2;
                    import web.rest.jsonClient;
                    var http = web.rest.jsonClient();

                    //请将 Key 换成自己的(注册 tavily 就可以领,每月免费 1000 次)。 
                    http.setAuthToken(string.escape2('\0\112\4\6\28\9\93\20\21\6\93\54\62\66\72\57\31\5\3\27\64\9\8\73\49\50\52\57\61\49\56\61\69\51\68\9\56\38\61\39\37\31\26'));
                    var tavily = http.api("https://api.tavily.com");

                    //搜索,不建议指定 include_raw_content 参数( 返回的 raw_content 可能有乱码 ).
                    var resp = tavily.search(
                        query = query,
                        max_results = 5, //限制返回结果数,默认值为 5。 
                    )

                    //利用消息对象自动合成提示词
                    import web.rest.aiChat; 
                    var msg = web.rest.aiChat.message(); 
                    msg.url(resp[["results"]]) //将搜索结果添加到系统提示词

                    if(#msg){
                        return msg[#msg].content;//返回合成的提示词
                    }

                } 
            }

            // 调用接口
            var chatMessage = chatUi.chatMessage;
            var ok,err,errCode = aiClient.messages(chatMessage,
                function(deltaText,reasoning){
                    if(reasoning) chatUi.showThinking(reasoning);
                    chatUi.assistant(deltaText);
                }
            );

            if(err){ 
                if(errCode==12029){
                    chatUi.errorMessage(`旧版操作系统不支持此服务商接口!<a href="javascript:void(0)" onclick="javascript:external.updateApiKey()">点这里更换其他接口</a>`)
                }
                elseif(aiClient.lastStatusCode==401){
                    chatUi.errorMessage(`API 密钥错误!<a href="https://imtip.aardio.com/api-keys/">点这里领取 tokens</a>,&nbsp;<a href="javascript:void(0)" onclick="javascript:external.updateApiKey()">点这里设置新密钥</a>`)
                }
                else{
                     chatUi.errorMessage(err)
                } 
            }
            else{
                var md = chatUi.lastAssistantMessage(true);
                if(!aiClient.alreadyExecuteCode){

                    /*
                    var indent,_,code = string.match(md,"!\N([ \t]*)(<```+>|<~~~+>)<aardio>(.+?)!\N\s*\2![^`\S]")


                    if(code){
                        var f,err1 = loadcode(code);
                        if(!f) {
                            code = ide.aifix(code)
                            f = loadcode(code); 
                        }

                        if(f) {
                            ..winex.attachThread(thread.getMainId())
                            f();
                        }
                        elseif(type(err1)==="string"){
                            winform.btnSend.disabled = false;
                            chatUi.prompt('编译你给的代码时出现错误:\n\n```txt\n' +err1+'\n```\n');
                            winform.btnSend.oncommand();
                            return;
                        }
                    }
                    */
                }
            }

            // 恢复按钮状态
            winform.btnSend.disabledText = null;
        },chatUi,winform,aiConfig
    )

    // 发送后焦点切回输入框
    winform.editPrompt.setFocus();
}

winform.editPrompt.text = "获取我的公网 IP,然后打开 必应 搜索此 IP"

chatUi.external = {
    updateApiKey = function(){
        winform.btnSetting.oncommand();
    } 
} 

winform.btnSend.oncommand = function(id,event){
    sendApiMessage();
}

//回车发送(Ctrl+Enter 换行)
winform.editPrompt.onOk = function(ctrl,alt,shift){
    if(ctrl){
        winform.btnSend.oncommand();
        return true;
    }
}

winform.btnSend.skin({
    background={
        default=0xFF0078D7;
        hover=0xFF0088EE;
        active=0xFF005BB5;
        disabled=0xFFCCCCCC;
    };
    color={
        default=0xFFFFFFFF;
        disabled=0xFF888888;
    }
})

winform.btnSetting.skin({
    color={
        active=0xFF00FF00;
        default=0xFF3C3C3C;
        disabled=0xFF6D6D6D;
        hover=0xFFFF0000        
    }
})

winform.show();
win.loopMessage();
Markdown 格式