//F1 快捷键触发器 import ide; import inet.url; import fsys; import key; var hwnd = ...; if(!hwnd) return; import win.ui.ctrl.edit; var codeEdit = win.ui.ctrl.edit(); codeEdit.hwnd = hwnd; var selText = codeEdit.selText; if(#selText) selText = string.trim(selText); if(#selText){ var op = string.match(selText,"^\s*(<\p+>|<@/*DSG{{*/@>||<%\[\]>)\s*$"); if(op){ var url = "doc://guide/language/special-characters.html" if(op==">>" || op=="<<" || op==">>>"){ url = "doc://language-reference/operator/bitwise.html" } elseif(op == "===" || op == "!==" || op == "==" || op == "!="){ url = "doc://language-reference/operator/equality.html" } elseif(op == "+" || op == "/" || op == "**"){ url = "doc://language-reference/operator/arithmetic.html" } elseif(op=="%"){ url="doc://language-reference/operator/arithmetic.html#mod" } elseif(op == ">" || op == "<" || op == ">=" || op == "<="){ url = "doc://language-reference/operator/comparison.html" } elseif(op == "!"){ url = "doc://language-reference/operator/logical.html#not" } elseif(op == "\"){ url = "doc://language-reference/datatype/string.html#escaped" } elseif(op == "||" || op == ":"){ url = "doc://language-reference/operator/logical.html#or" } elseif(op == "&&" || op == "?"){ url = "doc://language-reference/operator/logical.html#and" } elseif(op == "?=" || op == ":="){ url = "doc://language-reference/operator/logical.html#conditional-assignment" } elseif(op == "#"){ url = "doc://language-reference/operator/len.html" } elseif(op[1] == '['# || op[1] == ']'#){ url = "doc://language-reference/operator/member-access.html" } elseif(string.match(op,"^/\*+$")) { op = "/*"; url="doc://language-reference/basic-syntax.html" } elseif(string.match(op,"^\*+/$")) { op = "*/"; url="doc://language-reference/basic-syntax.html" } elseif(op=="//"){ url="doc://language-reference/basic-syntax.html" } elseif(op=="?=" || op=="?!"){ url="doc://library-guide/builtin/string/patterns.html#lookahead" } elseif(op=="::"){ url="doc://language-reference/variables-and-constants.html#reserved-constant" } if(!string.indexOf(url,"#")){ url = inet.url.appendExtraInfo(url,{q=op}); } ide.openDocument(url); return; } if(string.find(selText,"^\\\w$")){ ide.openDocument("doc://library-guide/builtin/string/patterns.html"+"#classes"); return; } selText = string.trim(selText,"."); var libPath = string.match(selText,"^!\w(\w[\.\w]+)\.[^\.\s]+!\W$"); var builtin = {table=1;string=1;raw=1;io=1;com=1;math=1;time=1;thread=1;fiber=1;global=1;ide=1}; if(!libPath && ..string.match(selText,"^[_\a]\w*$") && global[selText]) { libPath = "global" } elseif(libPath=="io.file"){ libPath = "io"; } var filePath = io.libpath(selText) || (#libPath && io.libpath(libPath) ); if(selText == "win.form" || selText == "winform" || selText == "mainForm" || libPath == "winform" || libPath == "mainForm"){ filePath = ..io.libpath("win.ui"); } var url; var mapUrl = { "var":"doc://language-reference/variables-and-constants.html#var", "null":"doc://language-reference/datatype/datatype.html", "and":"doc://language-reference/operator/logical.html#and", "not":"doc://language-reference/operator/logical.html#not", "or":"doc://language-reference/operator/logical.html#or", "false":"doc://language-reference/datatype/datatype.html", "true":"doc://language-reference/datatype/datatype.html", "if":"doc://language-reference/statements/branching.html", "else":"doc://language-reference/statements/branching.html", "elseif":"doc://language-reference/statements/branching.html", "select":"doc://language-reference/statements/branching.html", "case":"doc://language-reference/statements/branching.html", "for":"doc://language-reference/statements/looping.html", "in":"doc://language-reference/statements/looping.html", "while":"doc://language-reference/statements/looping.html", "do":"doc://language-reference/statements/looping.html", "break":"doc://language-reference/statements/looping.html", "continue":"doc://language-reference/statements/looping.html", "try":"doc://language-reference/statements/try.html", "catch":"doc://language-reference/statements/try.html", "class":"doc://language-reference/class/class.html", "ctor":"doc://language-reference/class/class.html", "function":"doc://language-reference/function/definitions.html", "lambda":"doc://language-reference/function/lambda.html", "λ":"doc://language-reference/function/lambda.html", "return":"doc://language-reference/function/result.html", "namespace":"doc://language-reference/namespace.html", "import":"doc://library-guide/import.html", "with":"doc://language-reference/namespace.html", "this":"doc://language-reference/class/class.html", "owner":"doc://language-reference/function/owner.html", "global":"doc://language-reference/namespace.html", "self":"doc://language-reference/namespace.html", "fs":"doc://library-reference/fsys/_.html", "import global":"doc://library-guide/import.html#import-global", "switch":"doc://language-reference/builtin-function/switch.html", "call":"doc://language-reference/builtin-function/call.html", "eval":"doc://language-reference/builtin-function/eval.html", "loadcode":"doc://language-reference/builtin-function/loadcode.html", "loadcodex":"doc://language-reference/builtin-function/loadcodex.html", "assert":"doc://language-reference/builtin-function/assert.html", "reduce":"doc://language-reference/builtin-function/reduce.html", "print":"doc://language-reference/builtin-function/print.html", "string.reduce":"doc://library-guide/builtin/string/matching.html#reduce", "string.reduceReplace":"doc://library-guide/builtin/string/matching.html#reduceReplace", "string.replaceUnmatched":"doc://library-guide/builtin/string/matching.html#replaceUnmatched", "preg":"doc://library-guide/ext/preg/_.html", "libxl":"doc://library-reference/dotNet/libxl/_.html", "table.isArrayLike":"doc://language-reference/datatype/table/_.html#array-like", "isArrayLike":"doc://language-reference/datatype/table/_.html#array-like", "json":"doc://library-guide/std/JSON/_.html", "JSON":"doc://library-guide/std/JSON/_.html", "request":"doc://library-reference/fastcgi/client/_.html?q=fastcgi.client#request", "response":"doc://library-reference/fastcgi/client/_.html?q=fastcgi.client#response", "session":"doc://library-reference/fastcgi/client/_.html?q=fastcgi.client#session", "curl":"doc://library-guide/ext/curl/_.html", } if( mapUrl[selText] ){ url = mapUrl[selText] ; } elseif(selText=="lambda" || selText = "λ"){ url = "doc://language-reference/function/lambda.html"; } elseif(selText=="lambda" || selText = "λ"){ url = "doc://language-reference/function/lambda.html"; } elseif(filePath){ var filePath = fsys.path.relative(filePath,"~/lib/"); filePath = fsys.path.replaceExt(filePath,".html"); filePath = io.joinpath("library-reference",filePath); filePath = string.replace(filePath,"\\","/"); url = "doc://"+filePath; } elseif(builtin[selText]){ url = "doc://library-reference/"+selText+"/_.html" } elseif( #libPath && builtin[libPath] ){ url = "doc://library-reference/"+libPath+"/_.html" } if(url){ if(!string.indexOf(url,"#")){ url = ..inet.url.appendExtraInfo(url,{q=selText}); } ide.openDocument(url); return; } /*************** var url = inet.url.appendExtraInfo("http://api.aardio.com/search",{ q = '```aardio \n' + selText + '\n```'; }) raw.execute( url,"","open",5/*_SW_SHOW*/,..io.fullpath("~/") ,ide.getMainHwnd() //如果不指定句柄,浏览器不会前置 ) return; ***************/ } global.onError = function( err,over ){ if(!over){ import debug; var stack = debug.traceback(,"调用栈",3); } codeEdit.selText = '\n' + err + '\n' } import ide; import web.rest.aiChat; import key; import fsys.table; var config = fsys.table(io.appData("aardio/ide/aiChat/~")); for(i,cfg in config.itemData){ if(cfg.f1){ config = cfg; break; } } //创建 AI 会话消息队列 var msg = web.rest.aiChat.message(); //自动生成 aardio 编程助手系统提示词 msg.aardioSystem(); var leftText = codeEdit.leftText(); if(!#leftText) { leftText = ""; //return; } else{ leftText = ..string.replace(leftText,"![\w\._$]|\.add\(\)\s+",""); } if(#config.systemPrompt){ msg.system(config.systemPrompt); } import ide; import win.version; var ideEnv = '## 当前运行环境\r\n- 当前 aardio 主版本号为:' + (ide.getConfig("version") || (_AARDIO_VERSION)); ideEnv = ideEnv ++ '\r\n- 当前时间为:' + tostring(..time()); ideEnv = ideEnv ++ '\r\n- 当前进程 EXE 执行文件名为:"' + ..io._exefile + '"'; ideEnv = ideEnv ++ '\r\n- 当前操作系统为:"' + ..win.version.format() ++ '"'; var projPath = ide.getProjectPath(); if(#projPath) { import fsys.file; var file = fsys.file(projPath,"r"); if(file) begin if(file.size() < 20000) begin var xml = file.readAll(); var project = '\r\n\r\n'+" ## aardio 源文件与工程文件 aardio 代码文件的后置名为 `.aardio`,可包含 UTF-8 编码的源代码,也可以包含编译后的二进制代码。 aardio 工程文件的后置名为 `.aproj`,其内容是 XML 格式的工程配置,也使用 UTF-8 编码 。 " project = project + '\r\n\r\n**用户当前在 aardio 开发环境中打开的工程文件路径是:** "'+projPath+'"\r\n' project = project + '\r\n\r\n用户当前打开的工程文件内容如下:' project = project + '\r\n\r\n```xml\r\n' + ..string.removeBom(xml) + '\r\n```\r\n\r\n' var desc = /***** **工程文件各 XML 节点的作用与含义:** - project 元素指定工程配置,并作为工程根目录包含其他 folder 或 file 元素。 project 元素的属性 ui 指定图形界面。 * 如果 ui 为 "win" 则为图形界面发布后运行默认不显示控制台。 * 如果 ui 为"console" 则为控制台程序发布后运行时默认显示控制台窗口。 project 元素的属性 dstrip 指定是否移除调试符号。 * `dstrip="true"` 则发布后移除调试信息,生成的文件更小但错误信息会缺少调试信息(例如文件名行号)。 - folder 元素为工程中的虚拟目录 如果 folder 的属性 embed 为 "true" 则该目录发布后嵌入 EXE 资源文件,aardio 中很多函数和库都自动支持这种嵌入资源而不需要额外修改代码。例如对于 `string.load("/res/test.txt")`,无论参数指定的文件是不是 EXE 资源文件函数的返回值都是一样的,这是 aardio 的一个主要特性。 如果 folder 元素的属性 local 为 "true" 则表示这是一个本地目录(通常也是 Web 前端工程的发布目录),发布为 EXE 时将添加该目录下的所有文件。这种目录在工程中不显示子级文件或目录,右键菜单的『同步本地目录』也是无效的。 如果 folder 元素的属性 ignored 为 "true" 是指这个目录在发布时被忽略(ignored)。这种目录通常用来指向包含 Web 前端工程源码的目录,工程本身其实并不需要这些多余的目录,生成 EXE 时也会忽略这种目录。 - file 元素则表示添加到工程中的文件 在工程根目录下只能有一个应用程序启动文件, 文件路径必须是 `main.aardio` 或以 `.main.aardio` 结束。除了启动文件,工程根目录只能包含 folder 元素。 *****/ project = ideEnv ++ project + desc + '\r\n\r\n'; var codePath = ide.getActiveDocPath(); if(#codePath && ..string.endsWith(codePath,".aardio",true) ){ project = project + '\r\n\r\n用户当前正在编辑的文件为: "'+codePath+'"\r\n' } msg.system(project); end; file.close() end; } else{ msg.system(ideEnv); } if(#selText){ var b,e = codeEdit.getSel(); if( !(b&&e) ) return; var leftText = codeEdit.leftText(b-1); var rightText = codeEdit.rightText(); //下面不需要添加 aardio 提示词,因为 AI 会话助手已经添加了。 var sysPrompt = " ## 任务 用户当前 """"""选中代码"""""" 在 """"""前置代码"""""" 与 """"""后置代码"""""" 中间。 你需要根据上下文(指 """"""前置代码"""""" 与 """"""后置代码"""""") 解答用户关于""""""选中代码"""""" 的疑问,帮助用户实现其需求。 你的主要目标是解答关于 """"""选中代码"""""" 的问题,在回复中不必再包含 """"""前置代码"""""" 与 """"""后置代码"""""" 这此已知且重复的内容。 ## 前置代码 ```aardio "+(leftText:"")+" ``` ## 选中代码 ```aardio "+selText+" ``` ## 后置代码 ```aardio "+(rightText:"")+" ``` " ide.createProcess("~/example/AI/aardioAgent.aardio",{ _ASK_AI_SYSTEMP_PROMPT = sysPrompt; _ASK_AI_USER_PROMPT = "帮我看看 """"""选中代码"""""" "; }) return; } elseif(!#selText){ if(io.exist("~\extensions\trigger\config\debug.bin")){ var debugInfo = eval(string.load("~\extensions\trigger\config\debug.bin")) io.remove("~\extensions\trigger\config\debug.bin") var errTime = ..time.iso8601(debugInfo[["Time"]]); var now = ..time.iso8601(); if(debugInfo && now.diffsecond( errTime ) < 30){ import JSON; var json = JSON.stringify(debugInfo,true,false); json = ..string.replace(json,"@\u0027","'"); var sysPrompt = (project||"") +'\n\n'+ " ## 任务 用户当前在 aardio 开发环境中按 F5 运行 aardio 代码以后报错。 请检查并解释错误原因,提供修改指导与解决问题的方案。 ## 用户正在编辑与调试的代码 ```aardio "+(codeEdit.text:"")+" ``` ## 当前正在编辑与调试的代码文件路径 "+( ide.getActiveDocPath()||"未保存的文件")+" ``` " ide.createProcess("~/example/AI/aardioAgent.aardio",{ _ASK_AI_SYSTEMP_PROMPT = sysPrompt; _ASK_AI_USER_PROMPT = "```json "+json+" ``` 帮我看看上面的 """"""报错信息"""""" " }) return; } } } msg.prompt(" ## 任务 分析上下文(""""""前置代码""""""与""""""后置代码"""""")插入新的代码(续写与补全)。 ## 要求 - 回复的全部内容必须是适合放在前置代码与后置代码中间位置的代码。 - 回复不要再包含""""""前置代码""""""或""""""后置代码"""""" 。 - 不要在回复的 aardio 代码首尾增加类似 “以下是适合插入的代码 …… 上面的代码如何如何,如果你还有其他需要又如何如何” 这样多余的补充说明。 - 请直接回复代码,不要用 Markdown 代码块标记包围代码。 - Please provide the code directly without adding fenced code block markers. ## 前置代码 ```aardio import console; //在控制台输出一句话 console.log(""Hello ``` ## 后置代码 ```aardio console.pause(); ``` ") //利用小样本学习,以 AI 助手的角色教它一遍,胜过写千万句提示词 msg.assistant(`,world!");`); //下面是真正的问题。 msg.prompt(" ## 任务 分析上下文(""""""前置代码""""""与""""""后置代码"""""")插入新的代码(续写与补全)。 ## 要求 - 回复的全部内容必须是适合放在前置代码与后置代码中间位置的代码。 - 回复不要再包含""""""前置代码""""""或""""""后置代码"""""" 。 - 不要在回复的 aardio 代码首尾增加类似 “以下是适合插入的代码 …… 上面的代码如何如何,如果你还有其他需要又如何如何” 这样多余的补充说明。 - 请直接回复代码,不要用 Markdown 代码块标记包围代码。 - Please provide the code directly without adding fenced code block markers. ## 前置代码 ```aardio "+leftText+" ``` ## 后置代码 ```aardio "+(codeEdit.rightText():"")+" ``` ") var firstKeyEnter; if(string.find(leftText,"|<# >||<#:>\N*[ \t]*$")){ ..key.send('\n') firstKeyEnter = true; } else { if(string.find(leftText,`[^=,]\s*\{\s*$`) ){//语句块开始标记 ..key.send('\n') firstKeyEnter = true; } if(string.find(leftText,`!\N[ \t]*?[\w_.]*[ \t]*%()[ \t]*;?[ \t]*$`) ){//完成的函数调用。 ..key.send('\n') firstKeyEnter = true; } elseif(string.find(leftText,`[^\r\n\t ]+/\*![^*][^\r\n]+?![*]\*/;?[ \t]*$`) ){ //行内段注释 } elseif(string.find(leftText,`(/(\*+)![^*].+?![*]\2/);?[ \t]*$`) ){ ..key.send('\n') firstKeyEnter = true; } } var lastIndent = ..string.match(codeEdit.lineText()||leftText,"!\N([ \t]+)\N+$") var cfgNew = { key = config.key; url = config.url; model = config.model; temperature = config.temperature; userAgent = config.userAgent; proxy = config.proxy; proxyBypass = config.proxyBypass; httpFlags = config.httpFlags; } for(k,v in cfgNew){ if(v=="")cfgNew[k] = null; } if(!#cfgNew.key){ cfgNew = table.assign(cfgNew,{ url = "https://ai.aardio.com/api/v1/"; model = "aardio"; temperature = 0.1; key = "free"; }); } cfgNew.userAgent = "Mozilla/5.0 (Windows NT "+ _WIN_VER_MAJOR +"."+_WIN_VER_MINOR+"; aardio; rv:"+_AARDIO_VERSION+") like Gecko"; var ai = web.rest.aiChat(cfgNew); ai.referer = "https://aardio.com"; ai.setHeaders({ "X-Title":"aardio"}); import winex.loading; var loading = winex.loading("正在思考",codeEdit); var origCode = codeEdit.text; var origCaretPos = codeEdit.caretPos; var codeBlockTag; var responseText = ""; firstLine = true; var ok,err = ai.messages(msg,function(delta,reasoning){ if(reasoning){ return loading.thinking(reasoning);; } if( loading.isCanceled() ) { codeEdit.selectAll(); codeEdit.selText = origCode; codeEdit.setFocus(origCaretPos); return false; } //移除多余的代码块标记 if(responseText && delta){ responseText = responseText ++ delta; if( (responseText == '```aardio\n') || (responseText == '```aardio\r\n')){ responseText = null; codeBlockTag = true; return; } else if(..string.startsWith('```aardio\n',responseText) ){ return; } else if(..string.startsWith('```aardio\r\n',responseText) ){ return; } elseif(..string.startsWith(responseText,'```aardio\n',)){ delta = ..string.right(responseText,-( (#'```aardio\n') + 1)); responseText = null; codeBlockTag = true; responseText = null; } elseif(..string.startsWith(responseText,'```aardio\r\n',)){ delta = ..string.right(responseText,-( (#'```aardio\r\n')+ 1)); responseText = null; codeBlockTag = true; responseText = null; } elseif(..string.startsWith(responseText,'\n\n')){ delta = ..string.right(responseText,-3); responseText = null; } else { delta = responseText responseText = null; } } if(delta){ if(#lastIndent){ if(firstLine){ if(..string.match(delta,"^[ \t]")){ if(firstKeyEnter){ delta = ..string.trimleft(delta); if(#delta)lastIndent = null; } else { lastIndent = null; } } if(#delta){ firstLine = null; } } elseif(#lastIndent){ delta = ..string.replace(delta,"\n",'\n'+lastIndent); } } codeEdit.selText = delta; } if(delta===null){ //移除多余的代码块标记 if(codeBlockTag){ var caretPos = codeEdit.caretPos; codeEdit.setSel(caretPos-4,caretPos); if(codeEdit.selText = '\n```\n'){ codeEdit.selText = ""; } else{ codeEdit.setSel(caretPos-3,caretPos); if(codeEdit.selText = '```\n' || codeEdit.selText = '\n```'){ codeEdit.selText = ""; } else { codeEdit.setSel(caretPos-2,caretPos); if(codeEdit.selText = '```'){ codeEdit.selText = ""; } else { codeEdit.setSel(caretPos); } } } } } } ); if(err){ //获取错误对象(解析 JSON 格式的错误信息) var errObject = ai.lastResponseError() if(errObject){ if(errObject[["error"]][["type"]] == "authentication_error" ){ codeEdit.selText = `请打开『aardio 工具 / 问 AI』配置有效的密钥,获取密钥: https://aardio.com/vip/` } else { codeEdit.selText = JSON.stringify(errObject,true,false); } } else { codeEdit.selText = err; } }