min-agent 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/package.json +1 -1
- package/skills/self-config/reference.md +4 -4
package/dist/cli.js
CHANGED
|
@@ -397,7 +397,7 @@ Resume with: min-agent exec --resume ${M}`);return f}finally{await W4()}}functio
|
|
|
397
397
|
${h2.dim}\uD83D\uDCAD 思考${h2.reset}
|
|
398
398
|
`);process.stderr.write(`${h2.dim}${$}${h2.reset}`)}emitDisplay($){try{if(this.cbs.onAssistantDisplayDelta){this.cbs.onAssistantDisplayDelta($);return}let Z=this.md.write($);if(Z)process.stdout.write(Z)}catch(Z){Q0("error",`display callback failed: ${Z instanceof Error?Z.message:String(Z)}`)}}feedReasoning($){this.emitThinking($)}mirror($){if(!$)return;this.rawText+=$,this.emitDisplay($)}pipeXml($,Z){let J=$?this.xmlSplit.feed($):[];if(Z)J.push(...this.xmlSplit.flush());let z=[];for(let G of J)if(G.type==="display"){if(!G.text)continue;this.mirror(G.text),z.push(G)}else z.push(G);return z}feedText($){let{display:Z,thinking:J}=this.thinkingSplit.feed($);return this.emitThinking(J),this.pipeXml(Z,!1)}flushSplitText(){let $=this.thinkingSplit.flush();return this.emitThinking($.thinking),this.pipeXml($.display,!0)}flushMarkdown(){if(this.interactive){try{let $=this.md.flush();if($)process.stdout.write($)}catch{}if(this.rawText.trim())console.log()}this.rawText=""}flushOutput(){let $=this.flushSplitText();return this.flushMarkdown(),$}flushOnError(){if(this.interactive&&this.rawText.trim())console.log();let $=this.flushSplitText();if(this.interactive)try{process.stdout.write(this.md.flush())}catch{}return this.rawText="",$}}class nW{params;stop={budget:!1,doom:!1,steer:!1,cap:!1,context:!1,tools:!1,stall:!1,wrapUp:!1};hasError=!1;assembler;renderer;usageSteps=0;innerController=new AbortController;forwardAbort=()=>this.innerController.abort();xmlSearchRecovered=!1;answerAfterXml=!1;pendingLoop=null;stepFinishSeen=!1;stepUsage;totalUsage;overflowError;constructor($){this.params=$;this.assembler=new hW($.messages,(Z)=>{if($.onStepPersist)r0($.onStepPersist,Z)}),this.renderer=new mW($.cbs,!$.callbacks)}get signal(){return this.innerController.signal}attachAbort(){this.params.abortSignal?.addEventListener("abort",this.forwardAbort,{once:!0})}detachAbort(){this.params.abortSignal?.removeEventListener("abort",this.forwardAbort)}onStepFinish($){let{tracker:Z,checkBudget:J,allowContextAbort:z,compactThreshold:G,messages:Q,overTurnBudget:Y}=this.params;if($&&Z)Z.update($);if(this.usageSteps++,J())this.stop.budget=!0,this.innerController.abort();else if(Y(this.assembler.innerSteps))this.stop.wrapUp=!0,this.innerController.abort();else if(z&&this.usageSteps>=2&&Z&&Z.lastInputTokens>G)this.stop.context=!0,this.innerController.abort();else if(this.usageSteps>=YA&&d6(Q,this.params.pruneBudget())!==Q)this.stop.tools=!0,this.innerController.abort()}noteStepUsage($){this.stepUsage=gW(this.stepUsage,$)}resolvedUsage($){let Z=_A($,this.totalUsage,this.stepUsage);if(W8(Z))return Z;let J=this.estimateUsage();if(!J)return Z;if(this.params.tracker)this.params.tracker.update(J);return Q0("info",`usage estimated for aborted pass in=${J.inputTokens} out=${J.outputTokens}`),J}estimateUsage(){let $=this.assembler.producedTokens;if($===0)return;let Z=x1(this.params.messages)+this.params.overhead.tokens;return{inputTokens:Z,outputTokens:$,totalTokens:Z+$,inputTokenDetails:{noCacheTokens:Z,cacheReadTokens:void 0,cacheWriteTokens:void 0},outputTokenDetails:{textTokens:$,reasoningTokens:void 0}}}onStepError($){let Z=String($);if(P8(Z))this.stop.context=!0;Q0("warn",`step failed (will retry): ${Z}`)}async applySlices($){for(let Z of $)if(Z.type==="display"){if(!Z.text)continue;if(this.assembler.pendingResults>0)this.assembler.flushStep();if(this.assembler.appendText(Z.text),this.xmlSearchRecovered&&Z.text.trim())this.answerAfterXml=!0}else if(await this.materializeXmlSearch(Z.block))return!0;return!1}applyLoopAction($){if($==="ok")return!1;if($==="halt")return this.stop.doom=!0,this.innerController.abort(),!0;return this.pendingLoop=$,jA(this.params.allTools),!1}settlePendingLoop(){if(!this.pendingLoop)return!1;if(this.assembler.hasUnpairedCalls)return!1;return this.stop.steer=this.pendingLoop==="steer",this.stop.cap=this.pendingLoop==="cap",this.pendingLoop=null,this.innerController.abort(),!0}async flushAndSettleLoop(){if(this.assembler.hasUnpairedCalls)return!1;if(await this.flushOutputAndStep())return!0;return this.settlePendingLoop()}async materializeXmlSearch($){let{cbs:Z,loopGuard:J}=this.params,z="search_web",G=$.query.trim(),Q={query:G},Y=this.assembler.nextMissingCallId();if(this.renderer.flushMarkdown(),this.assembler.recordCall({toolCallId:Y,toolName:"search_web",input:Q}),BZ("search_web",Q),Z.onToolCall)r0(Z.onToolCall,"search_web",Q,Y);else TJ("search_web",Q);if(J.researchCapped){let P=O9;if(this.assembler.recordResult({toolCallId:Y,toolName:"search_web",output:P}),v6("search_web",P),Z.onToolResult)r0(Z.onToolResult,"search_web",P,{toolCallId:Y,isError:!1});else K8("search_web",P,!1);return this.xmlSearchRecovered=!0,!1}if(this.applyLoopAction(J.observe("search_web",Q))){let P=C9;if(this.assembler.recordResult({toolCallId:Y,toolName:"search_web",output:P}),v6("search_web",P),Z.onToolResult)r0(Z.onToolResult,"search_web",P,{toolCallId:Y,isError:!1});else K8("search_web",P,!1);return!0}let K=$.kind==="results"?$.body:await this.executeSearchWeb(G,Y),X=typeof K==="string"&&/^(error|search error)\b/i.test(K);if(this.assembler.recordResult({toolCallId:Y,toolName:"search_web",output:K}),v6("search_web",K),Z.onToolResult)r0(Z.onToolResult,"search_web",K,{toolCallId:Y,isError:X});else K8("search_web",K,X);return this.xmlSearchRecovered=!0,this.applyLoopAction(J.observeResult("search_web",X?"error":K)),!1}async executeSearchWeb($,Z){if(!$)return'Search error: "query" must be a non-empty string.';let J=this.params.allTools.search_web;if(typeof J?.execute!=="function")return"Search error: search_web is unavailable.";try{let z=await J.execute({query:$},{toolCallId:Z,messages:this.params.messages,abortSignal:this.signal});return typeof z==="string"?z:S9(z)}catch(z){return`Search error: ${z instanceof Error?z.message:String(z)}`}}async flushOutputAndStep(){let $=await this.applySlices(this.renderer.flushOutput());return this.assembler.flushStep(),$}async handleEvent($){let{cbs:Z,loopGuard:J}=this.params;switch($.type){case"start-step":if(this.stepFinishSeen=!1,!this.assembler.hasUnpairedCalls)this.assembler.flushStep();return!1;case"finish-step":return this.stepFinishSeen=!0,this.noteStepUsage($.usage),await this.flushAndSettleLoop();case"finish":if(W8($.totalUsage))this.totalUsage=$.totalUsage;return!1;case"reasoning-delta":{let z=typeof $.text==="string"?$.text:"";if(z)this.renderer.feedReasoning(z);return!1}case"text-delta":{if(this.assembler.pendingResults>0&&await this.flushOutputAndStep())return!0;return await this.applySlices(this.renderer.feedText($.text))}case"tool-call":{if(this.assembler.pendingResults>0&&await this.flushOutputAndStep())return!0;if(await this.applySlices(this.renderer.flushOutput()))return!0;let z=$.toolName||"unknown",G=$.toolCallId||this.assembler.nextMissingCallId();if(this.assembler.recordCall({toolCallId:G,toolName:z,input:$.input}),BZ(z,$.input),Z.onToolCall)r0(Z.onToolCall,z,$.input,G);else TJ(z,$.input);if(this.applyLoopAction(J.observe(z,$.input)))return await this.flushOutputAndStep(),!0;return!1}case"tool-result":case"tool-error":{let z=$.type==="tool-error",G=z?$.error:$.output,Q=z?`Error: ${S9($.error)}`:$.output;if(this.assembler.recordResult({toolCallId:$.toolCallId,toolName:$.toolName||"unknown",output:G}),v6($.toolName,Q),Z.onToolResult)r0(Z.onToolResult,$.toolName,Q,{toolCallId:$.toolCallId,isError:z});else K8($.toolName,Q,z);if(this.applyLoopAction(J.observeResult($.toolName||"unknown",z?"error":G)),this.stepFinishSeen||this.pendingLoop)return await this.flushAndSettleLoop();return!1}case"error":{let z=String($.error);if(cZ($.error))return this.stop.stall=!0,Q0("warn",`provider stall: ${d3($.error)}`),await this.flushOutputAndStep(),this.innerController.abort(),!0;if(P8(z))return this.stop.context=!0,this.overflowError=z,Q0("warn",`context overflow: ${z}`),await this.flushOutputAndStep(),this.innerController.abort(),!0;if(this.hasError=!0,Q0("error",`stream error: ${z}`),Z.onStreamError)r0(Z.onStreamError,l4(z));else console.error(`\x1B[31m${l4(z)}\x1B[0m`);return!1}}return!1}snapshot($,Z={}){return{hasError:this.hasError,userAborted:Boolean(this.params.abortSignal?.aborted),budgetExceeded:this.stop.budget,doomLoop:this.stop.doom,researchSteer:this.stop.steer,researchCap:this.stop.cap,contextPressure:this.stop.context,toolPressure:this.stop.tools,maxStepsReached:this.params.stepBounded&&this.assembler.innerSteps>=this.params.maxSteps&&this.assembler.lastStepHadTools,wrapUp:this.stop.wrapUp,lastStepHadTools:this.assembler.lastStepHadTools,xmlToolFollowUp:this.xmlSearchRecovered&&!this.answerAfterXml&&!this.stop.doom,emptyCompletion:!this.stop.context&&!this.assembler.hadAssistantText&&!this.assembler.hadTools&&!this.xmlSearchRecovered,overflowError:this.overflowError,providerStall:this.stop.stall,stepCount:this.assembler.innerSteps,usage:$,...Z}}async finalize($){return await this.flushOutputAndStep(),this.settlePendingLoop(),this.snapshot(this.resolvedUsage($?await wW($):void 0))}async handleException($,Z){await this.applySlices(this.renderer.flushOnError()),this.assembler.flushStep(),this.settlePendingLoop();let J=this.resolvedUsage(Z?await wW(Z):void 0);if(this.params.abortSignal?.aborted)return this.snapshot(J,{userAborted:!0});if(cZ($)){let Q=this.assembler.hadAssistantText||this.assembler.hadTools||this.renderer.hadThinking;return Q0("warn",`provider stall: ${d3($)}`),this.stop.stall=!0,this.snapshot(J,{hasError:!1,userAborted:!1,emptyCompletion:!Q})}if($ instanceof Error&&$.name==="AbortError")return this.snapshot(J,{userAborted:!1});let z=$ instanceof Error?$.message:String($);if(Q0("error",z),P8(z))return this.stop.context=!0,this.overflowError=z,this.snapshot(J,{hasError:!1,contextPressure:!0,userAborted:!1});this.hasError=!0;let G=l4(z);if(this.params.cbs.onStreamError)r0(this.params.cbs.onStreamError,G);else if(G!==z)console.error(`\x1B[31m${G}\x1B[0m`);else console.error(`\x1B[31mError: ${z}\x1B[0m`);return this.snapshot(J,{hasError:!0,userAborted:!1,contextPressure:!1})}}async function OA($){let Z=new nW($),J;try{Z.attachAbort();let z=FA($.allTools,$.messages,$.taskState,$.loopGuard,$.memory),G=[$.systemPrompt,...z.stable].join(`
|
|
399
399
|
|
|
400
|
-
`);r6($.messages,$.pruneBudget());let Q=NA(z.volatile),Y=Q?[...$.messages,Q]:$.messages;$.overhead.tokens=a3(G,$.allTools)+(Q?a3(String(Q.content)):0);let K=m5({runOverride:$.thinking,providerType:$.providerType,modelId:$.modelId}),X=()=>ij({model:$.model,system:G,messages:Y,allowSystemInMessages:!0,tools:$.allTools,stopWhen:tj($.maxSteps),maxRetries:3,abortSignal:Z.signal,...$.temperature!=null?{temperature:$.temperature}:{},...$.maxTokens!=null?{maxOutputTokens:$.maxTokens}:{},...$.topP!=null?{topP:$.topP}:{},onStepFinish({usage:P}){Z.onStepFinish(P)},onError({error:P}){Z.onStepError(P)}});J=W6.run(K,X);for await(let P of J.fullStream)if(await Z.handleEvent(P))break;return await Z.finalize(J)}catch(z){return Z.handleException(z,J)}finally{Z.detachAbort()}}async function cW($,Z,J,z,G,Q,Y){let K=u1(),X=r4(K,Z);return uW($,X,J,z,G,Q,Y)}async function xJ($,Z,J,z,G,Q,Y){return uW($,Z,J,z,G,Q,Y)}var $A=1e5,ZA
|
|
400
|
+
`);r6($.messages,$.pruneBudget());let Q=NA(z.volatile),Y=Q?[...$.messages,Q]:$.messages;$.overhead.tokens=a3(G,$.allTools)+(Q?a3(String(Q.content)):0);let K=m5({runOverride:$.thinking,providerType:$.providerType,modelId:$.modelId}),X=()=>ij({model:$.model,system:G,messages:Y,allowSystemInMessages:!0,tools:$.allTools,stopWhen:tj($.maxSteps),maxRetries:3,abortSignal:Z.signal,...$.temperature!=null?{temperature:$.temperature}:{},...$.maxTokens!=null?{maxOutputTokens:$.maxTokens}:{},...$.topP!=null?{topP:$.topP}:{},onStepFinish({usage:P}){Z.onStepFinish(P)},onError({error:P}){Z.onStepError(P)}});J=W6.run(K,X);for await(let P of J.fullStream)if(await Z.handleEvent(P))break;return await Z.finalize(J)}catch(z){return Z.handleException(z,J)}finally{Z.detachAbort()}}async function cW($,Z,J,z,G,Q,Y){let K=u1(),X=r4(K,Z);return uW($,X,J,z,G,Q,Y)}async function xJ($,Z,J,z,G,Q,Y){return uW($,Z,J,z,G,Q,Y)}var $A=1e5,ZA,JA=4,IW=1000,zA=8000,GA=0,QA=0,YA=4,KA="Continue the task from where you left off. Do not wait for another user message. If the work is complete, give a brief summary and stop.",TW="You are out of time budget for this turn. Stop starting new work: finish or save what is already in progress, then reply with a short summary of what is done, what is not, and the exact next step. Do not call more tools than needed to leave things in a consistent state.",XA,RW=5242880,PA,h2,SW="本轮已达时间或步数预算,已让模型收尾并停止。发送消息可继续",vW="## Session state (reference only — not a to-do list, not part of the conversation)",VA="Error: tool call was interrupted before a result was returned.";var i4=C(()=>{c4();pZ();d();S2();LJ();J8();m$();n$();H4();K1();b1();g1();jJ();h7();b9();w9();Q8();FW();x4();p4();u4();S3();H4();ZA=Number.MAX_SAFE_INTEGER,XA=TW,PA={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp"},h2="NO_COLOR"in process.env?{dim:"",reset:""}:{dim:"\x1B[90m",reset:"\x1B[0m"}});var x9={};M0(x9,{pushTurn:()=>CA,popTurn:()=>bA,createUndoStack:()=>uJ,clearStack:()=>v9});function uJ(){return[]}function CA($,Z,J,z){return[...$,{start:Z,end:J,uiEnd:z}]}function bA($){if($.length===0)return null;return{turn:$[$.length-1],stack:$.slice(0,-1)}}function v9($){return[]}var oW={};M0(oW,{getWorkingTreeDiff:()=>hJ});import{execFile as wA}from"child_process";import{promisify as IA}from"util";async function hJ($=process.cwd(),Z=RA){try{await Z("git rev-parse --is-inside-work-tree",$)}catch{return{ok:!1,reason:"not_git",message:"当前目录不是 git 仓库"}}let J="",z="";try{J=await Z("git diff --stat",$),z=await Z("git diff",$)}catch(Q){return{ok:!1,reason:"error",message:Q instanceof Error?Q.message:String(Q)}}if(!z.trim())return{ok:!1,reason:"no_changes",message:"工作区无未提交变更"};let G=z.length>pW?z.slice(0,pW)+`
|
|
401
401
|
… [diff 过长,已截断]`:z;return{ok:!0,diff:J?`${J}
|
|
402
402
|
|
|
403
403
|
${G}`:G}}async function RA($,Z){let J=kA($),{stdout:z}=await TA(J[0],J.slice(1),{cwd:Z,encoding:"utf-8",timeout:1e4,maxBuffer:10485760});return z}function kA($){let Z=[],J="",z=null;for(let G of $)if(z)if(G===z)z=null;else J+=G;else if(G==='"'||G==="'")z=G;else if(G===" "){if(J)Z.push(J),J=""}else J+=G;if(J)Z.push(J);return Z}var pW=8000,TA;var mJ=C(()=>{TA=IA(wA)});var g9={};M0(g9,{snapshotTokenInfo:()=>yA});async function yA($,Z,J){let z=await e$(Z);return sY($,z.tokens,x1(J))}var u9=C(()=>{g1();p4()});function k($,Z){$.addMessage({id:`sys-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,role:"system",content:Z,timestamp:Date.now()})}async function dW($,Z,J,z,G,Q,Y,K){let{parseSlashArgs:X}=await Promise.resolve().then(() => (q3(),cQ)),P=X($),W=$.slice(1).trim().split(/\s+/),H=(P?.command||W[0]||"").toLowerCase(),U=P?[...P.tokens,...P.partial?[P.partial]:[]]:W.slice(1),q=U.join(" "),{truncateDisplay:M}=await Promise.resolve().then(() => IJ);switch(H){case"exit":case"quit":case"q":Y();break;case"new":K.startNewSession();break;case"undo":{let{popTurn:F}=await Promise.resolve().then(() => x9),N=F(K.undoStack);if(!N){k(Z,"没有可撤销的内容");break}K.setUndoStack(N.stack),J.splice(N.turn.start,N.turn.end-N.turn.start),Z.truncateMessages(N.turn.uiEnd),k(Z,"✓ 已撤销 1 轮");break}case"redo":{if(!K.lastUserMessage){k(Z,"没有可重发的消息");break}let F=K.lastUserMessage;return Z.addMessage({id:`user-${Date.now()}`,role:"user",content:F,timestamp:Date.now()}),J.push({role:"user",content:F}),"run"}case"diff":{let{getWorkingTreeDiff:F}=await Promise.resolve().then(() => (mJ(),oW)),N=await F();if(!N.ok){let f=N.reason==="not_git"?"非 git 仓库,无法显示 diff":N.reason==="no_changes"?"工作区无未提交变更":`diff 失败: ${N.message}`;k(Z,f)}else k(Z,N.diff);break}case"plan":{K.togglePlanMode(),k(Z,K.planMode?"✓ 计划模式已开启:仅只读工具可用,输出计划后再次输入 /plan 确认并执行":"✓ 已退出计划模式");break}case"reload":await K.reloadSystemPrompt();break;case"resume":case"sessions":{let F=q.trim();if(!F){K.openSessionPicker();break}K.applySession(F);break}case"rename":{let F=q.trim();if(!F){k(Z,"用法: /rename <标题>");break}let{saveSession:N,renameSession:f}=await Promise.resolve().then(() => (u$(),g4)),B=K.sessionId;if(!B)B=N(J,void 0,void 0,void 0,K.taskState),K.setSessionId(B);if(f(B,F))k(Z,`✓ 会话已重命名为: ${F}`);else k(Z,"重命名失败: 会话不存在");break}case"attach":case"image":{let F=q;if(!F){k(Z,"用法: /attach <图片路径>");break}let{loadImageParts:N}=await Promise.resolve().then(() => (i4(),gJ)),B=[{type:"text",text:""},...N([F],(_,V)=>{if(_==="not_found")k(Z,`⚠ 图片不存在: ${V}`);else if(_==="too_large")k(Z,`⚠ 图片超过 5MB 限制: ${V}`)})];if(B.length<=1)break;return J.push({role:"user",content:B}),Z.addMessage({id:`user-${Date.now()}`,role:"user",content:`[\uD83D\uDCCE 图片] ${F}`,timestamp:Date.now()}),"run"}case"compact":{let{compactMessages:F}=await Promise.resolve().then(() => (g1(),s3)),{estimateTokens:N}=await Promise.resolve().then(() => (g1(),s3)),{resolveModel:f}=await Promise.resolve().then(() => (c4(),mX)),{clearStack:B}=await Promise.resolve().then(() => x9);if(J.length<4)k(Z,"消息太少,无需压缩");else{k(Z,"⟳ 正在压缩上下文...");let _=f(z);K.setUndoStack(B(K.undoStack));let V=await F(J,_,{keepRecentTurns:2,taskGoal:K.taskState.goal||void 0});if(J.length=0,J.push(...V.messages),G)G.resetContext();k(Z,`✓ 已压缩 (约 ${N(J)} tokens)`);let{snapshotTokenInfo:A}=await Promise.resolve().then(() => (u9(),g9));Z.setTokenInfo(await A(G,z,J))}break}case"provider":{let{applyProviderSwitch:F,listProviderChoices:N}=await Promise.resolve().then(() => (v4(),y3));if(q){let f=F(q);if(!f.ok){k(Z,f.message);break}Q(f.defaultModel),K.setProvider(f.name),k(Z,`✓ 当前服务商已切换为: ${f.name}`);break}if(N().length===0){k(Z,"无已配置服务商,运行: min-agent setup");break}Z.showProviderPicker();break}case"model":{if(q){let F=await Promise.resolve().then(() => (d(),C1)),N=F.loadConfig(),f=F.getActiveProvider(N);if(f&&F.isBuiltinProvider(f)&&q!==F.BUILTIN_MODEL){k(Z,`内置服务商仅支持模型: ${F.BUILTIN_MODEL}`);break}if(f)f.defaultModel=q,F.saveConfig(N);Q(q),k(Z,`✓ 默认模型已设为: ${q}`)}else Z.showModelPicker();break}case"models":{let{fetchModels:F}=await Promise.resolve().then(() => (d(),C1)),{loadConfig:N,getActiveProvider:f}=await Promise.resolve().then(() => (d(),C1)),B=N(),_=f(B);if(!_?.baseURL||!_?.apiKey){k(Z,"未配置 Provider,运行: min-agent setup");break}k(Z,"正在获取模型列表...");let V=await F(_.baseURL,_.apiKey);if(V.length===0)k(Z,"无法获取模型列表");else{let A=V.map((O)=>{let v=O===_.defaultModel?" ← 默认":"";return` ${O}${v}`});k(Z,`可用模型 (${V.length}):
|
package/package.json
CHANGED
|
@@ -45,8 +45,8 @@ Read this when you need exact keys. Files are strict JSON.
|
|
|
45
45
|
"emptyRetryDelayMs": 1000,
|
|
46
46
|
"requestTimeoutMs": 180000,
|
|
47
47
|
"streamIdleTimeoutMs": 90000,
|
|
48
|
-
"turnTimeLimitMs":
|
|
49
|
-
"softStepLimit":
|
|
48
|
+
"turnTimeLimitMs": 0,
|
|
49
|
+
"softStepLimit": 0,
|
|
50
50
|
"subAgentMaxSteps": 15,
|
|
51
51
|
"exploreMaxSteps": 20,
|
|
52
52
|
"researchSteerAfter": 3,
|
|
@@ -60,10 +60,10 @@ Read this when you need exact keys. Files are strict JSON.
|
|
|
60
60
|
- `memory`: `on` | `off`; omit to keep **off**. When off, stored `memory.json` entries are not injected and memory tools are unavailable. A project `memory` value overlays global; writing memory globally removes the project overlay. `/memory --project` writes only the project file.
|
|
61
61
|
- `contextWindow`: tokens; omit to query the API. An `ollama` provider uses `POST /api/show`: Modelfile `num_ctx` if set, otherwise min(architecture context_length, 32768), else 2048. Chat goes to native `POST /api/chat` with that value as `options.num_ctx` (OpenAI-compatible `/v1` ignores it). Interactive `/ctx` (and `min-agent ctx`) sets this field on the active ollama provider to a fixed level (`2k` / `4k` / `8k` / `12k` / `16k` / `32k` / `64k` / `128k` / `256k`) or `auto` to clear it. Other providers then 512k fallback.
|
|
62
62
|
- `agent.autoContinue` omitted → uses `compaction.autoContinue` (default true).
|
|
63
|
-
- `agent.maxSteps` omitted → no tool-step ceiling.
|
|
63
|
+
- `agent.maxSteps` omitted → no tool-step ceiling. `agent.maxContinues` omitted → no auto-continue ceiling.
|
|
64
64
|
- `agent.maxEmptyAttempts` / `agent.emptyRetryDelayMs`: retries when the provider returns an empty stream (HTTP 200, no content). First retry is immediate, later ones back off exponentially, capped at 8s.
|
|
65
65
|
- `agent.requestTimeoutMs` / `agent.streamIdleTimeoutMs`: abort a request that never starts responding, or a stream that goes quiet mid-response; the run then retries it like an empty reply. 0 disables. Env overrides: `MIN_AGENT_REQUEST_TIMEOUT_MS`, `MIN_AGENT_STREAM_IDLE_TIMEOUT_MS`.
|
|
66
|
-
- `agent.turnTimeLimitMs` / `agent.softStepLimit`: budget for one turn. On expiry the model is asked to wrap up once, then the turn stops. 0 disables either half.
|
|
66
|
+
- `agent.turnTimeLimitMs` / `agent.softStepLimit`: budget for one turn. On expiry the model is asked to wrap up once, then the turn stops. Both default to 0 (disabled) so long-running turns are not cut off; 0 disables either half.
|
|
67
67
|
- `agent.subAgentMaxSteps` / `agent.exploreMaxSteps`: step ceilings for the `task` and `explore` sub-agents. Sub-agents share the parent's research budget and cost budget.
|
|
68
68
|
- `agent.researchSteerAfter` / `researchStopAfter`: research *rounds that returned no new source* before steering / dropping `search_web` and `web_fetch`; `researchTotalCap` is the hard number of research calls per turn. Productive research (new URLs or domains each round) is not penalised.
|
|
69
69
|
- `tools.bashTimeoutMs`: default kill timeout for `bash` (10 minutes; the model can override per call, 0 disables).
|