aardio 文档
aardio 范例: 全自主智能体
import autos;
if(_WIN7_LATER) ::Shell32.SetCurrentProcessExplicitAppUserModelID(autos.appUserModelId) //在任务栏显示为分离图标(避免合并到 aardio.exe 分组)
import fonts.fontAwesome;
import com.interface.IRichEditOleCallback;
import win.clip;
import process.admin;
import win.inputBox;
import win.ui;
/*DSG{{*/
mainForm = win.form(text=autos.title;right=900;bottom=600;bgcolor=0xFFFFFF)
mainForm.add(
bkPrompt={cls="bkplus";left=222;top=547;right=788;bottom=594;border={color=0xC0C0C0;radius=16;width=1};db=1;dl=1;dr=1;z=1};
btnClear={cls="plus";left=134;top=556;right=169;bottom=585;align="left";bgcolor=0xFFFFFF;color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-22;name='FontAwesome');padding={left=8}};iconText='\uF014';notify=1;textPadding={left=25};z=6};
btnCopy={cls="plus";left=176;top=556;right=211;bottom=585;align="left";bgcolor=0xFFFFFF;color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-22;name='FontAwesome');padding={left=8}};iconText='\uF0C5';notify=1;textPadding={left=25};z=7};
btnFeishu={cls="plus";left=49;top=556;right=84;bottom=586;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-22;name='FontAwesome')};iconText='\uF1D8';notify=1;textPadding={left=25};z=9};
btnImageAttachment={cls="plus";left=752;top=556;right=784;bottom=585;align="left";bgcolor=0xFFFFFF;border={radius=4};color=0x3C3C3C;db=1;dr=1;font=LOGFONT(h=-13);foreRepeat="scale";iconStyle={font=LOGFONT(h=-19;name='FontAwesome');padding={top=2}};iconText='\uF030';notify=1;paddingBottom=2;paddingLeft=2;paddingRight=2;paddingTop=2;textPadding={left=25};z=11};
btnSend={cls="plus";text="运行";left=794;top=550;right=889;bottom=590;bgcolor=0xD77800;border={radius=4};color=0xFFFFFF;db=1;dr=1;font=LOGFONT(h=-14);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=15;top=1}};iconText='\uF1B9';notify=1;textPadding={left=15};z=4};
btnSetting={cls="plus";left=6;top=556;right=41;bottom=586;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-22;name='FontAwesome')};iconText='\uF013';notify=1;textPadding={left=25};z=5};
btnWeixin={cls="plus";left=91;top=556;right=126;bottom=586;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-22;name='FontAwesome')};iconText='\uF1D7';notify=1;textPadding={left=25};z=8};
customChat={cls="custom";text="聊天区域";left=0;top=0;right=900;bottom=540;db=1;dl=1;dr=1;dt=1;z=2};
editPrompt={cls="richedit";left=228;top=554;right=748;bottom=589;autohscroll=false;db=1;dl=1;dr=1;multiline=1;z=3};
lableMessage={cls="plus";left=66;top=474;right=821;bottom=528;bgcolor=0x008000;border={radius=12};color=0xFFFFFF;db=1;dl=1;dr=1;font=LOGFONT(h=-14);hide=1;z=10}
)
/*}}*/
mainForm.btnSend.skin({
background={
default=0xFF0078D7;
hover=0xFF0088EE;
active=0xFF005BB5;
disabled=0xFFCCCCCC;
};
color={
default=0xFFFFFFFF;
disabled=0xFF888888;
};
checked={
background={
default=0xFFD13438;
hover=0xFFE35458;
active=0xFFA82A2D;
disabled=0xFFCCCCCC;
};
color={
default=0xFFFFFFFF;
disabled=0xFF888888;
}
}
})
mainForm.btnSetting.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
})
mainForm.btnFeishu.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
checked = {
color={
active=0xFF00FF00;
default=0xFF3370FF;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
}
})
mainForm.btnClear.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
mainForm.btnCopy.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
mainForm.btnWeixin.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
checked = {
color={
active=0xFF00FF00;
default=0xFF07C160;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
}
})
mainForm.btnImageAttachment.skin({
background={
active=0xFFCCCCCC;
default=0x00000000;
hover=0xFFE6E6E6;
};
color={
active=0xEE333333;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
mainForm.editPrompt.adjustInputLayout = function(focus){
var w,h = mainForm.dpiScale(1,1);
h = h * 50;
focus = focus && !mainForm.btnSend.busy();
if(focus){
if( ! mainForm.editPrompt["(focusedHeight)"] ){
mainForm.bkPrompt.top = mainForm.bkPrompt.top - h;
mainForm.bkPrompt.redraw();
mainForm.customChat.bottom = mainForm.customChat.bottom - h;
mainForm.editPrompt.top = mainForm.editPrompt.top - h;
mainForm.editPrompt["(focusedHeight)"] = true;
}
}
else{
if( mainForm.editPrompt["(focusedHeight)"] ){
mainForm.bkPrompt.top = mainForm.bkPrompt.top + h;
mainForm.bkPrompt.redraw();
mainForm.customChat.bottom = mainForm.customChat.bottom + h;
mainForm.editPrompt.top = mainForm.editPrompt.top + h;
mainForm.editPrompt["(focusedHeight)"] = false;
}
}
}
var defaultPrompt = "获取我的公网 IP,然后打开 必应 搜索此 IP";
mainForm.editPrompt.onFocusGot = function(){
if(#defaultPrompt){
if(owner.text == defaultPrompt){
owner.text = "";
}
defaultPrompt = "";
}
mainForm.editPrompt.adjustInputLayout(true);
}
mainForm.editPrompt.onFocusLost = function(){
mainForm.editPrompt.adjustInputLayout(false);
}
mainForm.editPrompt.langOptions = 2/*_IMF_AUTOFONT*/;
mainForm.afterDpiChanged = function(){
mainForm.setIcon("/autos.ico");
}
mainForm.show();
import fsys.table;
import web.rest.aiChat.settingForm;
var userDataPath = io.appData("aardio/autos");
var agentConfigPath = io.appData("aardio/autos/agent.table");
/*UPDATE{{*/
if(!io.exist(userDataPath)){
var oldUserDataPath = io.appData("aardio/std/example/ai/autos");
if(io.exist(oldUserDataPath)){
if(!fsys.move(oldUserDataPath,userDataPath)){
userDataPath = oldUserDataPath;
}
}
if(!io.exist(agentConfigPath)){
var oldAgentConfigPath = io.appData("aardio/std/example/ai/agent4.table");
if(!fsys.move(oldAgentConfigPath,agentConfigPath)){
agentConfigPath = oldAgentConfigPath;
}
}
}
/*}}*/
var agentWorkspace = io.createDir( io.joinpath(userDataPath,"workspace") );
var config = fsys.table(agentConfigPath,{
itemNames = ["默认"];
selItem = 1;
itemData = [{
url="https://api.deepseek.com/v1";
key= '';
model="deepseek-v4-pro";
temperature=1;
reasoning={"effort":"max 全力以赴"}
}]
});
var aiChatConfig = config.itemData[config.selItem];
import thread.event;
// 手动复位事件:set 后 wait(0) 会持续返回 true,直到下一轮请求调用 reset()。用于表示“用户已请求停止”的持续状态。
var eventStop = thread.event(,true);
//创建 AI 聊天界面
import web.form.chat;
var chatUi = web.form.chat(mainForm.customChat);
import com.interface.ITaskbarList3;
var taskbar = _WIN7_LATER && com.interface.ITaskbarList3.Create();
var sendApiMessage = function(resentCot,prompt){
if(!aiChatConfig[["url"]] || string.find(aiChatConfig[["url"]],"aardio.com") ){
mainForm.btnSend.checked = false;
mainForm.msgboxErr('请在设置中指定支持交错思考+工具调用的大模型。\n建议使用 DeepSeek Pro。\n\n请不要使用 ai.aardio.com 接口。');
mainForm.btnSetting.oncommand();
return;
}
if(!resentCot){
var clearPrompt;
if(!prompt) {
prompt = mainForm.editPrompt.text;
clearPrompt = true;
}
if(mainForm.btnSend.text!=="重试"){
// 检查输入是否为空(移除首尾空白)
if(!#string.trim(prompt)){
mainForm.btnSend.checked = false;
mainForm.msgboxErr("请输入提示词");
mainForm.editPrompt.setFocus();
return;
}
}
else{
chatUi.clearErrorMessage();
}
// UI 状态变更
if(clearPrompt)mainForm.editPrompt.text = ""; // 清空输入
..thread.set("resumeChainOfThought",null);
..thread.set("resumeChainOfThoughtProtocol",null);
}
elseif(!..thread.get("resumeChainOfThought")){
mainForm.btnSend.checked = false;
mainForm.msgbox("没有意外中断的交错思维链需要恢复!"," aardio autos ","warn");
return;
}
mainForm.btnClear.disabled = true;
eventStop.reset();
var loading = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250' }
mainForm.btnSend.text = "停止";
mainForm.btnSend.checked = true;
//显示动画,但启用按钮
mainForm.btnSend.reduce(loading,function(value,index){
if(value) mainForm.btnSend.iconText = value;
return 150;
} )
if(!resentCot){
chatUi.showLoading(" 正在思考...");
chatUi.prompt(prompt);
}
mainForm.editPrompt.adjustInputLayout(false);
mainForm.btnSend.setFocus();
config.chatMessages = chatUi.chatMessages;
if(taskbar) taskbar.SetProgressState(mainForm.hwnd,1/*_TBPF_INDETERMINATE*/);
// 创建 AI 对话线程
chatUi.aiChatThread = thread.create(
function(chatUi,mainForm,aiChatConfig,aiConfigItems,eventStop,fromWeiXinClawBotMessage,fromFeishuMessageId,feishuClientInstance,resentCot,hasImageAttachment){
import web.rest.aiChat;
import autos.tools.schemas;
import autos.tools.handlers;
import autos;
aiChatConfig.tools = autos.tools.schemas;
aiChatConfig.userAgent = "autos/" + autos.version +"(Windows NT "+ _WIN_VER_MAJOR +"."+_WIN_VER_MINOR+"; +https://aau.cn)";
// 创建 AI API 客户端
var aiClient = web.rest.aiChat(aiChatConfig);
aiClient.referer = "https://aau.cn";
aiClient.setHeaders({
"X-Title":"aadio autos",
});
import win.inputBox;
..subscribe("afterConsoleOpen",function(){
if(console){
console.setTitle("autos console - 点击本窗口关闭控钮将关闭对话系统")
console.setCtrlHandlerThread( function(ctrlType){
mainForm.saveChatMessage(); //用户直接关闭 AI 打开的 console 窗口时保存对话
},mainForm);
}
} );
aiClient.external = autos.tools.handlers;
autos.tools.handlers.__init__(null,{
aiChatConfig = aiChatConfig;
aiConfigItems = aiConfigItems;
chatUi = chatUi;
fromWeiXinClawBotMessage = fromWeiXinClawBotMessage;
fromFeishuMessageId = fromFeishuMessageId;
feishuClientInstance = feishuClientInstance;
mainForm = mainForm;
});
var resumeChainOfThoughtProtocol;
var chatMessages = chatUi.chatMessages;
if(resentCot){
chatMessages = ..thread.get("resumeChainOfThought");
resumeChainOfThoughtProtocol = ..thread.get("resumeChainOfThoughtProtocol");
if( resumeChainOfThoughtProtocol){
if(resumeChainOfThoughtProtocol!=aiClient._protocol){
chatUi.onComplete(false);
chatUi.errorMessage("恢复思维链时不能将原接口使用的协议类型 " + resumeChainOfThoughtProtocol + " 更改为 " + aiClient._protocol);
mainForm.btnSend.text = "继续";
return;
}
}
var userPrompt = string.trim(mainForm.editPrompt.text);
if(#userPrompt){
..table.push(chatMessages,{
role = "user";
content = userPrompt;
});
}
else{
if(chatMessages[#chatMessages][["role"]]=="assistant"){
..table.push(chatMessages,{
role = "user";
content = "继续";
});
}
}
mainForm.editPrompt.text = "";
}
elseif(hasImageAttachment){
var msg = chatMessages[#chatMessages];
if(msg.role=="user"){
msg.content = msg.content + '\n\n用户提供了附件图像,请使用工具 analyze_image 识别图像(`imageUrlOrPath` 参数请指定为 `attachment`)。'
}
}
aiClient.beforeToolCalling = lambda () !eventStop.wait(0);
aiClient.onToolCalling = lambda (name,args) !eventStop.wait(0);
aiClient.afterToolCalling = function (chatMessages){
..thread.set("resumeChainOfThought",chatMessages);
..thread.set("resumeChainOfThoughtProtocol",aiClient._protocol);
return !eventStop.wait(0);
}
var ok,err,errCode,sendBackProtocol = aiClient.messages(chatMessages,
function(deltaText,reasoning){
if(eventStop.wait(0)){
chatUi.assistant(null);
return false;
}
if(reasoning) chatUi.showThinking(reasoning);
chatUi.assistant(deltaText);
},,resumeChainOfThoughtProtocol
);
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="javascript:void(0)" onclick="javascript:external.updateApiKey()">点这里设置新密钥</a>`)
}
else{
if(type.isString(err)
&& string.find(string.lower(err)
,`<%<<balance>|<credit>|<quota>><<insufficient>|<exhausted>|<exceeded>|<run\s*out>>>|<%<<insufficient>|<exhausted>|<exceeded>|<depleted>><<balance>|<credit>|<quota>|<fund>>>`)){
chatUi.errorMessage(string.concat("余额不足,请及时充值或联系 API 接口服务商("+aiChatConfig.url+")。<code>",err,"</code>"))
}
elseif(#err){
chatUi.errorMessage(err)
}
elseif( (errCode===0 /*无其他错误*/) && ( !eventStop.wait(0) /*非用户中止*/ ) ){
chatUi.errorMessage("服务器回复调用成功,但并没有发送有效正文。请稍后点击「继续」重试(如果一直如此,请更换服务商)。")
}
}
}
// 恢复按钮状态
chatUi.onComplete(ok);
if((sendBackProtocol && err ) || eventStop.wait(0)){
//仅在交错思考回传工具调用结果失败或者用户手动点击“停止”才有必要恢复思维链(修改本工具源代码时请保留此注释)。
..thread.set("resumeChainOfThought",chatMessages);
..thread.set("resumeChainOfThoughtProtocol",sendBackProtocol);
mainForm.btnSend.text = #err ? "重试" : "继续";
}
elseif(err){
mainForm.btnSend.text = "重试";
}
},chatUi,mainForm,aiChatConfig,config.itemData,eventStop,mainForm.fromWeiXinClawBotMessage,mainForm.fromFeishuMessageId,mainForm.feishuClientInstance,resentCot,type(mainForm.btnImageAttachment.foreground)==="table"
)
// 发送后焦点切回输入框
mainForm.editPrompt.setFocus();
}
chatUi.onComplete = function(success){
mainForm.saveChatMessage();
mainForm.btnSend.checked = false;
mainForm.btnSend.disabledText = null;
mainForm.btnSend.reduce(false);
mainForm.btnSend.text = "运行";
mainForm.btnSend.iconText = '\uF1B9';
mainForm.btnClear.disabled = false;
mainForm.editPrompt.setFocus();
if(chatUi.aiChatThread){
..raw.closeHandle(chatUi.aiChatThread);
chatUi.aiChatThread = null;
}
if(mainForm.stopTimerId){
mainForm.clearTimeout(mainForm.stopTimerId);
mainForm.stopTimerId = null;
}
if(taskbar) taskbar.SetProgressState(mainForm.hwnd,0/*_TBPF_NOPROGRESS*/);
}
mainForm.saveChatMessage = function(){
config.save();
}
mainForm.onDestroy = function(){
if(mainForm.feishuClientInstance){
mainForm.feishuClientInstance.stop();
mainForm.feishuClientInstance = null;
}
feishuClient = null;
if(weixinListeningThread){
..thread.terminate(weixinListeningThread,0)
..raw.closeHandle(weixinListeningThread);
weixinListeningThread = null;
}
eventStop.set();
if(chatUi.aiChatThread){
if(!..thread.wait(chatUi.aiChatThread,200)){
..thread.terminate(chatUi.aiChatThread,0);
}
..raw.closeHandle(chatUi.aiChatThread);
chatUi.aiChatThread = null;
}
mainForm.saveChatMessage();
}
chatUi.external = {
alert = function(msg){
mainForm.msgbox(msg," 🚗 aardio autos ");
};
updateApiKey = function(){
mainForm.btnSetting.oncommand();
};
updateSearchKey = function(){
var webSearchConfig = fsys.table(io.joinpath(userDataPath,"tavily.table"));
var key = mainForm.inputBox("请输入密钥(自动识别 Tavily,Exa 等搜索接口密钥)","AA(aardio autos) - 搜索接口密钥",webSearchConfig.key,,true);
if(key){
webSearchConfig.key = key;
webSearchConfig.save();
}
};
openMemory = function(){
raw.explore(io.createDir(io.joinpath(userDataPath,"~memory/")))
};
showMessage = function(msg){
mainForm.showMessage(msg,,true)
};
importChatMessages = function(){
import fsys.dlg;
var path = fsys.dlg.open("*.jsonl|*.jsonl|*.json|*.json||","自 jsonl 或 json 文件导入对话");
if(!path) return;
chatUi.importChatMessagesFromFile(path);
};
}
mainForm.btnSend.oncommand = function(id,event){
if(mainForm.btnSend.text == "停止"){
eventStop.set();
mainForm.btnSend.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
mainForm.stopTimerId = mainForm.setTimeout(
function(){
mainForm.stopTimerId = null;
if( mainForm.btnSend.text == "停止"){
if(chatUi.aiChatThread ){
..thread.terminate(chatUi.aiChatThread,0)
..raw.closeHandle(chatUi.aiChatThread)
chatUi.aiChatThread = null;
// 恢复按钮状态
chatUi.onComplete();
if( ..thread.get("resumeChainOfThought") ){
mainForm.btnSend.text = "继续"
}
}
}
return 0;
},6000
)
return;
}
if(mainForm.btnSend.text=="继续"){
chatUi.clearErrorMessage();
sendApiMessage(true);
}
else{
mainForm.fromWeiXinClawBotMessage = null;
mainForm.fromFeishuMessageId = null;
sendApiMessage();
}
}
//回车换行(Ctrl+Enter 发送)
mainForm.editPrompt.onOk = function(ctrl,alt,shift){
if(ctrl){
mainForm.btnSend.checked = true;
mainForm.btnSend.oncommand();
return true;
}
}
var resetMessages = function(restore){
chatUi.clear();
var tip = /***
[AA( aardio autos )](http://aau.cn) - 开源,免费的全自主 AI 智能体(Autonomous Agent)
本工具拥有自主编程、调试、操作电脑的能力。 **使用本工具造成的一切后果自负,如不同意请勿使用!**
#### 🚗 起步
请 <a href="javascript:void(0)" onclick="javascript:external.updateApiKey()" title="打开 API 设置窗口(试试右键点配置名 » 智能粘贴)。请选择支持交错思考(边思考边调用工具)能力的模型。">» 设置接口</a> / [推理强度](http://www.aardio.com/zh-cn/docs/library-guide/std/web/rest/aiChat.html#reasoning) (磨蹭卡壳时调低,粗心草率时调高) [» 新手资源包](http://aau.cn/pack)
请 <a href="javascript:void(0)" onclick="javascript:external.updateSearchKey()" title="兼容并自动识别 AI 搜索厂商 Tavily/Exa/Bocha 的密钥格式。设置此密钥 AI 才能具有联网搜索的能力。">» 设置联网密钥</a> (Tavily <a href="https://app.tavily.com/home" target="_blank">注册</a> 免费 1000 次/月)
#### 🚗 技巧
- 输入框按 `Ctrl+Enter`快速发送,`Ctrl+V`粘贴文件或图像附件(点  截屏,右键清除)
- 展开「推理过程」可查看 <a title="AI 调用工具执行的代码仅临时显示在推理过程(不带入下轮对话,重启丢弃)。智能体的默认行为是执行代码而非生成代码。如果需要将代码回复到正文(默认 AI 会自动判断是否有必要这么做),请避免使用可能误导 AI 「仅执行代码」的提示词(或带有类似歧义)。如果需要保存代码到本地文件(这本就是智能体的基本能力)也请明确告知 AI。" href="javascript:void(0)">执行代码</a>,`Ctrl+单击` 或 3 连击选中代码块
- 中止任务后可点「继续」恢复思维链(可输入临时性提示词纠正 AI 思维路径)
- 点(  )按钮清除对话(减负提效),<a title="如果 AI 打开控制台(黑窗口)请不要直接关闭(不保证能保存对话)" href="javascript:void(0)" >正常关闭自动保存</a>,输入框右键 <a href="javascript:void(0)" onclick="javascript:external.importChatMessages()" title="点这里自 json,jsonl 文件导入对话">导入/导出</a> 对话
- 新建对话或重启程序可重新加载 <a href="javascript:void(0)" onclick="javascript:external.openMemory()" title="点这里打开记忆文件存储目录,main.md 为主记忆,手工操作时请注意备份">长期记忆</a>,可显式要求 AI 写入、清除、切换`主记忆`
- 可自主按需加载 / 创建技能包(高效复用) [» 技能包仓库](http://aau.cn/skills)
***/
if(!restore) {
config.chatMessages = null;
config.save();
chatUi.write(tip);
}
else{
config.chatMessages = chatUi.chatMessages;
config.save();
}
var systemPrompt = "";
var aiChatConfig = config.itemData[[config.selItem]]
if(#aiChatConfig[["systemPrompt"]]){
systemPrompt = aiChatConfig.systemPrompt + '\n\n';
}
systemPrompt = systemPrompt + "
## 角色
你是 Autos,高级 aardio 自动编程智能体。
你擅长编写、调试、测试和改进 aardio 代码,
并可使用工具运行代码、检查文件、搜索文档、自动化操作电脑。
## 要求
- 优先用最短可靠路径验证关键风险;避免无价值的重复探索、冗长解释和不必要的工具调用
- 必要时应主动调用工具验证关键假设,复杂任务可充分使用工具,关键目标应尽最大能力思考,优先探索高信息增益、能验证关键假设或降低主要风险的方法;必要时可以充分尝试不同路径,但避免无意义的重复试错,避免做无用功。
- 编程任务请调用工具执行必要的单元测试(验证关键代码、你的想法、思路的可行性)
- 微信/飞书来源的消息必须用对应工具回复
"
systemPrompt = systemPrompt + "
## 复杂任务开发流程
以下是 default workflow / playbook,不是硬性清单;可按任务复杂度跳过、合并、重排。
1. Align:明确目标、约束、上下文、验收标准(Definition of Done)。若缺失信息可以安全假设,就说明假设并继续;若会显著影响方向或风险,则先询问。
2. Plan:拆分任务,选择技术路线,识别关键风险、依赖、验证方式与必要的回滚/备份策略。
3. De-risk:优先验证最不确定、最可能阻塞的点;必要时查文档/范例/源码,或构造 minimal repro 验证关键 API、协议、环境差异。
4. Implement:做最小但完整的有效改动,保持简单、可维护、可回滚;避免无关重构和扩大任务范围。
5. Validate:运行聚焦的测试或实际验证,观察错误与输出,用结果修正方案;必要时扩大验证范围,直到达到足够置信度。
6. Deliver:简洁总结已完成内容、验证证据、剩余风险与建议下一步;若任务仍很长,可给出可恢复的 checkpoint / State Summary。
流程是迭代的:Observe » Orient » Decide » Act。请根据证据持续调整计划,尽最大努力交付高质量结果;关键任务不要吝惜必要的推理和验证,但始终避免 busywork。
### 任务边界、Checkpoint 与上下文预算
本节是 soft heuristic / meta-guidance,不是硬性限制;请按当前任务的最佳实践自主权衡。
默认保持 Autonomy:用户的显式目标是 priority anchor,而不是探索上限。为完成目标所需的隐含子任务、短闭环验证(micro-loop)可自主推进;避免 zero-value confirmation,不要机械请示。
避免跑偏:复杂任务中请留意 task boundary / scope creep / context budget。工具调用应优先服务当前目标;若新发现的问题能解除阻塞或显著降低风险,可自主处理;否则先记录为 risk / technical debt / follow-up,避免把相关问题自动升级为当前任务。
分而治之:当你自行判断方向不确定性升高、可能进入 rabbit hole、上下文或思维链明显膨胀、连续行动的边际收益下降,或即将进入高影响新阶段时,可主动结束本次对话以创建“阶段性 checkpoint”。阶段性 checkpoint 的目的不是降低探索性,而是 alignment 与 context compaction。
阶段性 checkpoint 的正文应作为可恢复的 State Summary,简短说明:已确认事项、当前判断或风险、下一步默认方案,或确实需要用户决策的问题。若下一步短小、低风险,且能验证关键假设或完成当前 micro-loop,请继续完成小闭环,不要过度频繁打断或要求用户确认。
## 提示
执行 aardio 代码时,你可以:
- 使用 `return` 语句返回你需要的值。
- 自动捕获 `print` 函数的所有输出。
- 调用 `util.testRunner` 执行自动测试,并使用 `return $.report()` 方法收集测试结果。
即使本系统没有提供相关工具,
你也可以调用 aardio 强大的标准库与 ide 扩展库。
- 获取库路径: `var path,dir = io.libpath(lib)` ,库不存在时返回 null 。创建库时应当硬编码路径 `~/lib/namespace...`(公共库)或 `/lib/namespace...`(用户库)
- aardio 范例目录: `~\examples\` ,可调用工具 `search_text(path='examples')` 搜索范例
- aardio 调用其他编程语言: `~\examples\Languages\`,例如 `\examples\Languages\R\`
- aardio 文档与指南目录: `~\docs\` ,可调用工具 `search_text(path='docs')` 搜索文档。文档中的虚拟路径`~/docs/examples/`指向物理路径 `~/examples/`
- `https://www.aardio.com/zh-cn/docs/` 协议: 文档中 `https://www.aardio.com/zh-cn/docs/` 链接的根目录为 IDE 目录 `~/docs/`,`https://www.aardio.com/zh-cn/docs/examples/` 对应 IDE 目录 `~/examples/` ,`https://www.aardio.com/zh-cn/docs/library-references/` 下面的库参考文档则由 ide.doc.libraryMd 动态生成
- 库文档分为 3 类:
1. 库参考:调用 lookup_library_reference 工具获取,由库源码内智能提示声明(必不可少)生成(基于 ide.doc.libraryMd )
2. 库指南:位于 `~\docs\library-guide` 目录,内置库与部分标准库
3. 库文档:位于 `~\docs\library` 目录,扩展库安装的文档
- 探查库源码: 工具 get_library_source
- 重新加载已修改的库: 工具 loadcodex_clean
- 自动化: 标准库 winex(控制外部窗口),key(模拟键盘),mouse(模拟鼠标) 等命名空间
- 进程操作: process 命名空间
- 文件操作: fsys 命名空间,io 内置库
- 网页自动化: web.view(WebView2 ) 提供 preloadScript 方法可注入并修改 JS 内置函数,cdp 系列方法也非常有用,也可以利用 waitEle,waitEle2 方法实现 XPath 查询、检测、等待网页元素并回调 JS 非常方便,范例 `~/examples/WebUI/web.view/XPath.aardio`
- Markdown 转 HTML: string.markdown 基于 C 组件速度极快,推荐
- HTML 转 PDF: web.view + cdp('Page.printToPDF')
- PDF: fsys.pdfium
- Word 文档(*.docx): 标准库 com.doc (基于 `com.TryGetObject('Word.Application','wps.Application')`),兼容 WPS
- PPT: `com.TryGetObject('PowerPoint.Application', 'WPP.Application')` 创建 COM 对象操作 PPT 幻灯片文件
- Excel: com.excel ,兼容 WPS
- 系统自动化: mouse, key, winex, process 库
- OCR: 标准库自带的 dotNet.ocr 或工具 analyze_image
- 读写剪贴板: win.clip 命名空间
- 操作系统版本信息: win.version
- SYSTEM_INFO 结构体: sys.info
- PowerShell: 标准库自带的 dotNet.ps 或工具 process_powershell ;仅在有必要时才使用 PowerShell ,编辑文本或代码请改用 patch_text_file, edit_text_file 等更可靠的工具。
- CMD/外部进程: 工具 process_popen;代码内可用 process.popen
- 批处理(*.bat): process.batch
- 创建美观的图形界面: 用 plus 控件, skin 方法美化。要求不高的简单图例使用 gdip.chart.bar 等基于 plus 控件的简单图表
- GDI+ 自绘: plus 控件适合 GDI+ 自绘,例如写见缝插针小游戏、简单动画可能比网页还方便,但 GDI+ 不适合大面积密集绘图或对性能要求高的动画
- 创建复杂的适合用网页展示的界面: web.view(WebView2) 加载前端是最佳实践,例如显示数据看板、统计报表用网页非常方便,与 aardio 交互也非常方便。
- ImTip 超级热键: process.imTip 库,以及超级热键指南( `~/docs/library-guide/std/key/hotkey.md` )
- 调用 .NET 框架或程序集: 标准 dotNet
- 编译运行 C# 代码: `dotNet.createCompiler('C#')` ,注意 aardio 中的 CLR 编译器最高支持 C# 4.0( .NET 4.0+)/5.0( .NET 4.5+) 语法
- 调用 WinRT 组件: dotNet.uwpCompiler,参考 `\examples\Languages\dotNet\WinRT`目录
- JScript 或 VBScript: 标准库 web.script
- 现代 JavaScript: 标准库 nodeJs 或 web.view
- 调用 Python: py3 扩展库
- 调用或编译执行 C 语言,生成 DLL: tcc 扩展库
- 调用 HTTP API: aardio 通常不需要专门的 SDK,大多时候只需要 web.rest.jsonClient 或 web.rest.jsonLiteClient,`\examples\Web\REST` 目录下提供了很多示范代码
以上只是部分提示与建议,你可以根据用户需求与最佳实践进一步调研分析、权衡取舍
## 共享浏览器
当你需要调用浏览器显示网页并希望其持久驻留(跨工具调用、跨对话线程),并且获得控制这个浏览器的能力时(例如执行 JavaScript,探查网页状态,自动化操作,跟踪或辅助用户操作),
请使用 `web.view.shared({text=""title""})` 创建共享浏览器窗 —— 这会在独立线程中创建共享 WebView2 窗口;相同 `text` 复用同一实例,不同 `text` 可创建不同实例。
shared 浏览器应通过 JavaScript 或 CDP 交互;尽量避免绑定依赖当前对话线程上下文的 aardio 回调闭包。
示例:
```aardio
import web.view;
var wb = web.view.shared(text='shared-demo');
wb.go('https://example.com');
wb.waitEle(`//h1[contains(., ""Example Domain"")]`,5000);
wb.html = /***
<button id=""btn"" onclick=""this.innerText='已点击'"">点我</button>
***/
wb.waitEle(`//button[@id=""btn"" and normalize-space(.)=""已点击""]`/*,5000*/);
return {
text = wb.eval(""document.getElementById('btn').innerText"");
}
```
"
//保持不变以利于构建缓存
chatUi.aardioSystem(systemPrompt);
//技能包
import autos.skills;
var systemPrompt = autos.skills.buildRoutePrompt();
var lunar;
try{
import time.lunar;
lunar = '\r\n- 当前农历:' + tostring(time.lunar());
}
catch(e){
lunar = ""; //兼容 XP 系统
}
//主记忆
var mainMemoryPath = io.joinpath(userDataPath,"~memory/main.md")
systemPrompt = systemPrompt + "
## 背景
- 当前日期:" + tostring(time(str,"%Y年%m月%d日","chs"))
+ '\n- 当前操作系统:"' + ..win.version.format() + '"'
+ lunar
+ '\n- aardio 开发环境所在目录:`' + io.fullpath("~/") + '`'
+ '\n- 操作系统临时目录:`' + fsys.getTempDir() + '`'
+ '\n- 你可以自由读写文件的工作区目录:`' + agentWorkspace + '`'
+ '\n- 本系统名称为: AA( aardio autos ) 版本: ' + autos.version
+ '\n- 本系统源代码位于:`' + io.fullpath("~\examples\AI\autos.aardio") + '` 如果用户有需要,你可以改进系统源代码,但需经过用户确认同意。如果用户要求你介绍自己,你可以先读取运行你的这个系统源代码作为参考。'
+ '\n- 本系统进程权限:' + (..process.admin.isRunAs() ? "以管理权限启动" : "以普通权限启动") + "。如果你需要以管理权限执行工具或代码,请提醒用户可按住 Shift 键单击 aardio 工具面板顶部的`AA`按钮以管理权限启动 Autos 。"
+ '\n\n'
+ "## 长期记忆
### 记忆文件系统
- 长期记忆根文件夹 `" + io.joinpath(userDataPath,"~memory/") + "` 是你的大脑。
- main.md 是你的主记忆,创建会话时自动加载,阶段性成果/大坑教训应使用 write_memory 写入主记忆。
- 除 main.md 以外的其他记忆文件则用于保存记忆分枝。
但应当控制写入长期记忆的频率,避免过度频繁地写入长期记忆。
几乎没有可重用价值的信息(对以后的对话和任务几乎没有帮助)不应当写入长期记忆。
写入主记忆不会影响当前上下文,只有用户清除当前会话并创建新会话时才会加载新的主记忆。
### 整理与修剪主记忆
当前主记忆文件(main.md)的体积:" + math.size64(io.getSize(mainMemoryPath)).format() + ",超过 30KB 你应当在会话结束前整理与修剪主记忆(调用工具 read_memory 读取最新的主记忆,然后调用工具 write_memory 替换主记忆文件)。
整理与修剪主记忆的原则是丢弃对任务推进没有价值的信息,归纳整理并保留有价值的知识、技能与重要记忆,暂时不需要的记忆可以存为其他分枝记忆文件(在主记忆中记录其路径与摘要)。
如果项目切换或者用户要求,可以调用工具 switch_memory 备份并切换主记忆。
### 利用长期记忆分解并逐步完成复杂任务
避免在一次对话中完成复杂的任务的所有步骤。
你应当做好规划,分而冶之,把复杂的任务目标拆分为可以逐个完成的简单小目标。
在长期记忆中记录复杂任务的规划、步骤,以及需要逐个攻克的难点。
每次完成一个小目标或里程碑并结束对话时你应当将重要的信息、研究成果、任务进度、下一步建议执行的任务写入长期记忆。
即使用户清除对话上下文,你仍然可以使用长期记忆继续推进项目,不会遗忘重要的信息。
### 刷新主记忆
在用户创建新对话(清除原对话)或重启 Autos (保留原对话)时都会自动读取新的主记忆(注入系统提示词)。
在用户清除上下文并新建对话之前,继续原对话不会重新读取新的主记忆(这是为了重用大模型 API 的前缀缓存)。
因此增量写入主记忆的重要信息你也要输出到回复正文(除非在上下文中已存在)。
";
var memPath = io.joinpath(userDataPath,"~memory/main.md")
if(..io.exist(memPath)){
var main = string.load(memPath)
if(main) systemPrompt = systemPrompt + '\n\n\n---\n\n\n以下是你之前记录的长期记忆和关键信息(主记忆 main.md)。\n\n'+main;
}
chatUi.system(systemPrompt);
//assert(#chatUi.chatMessages===2);//超长而自动清理时最多保留头部 2 个系统提示词
mainForm.btnImageAttachment.foreground = null;
mainForm.btnImageAttachment.iconText = '\uF030';
mainForm.btnSend.text = "运行";
}
mainForm.btnSetting.oncommand = function(id,event){
table.assign(config,{
title = "AA( aardio autos ) - 设置"; // 标题
hyperlink1Title = "获取 key"; // key 输入框显示嵌入链接
f1Title = "允许使用此接口的视觉能力";
f1MultiSelect = true;
allowKatex = true;//Win10+
});
//打开 AI 设置窗口,参数 2 指定配置文件
var frmSetting = web.rest.aiChat.settingForm(mainForm,config);
//用户点击了「保存」
if( frmSetting.doModal(mainForm) ){
//获取用户当前选择的配置
var configItem = config.itemData[config.selItem];
if(configItem){
if( configItem.model && string.find( configItem.model,"!\wgpt!\W") ){
//OpenAI 透传缓存
if(configItem.key && type(configItem.extraParameters)!="table"){
import crypt;
configItem.extraParameters = {
//隔离缓存 key,避免缓存溢出
prompt_cache_key = crypt.sha256( configItem.key + ".aardio.autos" + io._exepath);
}
config.save()
}
}
aiChatConfig = table.assign({},configItem);
if(!chatUi.started()){
resetMessages();
}
}
}
}
mainForm.btnClear.oncommand = function(id,event){
mainForm.btnSend.disabled = true;
if(chatUi.aiChatThread){
..thread.terminate(chatUi.aiChatThread,0)
..raw.closeHandle(chatUi.aiChatThread)
chatUi.aiChatThread = null;
}
io.close();
resetMessages();//清除聊天上下文
mainForm.showMessage("✅ 已重新读取并刷新主记忆 ……");
mainForm.editPrompt.setFocus();
mainForm.btnSend.disabled = false;
}
mainForm.btnCopy.oncommand = function(id,event){
var md;
if(::GetKeyState(0x10/*_VK_SHIFT*/) & 0x8000){
md = chatUi.getMarkdown();
}
else{
md = chatUi.lastAssistantMessage(true)
}
if(!#md) return mainForm.msgboxErr("未复制任何内容,AI 回复内容为空!");
win.clip.write( string.crlf(md,'\r\n') );
mainForm.btnCopy.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text=''}
thread.delay(800);
mainForm.btnCopy.disabledText = null;
mainForm.editPrompt.setFocus();
}
mainForm.weixinSendMessage = function(fromMsg,requestText,attachmentNotice){
if(mainForm.btnSend.busy()){
return "抱歉我正在思考,请稍后联系我。";
}
else{
mainForm.fromWeiXinClawBotMessage = fromMsg;
if(attachmentNotice){
chatUi.prompt(attachmentNotice,,true);
config.chatMessages = chatUi.chatMessages;
mainForm.saveChatMessage();
}
if(requestText){
sendApiMessage(false,requestText);
}
}
}
// 飞书消息处理函数
mainForm.feishuSendMessage = function(messageId, requestText,attachmentNotice){
if( mainForm.fromFeishuMessageId == messageId ){
return mainForm.btnSend.busy()?"我正在思考 ……":null;
}
if(mainForm.btnSend.checked){
return "抱歉我正在思考,请稍后联系我。";
}
else{
mainForm.fromFeishuMessageId = messageId;
if(attachmentNotice){
chatUi.prompt(attachmentNotice,,true);
config.chatMessages = chatUi.chatMessages;
mainForm.saveChatMessage();
}
if(requestText){
sendApiMessage(false,requestText);
}
}
}
import win.debounce;
var hideMessage = win.debounce(
function(){
mainForm.lableMessage.show(false);
},3000);
mainForm.lableMessage.orphanWindow(true);
mainForm.showMessage = function(content,msgType,popup){
if(!content){
mainForm.lableMessage.show(false);
return ;
}
if(mainForm.btnSend.busy() || popup){
content = string.replace(content,'\r?\n'," ");
if(msgType=="error") mainForm.lableMessage.foreground = 0xFFD13438;
elseif(msgType=="loading") mainForm.lableMessage.foreground = 0xFF107C41;
else/*if(msgType=="success")*/ mainForm.lableMessage.foreground = 0xDD107C41;
mainForm.lableMessage.text = content;
mainForm.lableMessage.show();
hideMessage();
}
else{
var overwrite = !chatUi.started();
if(msgType=="error") chatUi.errorMessage(content,overwrite);
elseif(msgType=="loading") chatUi.showLoading(content,overwrite);
else/*if(msgType=="success")*/ chatUi.successMessage(content,overwrite);
}
}
mainForm.editPrompt.oleCallback(
GetDragDropEffect = function(drag,grfKeyState,effect){
return 0,1/*_DROPEFFECT_COPY*/
}
QueryAcceptData = function(ptrDataObj,format,reco,really,hMetaPict){
if(really){
var dataObj = com.interface.IDataObject(ptrDataObj);
if(dataObj.isText()){
var txt = dataObj.getText();
if(txt){
var b,e = mainForm.editPrompt.getSel();
if(!e) mainForm.editPrompt.setSel(-1);
mainForm.editPrompt.selText = txt;
}
}
elseif( dataObj.isFile()){
var files = dataObj.getDropFile();
if(#files){
mainForm.editPrompt.setSel(-1);
mainForm.editPrompt.selText = " `" + string.join(files,",")+"` ";
}
}
elseif( dataObj.isBitmap()){
var bmp = dataObj.getBitmap();
if(bmp){
var oldBmp = mainForm.btnImageAttachment.setForeground(bmp);
if(oldBmp) oldBmp.delete();
mainForm.btnImageAttachment.iconText = null;
}
}
/*返回 0 继续默认处理,文本放入控件,返回 _S_FALSE 阻止默认处理。*/
return 1/*_S_FALSE*/
}
return 0;
}
)
var weixinListeningThread;
var weixinTokenPath;
mainForm.btnWeixin.oncommand = function(id,event){
import web.rest.iLinkClient.login;
if(!mainForm.btnWeixin.checked){
if(weixinListeningThread){
thread.terminate(weixinListeningThread,0)
raw.closeHandle(weixinListeningThread);
weixinListeningThread = null;
}
if(weixinTokenPath){
io.remove(weixinTokenPath)
weixinTokenPath = null;
}
mainForm.showMessage("✅ 微信机器人已断开连接,再次点击微信图标重新扫码连接。");
return;
}
var bot,err = web.rest.iLinkClient.login(parent=mainForm;text="使用微信连接 aardio autos");
if(bot) mainForm.showMessage('✅ 微信机器人已上线,可接收 / 发送文本、图片、文件 ... 再次点击微信图标断开连接。');
else {
if(#err ) mainForm.msgboxErr( err );
mainForm.btnWeixin.checked = false;
return;
}
weixinTokenPath = bot.config.tokenPath;
weixinListeningThread = thread.create(
function(mainForm,chatUi){
import autos.weixinClient;
autos.weixinClient(mainForm,chatUi);
},mainForm,chatUi
)
}
// 飞书配置和连接
var feishuClient;
var feishuConfig = fsys.table(io.joinpath(userDataPath,"feishu.table"));
var frmFeishu;
mainForm.feishuOnReady = function(){
feishuClient = mainForm.feishuClientInstance;
mainForm.btnFeishu.checked = true;
if(frmFeishu && frmFeishu.valid){
frmFeishu.setStatus("已连接", 0x00AA00);
frmFeishu.close();
}
mainForm.btnFeishu.checked = true;
mainForm.showMessage('✅ 飞书机器人已上线,可接收 / 发送文本、图片、文件。\n\n再次点击飞书图标断开连接。');
}
mainForm.feishuOnError = function(err){
if(!mainForm.btnFeishu.checked && (frmFeishu && frmFeishu.valid)){
frmFeishu.setStatus("连接失败:" + (err || "未知错误"), 0xFF0000);
frmFeishu.btnConnect.disabled = false;
}
}
mainForm.feishuOnClose = function(reason){
feishuClient = null;
mainForm.feishuClientInstance = null;
mainForm.btnFeishu.checked = false;
}
mainForm.btnFeishu.oncommand = function(id,event){
import web.feishu.settingForm;
// 如果已连接,断开连接
if(!mainForm.btnFeishu.checked && feishuClient){
feishuConfig.autoConnect = false;
feishuConfig.save();
feishuClient.stop();
feishuClient = null;
mainForm.feishuClientInstance = null;
mainForm.btnFeishu.checked = false;
mainForm.showMessage("✅ 飞书机器人已断开连接,再次点击重新连接。","success");
return;
}
mainForm.btnFeishu.checked = false;
// 打开配置窗口
frmFeishu = web.feishu.settingForm(mainForm, feishuConfig);
// 连接回调
frmFeishu.onConnect = function(appId, appSecret){
frmFeishu.setStatus("正在连接...", 0x0078D4);
frmFeishu.btnConnect.disabled = true;
thread.invoke(
function(mainForm, chatUi, appId, appSecret){
import win.ui;
import autos.feishuClient;
mainForm.showMessage("✅ 飞书机器人正在连接","loading");
var client = autos.feishuClient(mainForm, chatUi, appId, appSecret);
mainForm.feishuClientInstance = client;
client.start();
win.loopMessage();
}, mainForm, chatUi, appId, appSecret
);
}
frmFeishu.doModal();
}
if(feishuConfig.autoConnect && feishuConfig.appId && feishuConfig.appSecret ){
mainForm.btnFeishu.checked = true;
thread.invoke(
function(mainForm, chatUi, appId, appSecret){
import win.ui;
import autos.feishuClient;
mainForm.showMessage("✅ 飞书机器人正在连接","loading");
var client = autos.feishuClient(mainForm, chatUi, appId, appSecret);
mainForm.feishuClientInstance = client;
client.start();
win.loopMessage();
}, mainForm, chatUi, feishuConfig.appId, feishuConfig.appSecret
);
}
chatUi.importChatMessagesFromFile = function(path){
var json = string.load(path);
if(!#json){
return mainForm.msgboxErr("无效对话数据")
}
var messages;
if(..string.endsWith(path,".jsonl",true)){
messages = JSON.ndParse(json);
}
else {
messages = JSON.parse(json);
}
if(!#messages){
return mainForm.msgboxErr("无效对话数据")
}
chatUi.importChatMessages(messages)
}
chatUi.importChatMessages = function(messages){
mainForm.btnClear.disabled = true;
mainForm.btnSend.disabled = true;
mainForm.btnSetting.disabled = true;
mainForm.showMessage("✅ 正在刷新主记忆 + 恢复会话 ……");
resetMessages(true);
var last = messages[#messages];
if((last[["role"]]=="assistant") && (!#last.content)){
table.pop(messages);
}
for(i=1;#messages;1){
var msg = messages[i];
if(type(msg.content)!="string"){
if(msg[["role"]]!="user"){
//resetMessages();
break;
}
elseif(!..table.isArrayLike(msg.content)){
//resetMessages();
continue;
}
}
if(msg[["role"]]=="system"){
if(i<= #chatUi.chatMessages){
continue;
}
chatUi.system(msg.content)
}
elseif(msg[["role"]]=="user"){
if(i<#messages){
chatUi.promptOnce(msg.content)
}
else{
mainForm.editPrompt.text = msg.content;
}
}
elseif(msg[["role"]]=="assistant"){
var content = msg.content;
if(#content) chatUi.assistantOnce(content);
}
else {
resetMessages();
break;
}
}
config.save();
mainForm.showMessage(false);
mainForm.btnClear.disabled = false;
mainForm.btnSend.disabled = false;
mainForm.btnSetting.disabled = false;
}
mainForm.editPrompt.enablePopMenu(lambda(){
{ /*分隔线*/ };
{ '导入对话'; function(id){
import fsys.dlg;
var path = fsys.dlg.open("*.jsonl|*.jsonl|*.json|*.json||","自 jsonl 或 json 文件导入对话");
if(!path) return;
chatUi.importChatMessagesFromFile(path);
}; mainForm.btnSend.busy() ? 1/*_MF_GRAYED*/ : 0};
{ "导出对话"; function(id){
import fsys.dlg;
var path = fsys.dlg.save("*.jsonl|*.jsonl|*.json|*.json||","导出对话到 *.jsonl");
if(!path) return;
var file,err = io.file(path,"w+b");
if(!file) return mainForm.msgboxErr(err);
var chatMessages = chatUi.chatMessages;
if(..string.endWith(path,".jsonl",true)){
for(i=1;#chatMessages;1){
var msg = chatMessages[i]
var line = JSON.stringify(msg,false,false);
line = string.crlf(line,"")
file.write(line,'\r\n');
}
}
else {
file.write((JSON.stringifyArray(chatMessages,true,false)));
}
file.close();
}; #chatUi.chatMessages<3 ? 1/*_MF_GRAYED*/ : 0};
});
mainForm.btnSend.disabled = true;
if(config.chatMessages){
chatUi.importChatMessages(config.chatMessages);
}
else{
resetMessages();
mainForm.editPrompt.text = defaultPrompt
}
mainForm.btnSend.disabled = false;
mainForm.createHbitmapFromAttachment = function(){
var bmp = mainForm.btnImageAttachment.foreground;
if(type(bmp)==="table") return bmp.copyHandle();
}
mainForm.btnImageAttachment.onRightMouseUp = function(wParam,lParam){
mainForm.btnImageAttachment.foreground = null;
mainForm.btnImageAttachment.iconText = '\uF030';
}
mainForm.btnImageAttachment.oncommand = function(id,event){
mainForm.show(0);
import gdip.snap;
import mouse.screenArea;
var screenArea = mouse.screenArea();
screenArea.onSelectionChanged = function(rc){
mainForm.btnImageAttachment.iconText = null;
var oldBmp = mainForm.btnImageAttachment.setForeground( (gdip.snap(screenArea.hwnd,rc)) );
if(oldBmp) oldBmp.delete();
owner.endModal(true);
mainForm.editPrompt.setFocus();
}
screenArea.doModal();
mainForm.show(5/*_SW_SHOW*/);
}
win.loopMessage();
Markdown 格式