@yuandc/aica 0.1.35 → 0.1.37
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/acp/client/acp-events.js +1 -1
- package/dist/acp/providers/codex/codex-path.js +1 -1
- package/dist/acp/providers/codex/collaboration-events.js +1 -0
- package/dist/acp/providers/codex/events.js +9 -9
- package/dist/acp/providers/codex-acp/adapter.js +4 -4
- package/dist/acp/providers/codex-acp/provider.js +1 -1
- package/dist/acp/providers/codex-acp/subtask-history.js +3 -0
- package/dist/acp/providers/codex-acp/subtask-routing.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createPlanEvent as y,normalizePlanSessionUpdate as _}from"../plan-events.js";import{STANDARD_AGENT_EVENT_TYPES as A,createAgentMessageChunk as b,createAgentProgressChunk as x,createAgentThoughtChunk as k,createToolCall as C,createToolCallUpdate as I,firstString as a,normalizeToolKind as S,normalizeToolStatus as h}from"../standard-events.js";function f(n){if(!n||typeof n!="object"||Array.isArray(n))return null;const t=n,e=t.update;return!e||typeof e!="object"||Array.isArray(e)?null:{sessionId:typeof t.sessionId=="string"?t.sessionId:void 0,update:e}}function E(n){const t=f(n);if(!t)return null;const e=String(t.update.sessionUpdate||""),r=
|
|
1
|
+
import{createPlanEvent as y,normalizePlanSessionUpdate as _}from"../plan-events.js";import{STANDARD_AGENT_EVENT_TYPES as A,createAgentMessageChunk as b,createAgentProgressChunk as x,createAgentThoughtChunk as k,createToolCall as C,createToolCallUpdate as I,firstString as a,normalizeToolKind as S,normalizeToolStatus as h}from"../standard-events.js";function f(n){if(!n||typeof n!="object"||Array.isArray(n))return null;const t=n,e=t.update;return!e||typeof e!="object"||Array.isArray(e)?null:{sessionId:typeof t.sessionId=="string"?t.sessionId:void 0,update:e}}function E(n){const t=f(n);if(!t)return null;const e=String(t.update.sessionUpdate||""),r=u(t.update._meta)??void 0;if(e==="agent_message_chunk")return b({text:i(t.update.content),method:"session/update",params:n,meta:r});if(e==="agent_progress_chunk")return x({text:i(t.update.content),method:"session/update",params:n,meta:r});if(e==="agent_thought_chunk")return k({text:i(t.update.content),method:"session/update",params:n,meta:r});if(e==="tool_call"||e==="tool_call_update")return w(e,t.update,n);if(e==="plan"||e==="plan_update"||e==="plan_removed"){const o=_(t.update);return o?y({update:o,method:"session/update",params:n,meta:r}):null}return A.has(e)?{type:e,label:T(e),...i(t.update.content)?{text:i(t.update.content)}:{},raw:{method:"session/update",params:n,update:t.update},atMs:Date.now()}:null}function P(n){const t=f(n);if(!t||m(t.update))return null;const e=String(t.update.sessionUpdate||"");if(e==="agent_message_chunk")return{phase:"thinking",label:"回复中",detail:g(i(t.update.content)),updateType:e};if(e==="agent_progress_chunk")return{phase:"thinking",label:"处理中",detail:g(i(t.update.content)),updateType:e};if(e==="agent_thought_chunk")return{phase:"thinking",label:"思考中",detail:g(i(t.update.content)),updateType:e};if(e==="tool_call"||e==="tool_call_update"){const r=a(t.update.toolCallId,t.update.id),o=h(a(t.update.status)),s=a(t.update.title,t.update.kind),c=U(t.update.rawOutput);if(r==="codex.connection")return{phase:o==="failed"?"failed":o==="completed"?"exploring":"resuming",label:s||(o==="completed"?"Codex 连接已恢复":"Codex 正在重连"),detail:c,updateType:e};if(r==="codex.error")return{phase:"failed",label:s||"Codex 执行异常",detail:c,updateType:e};const d=u(t.update.rawInput),l=a(d?.command);return s==="压缩上下文"?{phase:"thinking",label:"压缩上下文",updateType:e}:s==="等待协作消息"?{phase:"exploring",label:"等待协作消息",updateType:e}:/^(?:(?:启动|发送|恢复|等待|结束|中断|查看|处理)子任务|子任务(?:交互|完成|中断))/.test(s||"")?{phase:"exploring",label:s||"处理子任务",updateType:e}:l?{phase:"exploring",label:"执行命令",detail:s||l,updateType:e}:{phase:"exploring",label:"调用工具",detail:s,updateType:e}}return e==="plan"||e==="plan_update"?{phase:"thinking",label:"规划中",updateType:e}:e==="aca_context_maintenance"?{phase:"thinking",label:a(t.update.label)||"正在整理会话上下文",detail:a(t.update.detail),updateType:e}:null}function D(n){const t=f(n);return t?m(t.update):null}function m(n){const t=u(n._meta),e=u(t?.aca);return u(e?.subtask)}function i(n){if(typeof n=="string")return n;if(!n||typeof n!="object"||Array.isArray(n))return"";const t=n;return typeof t.text=="string"?t.text:""}function w(n,t,e){const r=a(t.toolCallId,t.id)||`acp.${Date.now()}`,o=S(a(t.kind,t.title)),s=h(a(t.status)),c=t.rawInput??t.input,d=t.rawOutput??t.output,l={method:"session/update",params:e,toolCallId:r,kind:o,title:a(t.title,t.kind),status:s,rawInput:c,rawOutput:d,content:t.content,locations:Array.isArray(t.locations)?t.locations.filter(p=>!!(p&&typeof p=="object"&&!Array.isArray(p))):void 0,meta:t._meta&&typeof t._meta=="object"&&!Array.isArray(t._meta)?t._meta:void 0};return n==="tool_call"?C(l):I(l)}function T(n){return n.replace(/_/g," ")}function g(n){const t=n.replace(/\s+/g," ").trim();if(t)return t.length>120?`${t.slice(0,117)}...`:t}function U(n){if(!n||typeof n!="object"||Array.isArray(n))return;const t=n,e=t.error&&typeof t.error=="object"&&!Array.isArray(t.error)?t.error:null,r=a(e?.message,t.message),o=/reconnecting\.{3}\s*(\d+)\s*\/\s*(\d+)/i.exec(r||"");return o?`第 ${o[1]}/${o[2]} 次尝试`:/selected model is at capacity/i.test(r||"")?"所选模型当前繁忙,请稍后重试":r}function u(n){return n&&typeof n=="object"&&!Array.isArray(n)?n:null}export{f as acpSessionUpdateFromParams,E as eventFromAcpSessionUpdate,P as statusFromAcpSessionUpdate,D as subtaskContextFromAcpSessionUpdate,i as textFromAcpContent};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import d from"node:fs";import T from"node:os";import
|
|
1
|
+
import d from"node:fs";import{createRequire as T}from"node:module";import F from"node:os";import L from"node:path";const g=T(import.meta.url);function v(n={}){const e=n.env??process.env,r=n.platform??process.platform,c=n.arch??process.arch,o=n.homeDir??F.homedir(),i=n.execPath??process.execPath,t=r==="win32"?L.win32:L.posix,u=l(e.CODEX_PATH);if(u){const s=C(u,e,r,t);return s?$(s,r,c,t)??s:u}const f=n.bundledCodexLauncher===void 0?O():l(n.bundledCodexLauncher??void 0),a=x([f,C("codex",e,r,t),...k(e,r,o,i,t)]);let P=null;for(const s of a){if(!s||!w(s,r))continue;const b=S(s,r,c,t);if(b)return b;if(!D(s))return s;P??=s}for(const s of M(e,r,o,i,t)){const b=j(s,r,c,t);if(b)return b}return P??"codex"}function O(){try{return g.resolve("@openai/codex/bin/codex.js")}catch{return null}}function k(n,e,r,c,o){const i=e==="win32"?"codex.exe":"codex",t=e==="win32"?"codex.cmd":"codex",u=l(n.npm_config_prefix),f=l(n.APPDATA),a=l(n.LOCALAPPDATA);return x([o.join(r,".codex","packages","standalone","current","bin",i),n.NVM_BIN?o.join(n.NVM_BIN,i):null,n.VOLTA_HOME?o.join(n.VOLTA_HOME,"bin",i):null,u?o.join(u,e==="win32"?"":"bin",t):null,o.join(o.dirname(c),t),e==="win32"&&f?o.join(f,"npm",t):null,e==="win32"&&a?o.join(a,"npm",t):null,e!=="win32"?o.join(r,".local","bin",i):null,e==="darwin"?"/opt/homebrew/bin/codex":null,e!=="win32"?"/usr/local/bin/codex":null,e!=="win32"?"/usr/bin/codex":null])}function M(n,e,r,c,o){const i=x([l(n.npm_config_prefix),l(n.NVM_BIN)?o.dirname(l(n.NVM_BIN)):null,o.dirname(o.dirname(c)),e==="win32"?l(n.APPDATA):null,e==="win32"?l(n.LOCALAPPDATA):null,e!=="win32"?o.join(r,".local"):null,e!=="win32"?"/usr/local":null,e!=="win32"?"/usr":null]);return x(i.flatMap(t=>_(t,e,o)))}function S(n,e,r,c){const o=E(n,e,c);for(const i of o){const t=j(i,e,r,c);if(t)return t}return null}function $(n,e,r,c){for(const o of B(n,c)){const i=j(o,e,r,c);if(i)return i}return null}function E(n,e,r){const c=[];let o=y(n)??n;o=r.dirname(o);for(let i=0;i<8;i+=1){r.basename(o)==="codex"&&r.basename(r.dirname(o))==="@openai"&&c.push(o),c.push(..._(o,e,r));const t=r.dirname(o);if(t===o)break;o=t}return x(c)}function B(n,e){const r=[];let c=e.dirname(y(n)??n);for(let o=0;o<8;o+=1){e.basename(c)==="codex"&&e.basename(e.dirname(c))==="@openai"&&r.push(c);const i=e.dirname(c);if(i===c)break;c=i}return x(r)}function _(n,e,r){return e==="win32"?[r.join(n,"node_modules","@openai","codex")]:[r.join(n,"lib","node_modules","@openai","codex"),r.join(n,"node_modules","@openai","codex")]}function j(n,e,r,c){if(!N(n))return null;const o=`codex-${e}-${r==="x64"?"x64":r}`,i=c.join(n,"node_modules","@openai",o),t=c.dirname(n),u=c.basename(n)==="codex"&&c.basename(t)==="@openai"?c.join(t,o):null;return m(i,e,c)??(u?m(u,e,c):null)??m(n,e,c)}function m(n,e,r,c=0){if(c>8||!N(n))return null;let o;try{o=d.readdirSync(n,{withFileTypes:!0})}catch{return null}const i=e==="win32"?"codex.exe":"codex";for(const t of o){const u=r.join(n,t.name);if(t.isFile()&&t.name.toLowerCase()===i&&w(u,e)&&!D(u))return u}for(const t of o){if(!t.isDirectory())continue;const u=m(r.join(n,t.name),e,r,c+1);if(u)return u}return null}function C(n,e,r,c){if(c.isAbsolute(n)||n.includes("/")||n.includes("\\"))return w(n,r)?n:null;const o=r==="win32"?n.includes(".")?[""]:(e.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";").map(t=>t.toLowerCase()):[""],i=r==="win32"?";":":";for(const t of(e.PATH||"").split(i)){const u=l(t);if(u)for(const f of o){const a=c.join(u,`${n}${f}`);if(w(a,r))return a}}return null}function w(n,e){try{return d.accessSync(n,e==="win32"?d.constants.F_OK:d.constants.X_OK),d.statSync(n).isFile()}catch{return!1}}function N(n){try{return d.statSync(n).isDirectory()}catch{return!1}}function D(n){const e=y(n)??n;if(/\.(?:js|mjs|cjs|cmd|bat)$/i.test(e))return!0;try{const r=d.readFileSync(e,{encoding:"utf8",flag:"r"}).slice(0,256);return/^#!.*\bnode\b/m.test(r)}catch{return!1}}function y(n){try{return d.realpathSync(n)}catch{return null}}function l(n){return n?.trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2")||null}function x(n){return[...new Set(n.filter(e=>e!=null))]}export{v as resolveCodexPath};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function m(t,e){const n=a(e,"type");return n==="subAgentActivity"?v(t,e):n!=="collabAgentToolCall"&&n!=="collabToolCall"?null:t==="item/started"?k(e):w(e)}function k(t){const e=a(t,"tool"),n=f(t),r=g(n,t.agentsStates),o=e==="wait"&&!r?"collaboration_wait":"subtask";return s({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:h(e,r,t),status:i(a(t,"status")),rawInput:u(t,n),_meta:{aca:{processKind:o,action:e,collaboration:n,task:p(t,e,!1)}}})}function w(t){const e=a(t,"tool"),n=f(t),r=g(n,t.agentsStates),o=e==="wait"&&!r?"collaboration_wait":"subtask";return s({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),kind:"other",title:h(e,r,t),status:b(a(t,"status")),rawInput:u(t,n),rawOutput:s({agentsStates:t.agentsStates,...n}),_meta:{aca:{processKind:o,action:e,collaboration:n,task:p(t,e,!0)}}})}function v(t,e){const n=a(e,"kind"),r=a(e,"agentThreadId"),o=a(e,"agentPath"),l=C(o),I=s({receiverThreadIds:r?[r]:void 0,receiverThreadId:r}),T=_(n,l),y=n==="completed"||n==="interrupted";return s({sessionUpdate:t==="item/started"?"tool_call":"tool_call_update",toolCallId:a(e,"id"),kind:"other",title:T,status:t==="item/started"?"in_progress":n==="interrupted"?"cancelled":"completed",rawInput:{agentThreadId:r,agentPath:o,activityKind:n},_meta:{aca:{processKind:"subtask",action:n==="started"?"spawnAgent":"subAgentActivity",collaboration:I,task:s({taskId:a(e,"id"),kind:"subagent",status:y?n==="interrupted"?"cancelled":"completed":"in_progress",description:l||o,actor:l||"subagent",sourceThreadId:r})}}})}function u(t,e){return s({tool:a(t,"tool"),arguments:s({...e,prompt:c(t,"prompt"),model:c(t,"model"),reasoningEffort:c(t,"reasoningEffort"),agentsStates:d(t.agentsStates)})})}function p(t,e,n){const r=c(t,"prompt");return s({taskId:a(t,"id"),kind:"subagent",status:n?b(a(t,"status")):i(a(t,"status")),description:r,actor:e,modelId:c(t,"model")})}function f(t){const e=new Set(A(t,"receiverThreadIds").filter(r=>typeof r=="string"&&!!r.trim()).map(r=>r.trim()));for(const r of["receiverThreadId","newThreadId"]){const o=a(t,r);o&&e.add(o)}const n=d(t.agentsStates);if(n)for(const r of Object.keys(n))r.trim()&&e.add(r.trim());return s({senderThreadId:a(t,"senderThreadId"),receiverThreadIds:[...e],receiverThreadId:a(t,"receiverThreadId"),newThreadId:a(t,"newThreadId")})}function g(t,e){return A(t,"receiverThreadIds").length>0||!!a(t,"receiverThreadId")||!!a(t,"newThreadId")||Object.keys(d(e)??{}).length>0}function h(t,e,n){const r=S(c(n,"prompt"));switch(t){case"spawnAgent":return r?`启动子任务 · ${r}`:"启动子任务";case"sendInput":case"sendMessage":case"followupTask":return r?`发送子任务指令 · ${r}`:"发送子任务指令";case"resumeAgent":return"恢复子任务";case"wait":return e?"等待子任务":"等待协作消息";case"closeAgent":return"结束子任务";case"interruptAgent":return"中断子任务";case"listAgents":return"查看子任务";default:return"处理子任务"}}function _(t,e){const n=e?` · ${e}`:"";switch(t){case"started":return`启动子任务${n}`;case"interacted":return`子任务交互${n}`;case"completed":return`子任务完成${n}`;case"interrupted":return`子任务中断${n}`;default:return`处理子任务${n}`}}function C(t){return t.split("/").filter(Boolean).at(-1)??""}function S(t){const e=(t||"").replace(/\s+/g," ").trim();return e.length>72?`${e.slice(0,71)}…`:e}function i(t){const e=t.toLowerCase();return["completed","success","succeeded"].includes(e)?"completed":["failed","error"].includes(e)?"failed":["cancelled","canceled","interrupted"].includes(e)?"cancelled":"in_progress"}function b(t){const e=i(t);return e==="in_progress"?"completed":e}function c(t,e){const n=t[e];return typeof n=="string"&&n.trim()?n.trim():void 0}function a(t,e){const r=d(t)?.[e];return typeof r=="string"?r.trim():""}function A(t,e){const r=d(t)?.[e];return Array.isArray(r)?r:[]}function d(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:null}function s(t){const e={};for(const[n,r]of Object.entries(t))r==null||r===""||Array.isArray(r)&&r.length===0||typeof r=="object"&&!Array.isArray(r)&&Object.keys(r).length===0||(e[n]=r);return e}export{m as createCodexCollaborationUpdate};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as ct}from"node:fs";import{applyPatch as lt,parsePatch as ut,reversePatch as it}from"diff";import{createPlanEvent as O}from"../../plan-events.js";import{createCodexCollaborationUpdate as dt}from"./collaboration-events.js";import{codexErrorSessionUpdate as pt}from"./connection-events.js";import{codexPlanUpdateFromNotification as F}from"./plan-events.js";const v=new Set,T=new Set;function se(t,e,n={}){switch(t){case"item/agentMessage/delta":{const r=a(e,"delta"),o=a(e,"itemId"),s=o?n.agentMessagePhases?.get(o):"";return r?s==="commentary"?[h("agent_progress_chunk",r)]:s&&s!=="final_answer"?[]:[h("agent_message_chunk",r)]:[]}case"item/reasoning/summaryTextDelta":case"item/reasoning/textDelta":{const r=a(e,"delta");return r?[h("agent_thought_chunk",r)]:[]}case"turn/plan/updated":{const r=n.planDeltas?.fromSnapshot(e)??F(e);return r?[r]:[]}case"item/plan/delta":{const r=n.planDeltas?.fromDelta(e);return r?[r]:[]}case"item/started":case"item/completed":{const r=y(e,"item"),o=a(r,"type");if(!r||!o||o==="userMessage"||o==="agentMessage"||o==="reasoning")return[];if(o==="exitedReviewMode"){const c=a(r,"review");return t==="item/completed"&&c?[h("agent_message_chunk",`${c}
|
|
2
2
|
|
|
3
|
-
`)]:[]}const s=E(t,r);return s?[s]:
|
|
3
|
+
`)]:[]}const s=E(t,r);return s?[s]:Ot(o)?[]:[t==="item/started"?vt(r):Tt(r)]}case"item/commandExecution/outputDelta":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=i(e,["delta","data","output","text"]);return!r&&!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:U(r,o)}]}case"item/commandExecution/terminalInteraction":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"stdin");return r?[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:U(r,`
|
|
4
4
|
${o}
|
|
5
|
-
`)}]:[]}case"item/mcpToolCall/progress":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"message").trim();return!r||!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:{mcp_output_delta:{data:o,terminal_id:r}}}]}case"turn/diff/updated":{const r=a(e,"diff");return r?[{sessionUpdate:"tool_call_update",toolCallId:a(e,"turnId")||"codex.diff",kind:"edit",title:"Diff updated",status:"completed",content:[{type:"diff",oldText:null,newText:r}],rawOutput:{diff:r}}]:[]}case"thread/tokenUsage/updated":return[{sessionUpdate:"usage_update",_meta:{codex:e}}];case"thread/name/updated":return[{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}];case"thread/status/changed":return[
|
|
5
|
+
`)}]:[]}case"item/mcpToolCall/progress":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"message").trim();return!r||!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:{mcp_output_delta:{data:o,terminal_id:r}}}]}case"turn/diff/updated":{const r=a(e,"diff");return r?[{sessionUpdate:"tool_call_update",toolCallId:a(e,"turnId")||"codex.diff",kind:"edit",title:"Diff updated",status:"completed",content:[{type:"diff",oldText:null,newText:r}],rawOutput:{diff:r}}]:[]}case"thread/tokenUsage/updated":return[{sessionUpdate:"usage_update",_meta:{codex:e}}];case"thread/name/updated":return[{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}];case"thread/status/changed":return[I({threadStatus:a(e,"status")})];case"thread/archived":return[I({archived:!0})];case"thread/unarchived":return[I({archived:!1})];case"thread/closed":return[I({closed:!0})];case"account/rateLimits/updated":return[V(e)];case"account/updated":return[I({account:d(e)??e})];case"configWarning":{const r=a(e,"summary"),o=a(e,"details");return[h("agent_message_chunk",`Config warning: ${r}${o?`
|
|
6
6
|
|
|
7
7
|
${o}`:""}
|
|
8
8
|
|
|
@@ -12,18 +12,18 @@ ${o}`:""}
|
|
|
12
12
|
|
|
13
13
|
`)];case"thread/compacted":return[h("agent_message_chunk",`*Context compacted to fit the model's context window.*
|
|
14
14
|
|
|
15
|
-
`)];case"fuzzyFileSearch/sessionUpdated":return[N(e)];case"fuzzyFileSearch/sessionCompleted":return[B(e)];case"item/autoApprovalReview/started":return[k(e,"started")];case"item/autoApprovalReview/completed":return[k(e,"completed")];case"error":return[
|
|
15
|
+
`)];case"fuzzyFileSearch/sessionUpdated":return[N(e)];case"fuzzyFileSearch/sessionCompleted":return[B(e)];case"item/autoApprovalReview/started":return[k(e,"started")];case"item/autoApprovalReview/completed":return[k(e,"completed")];case"error":return[pt(e)];default:return R(t,e),[]}}function ce(t,e,n,r={}){switch(t){case"item/agentMessage/delta":{const o=a(e,"delta"),s=a(e,"itemId"),c=s?r.agentMessagePhases?.get(s):"";if(!o||c&&c!=="commentary"&&c!=="final_answer")break;const u=c==="commentary"?"agent_progress_chunk":"agent_message_chunk",p=c==="commentary"?"progress":"message";n.pushStatus("thinking",c==="commentary"?"处理中":"生成回复中",C(o),t),n.pushUpdate({type:u,label:p,text:o,raw:{method:t,params:e,update:h(u,o)},atMs:Date.now()});break}case"item/reasoning/summaryTextDelta":case"item/reasoning/textDelta":{const o=a(e,"delta");n.pushStatus("thinking","思考中",C(o),t),n.pushUpdate({type:"agent_thought_chunk",label:"thought",...o?{text:o}:{},raw:{method:t,params:e},atMs:Date.now()});break}case"turn/plan/updated":{const o=r.planDeltas?.fromSnapshot(e)??F(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(O({update:o,method:t,params:e}));break}case"item/plan/delta":{const o=r.planDeltas?.fromDelta(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(O({update:o,method:t,params:e}));break}case"item/started":case"item/completed":{const o=y(e,"item"),s=a(o,"type"),c=E(t,o);if(!c){const _=$(s);(s==="reasoning"||s==="agentMessage")&&n.pushStatus(j(s),_,gt(o),t);break}const u=ht(t,e,o),p=ft(s,c);n.pushStatus(j(s),x(s),void 0,t),n.pushUpdate({type:t==="item/started"?"tool_call":"tool_call_update",label:p,status:i(c,["status"])||(t==="item/started"?"in_progress":"completed"),toolCallId:a(o,"id"),raw:{method:t,params:e,tool:u,update:c},atMs:Date.now()});break}case"item/commandExecution/outputDelta":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),s=i(e,["delta","data","output","text"]);if(!o&&!s)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:U(o,s)}},atMs:Date.now()});break}case"item/commandExecution/terminalInteraction":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),c=`
|
|
16
16
|
${a(e,"stdin")}
|
|
17
|
-
`;if(!o)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:U(o,
|
|
17
|
+
`;if(!o)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:U(o,c)}},atMs:Date.now()});break}case"item/mcpToolCall/progress":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),s=a(e,"message").trim();if(!o||!s)break;n.pushStatus("exploring","调用工具",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:{mcp_output_delta:{data:s,terminal_id:o}}}},atMs:Date.now()});break}case"turn/diff/updated":n.pushStatus("exploring","编辑文件中","diff",t),n.pushUpdate({type:"diff",label:"diff",text:a(e,"diff"),raw:{method:t,params:e},atMs:Date.now()});break;case"thread/tokenUsage/updated":n.pushUpdate({type:"usage_update",label:"usage",raw:{method:t,params:e},atMs:Date.now()});break;case"thread/name/updated":M(n,{method:t,params:e,type:"session_info_update",label:"session_info",update:{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}});break;case"thread/status/changed":b(n,t,e,{threadStatus:a(e,"status")});break;case"thread/archived":b(n,t,e,{archived:!0});break;case"thread/unarchived":b(n,t,e,{archived:!1});break;case"thread/closed":b(n,t,e,{closed:!0});break;case"account/rateLimits/updated":M(n,{method:t,params:e,type:"session_info_update",label:"rate_limit",update:V(e)});break;case"configWarning":{const o=a(e,"summary"),s=a(e,"details"),c=`Config warning: ${o}${s?`
|
|
18
18
|
|
|
19
19
|
${s}`:""}
|
|
20
20
|
|
|
21
|
-
`;n.pushUpdate({type:"agent_message_chunk",label:"message",text:
|
|
21
|
+
`;n.pushUpdate({type:"agent_message_chunk",label:"message",text:c,raw:{method:t,params:e,update:h("agent_message_chunk",c)},atMs:Date.now()});break}case"warning":{const o=`Warning: ${a(e,"message")}
|
|
22
22
|
|
|
23
23
|
`;n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:h("agent_message_chunk",o)},atMs:Date.now()});break}case"model/rerouted":{const o=`Model rerouted from ${a(e,"fromModel")} to ${a(e,"toModel")} (${a(e,"reason")}).
|
|
24
24
|
|
|
25
25
|
`;n.pushStatus("thinking","模型已切换",C(o),t),n.pushUpdate({type:"agent_thought_chunk",label:"thought",text:o,raw:{method:t,params:e,update:h("agent_thought_chunk",o)},atMs:Date.now()});break}case"thread/compacted":{const o=`*Context compacted to fit the model's context window.*
|
|
26
26
|
|
|
27
|
-
`;n.pushStatus("thinking","上下文已压缩",void 0,t),n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:h("agent_message_chunk",o)},atMs:Date.now()});break}case"fuzzyFileSearch/sessionUpdated":{const o=N(e);n.pushStatus("exploring",a(o,"title")||"Search",
|
|
28
|
-
`).trim()}function $(t){switch(t){case"commandExecution":return"执行命令中";case"fileChange":return"编辑文件中";case"mcpToolCall":case"dynamicToolCall":return"调用工具中";case"collabAgentToolCall":case"collabToolCall":return"处理子任务中";case"contextCompaction":return"压缩上下文中";case"webSearch":return"搜索中";case"imageGeneration":return"生成图片中";case"reasoning":return"思考中";case"agentMessage":return"生成回复中";default:return"处理中"}}function x(t){switch(t){case"commandExecution":return"执行命令";case"fileChange":return"编辑文件";case"mcpToolCall":case"dynamicToolCall":return"调用工具";case"collabAgentToolCall":case"collabToolCall":return"处理子任务";case"contextCompaction":return"压缩上下文";case"webSearch":case"fuzzyFileSearch":return"搜索";case"imageView":return"查看图片";case"imageGeneration":return"生成图片";default:return $(t)}}function
|
|
29
|
-
`)}}]}function L(t){switch(t){case"inProgress":return"In progress";case"approved":return"Approved";case"denied":return"Denied";case"aborted":return"Aborted";case"timedOut":return"Timed out";default:return t||"Unknown"}}function W(t){if(!t)return"";const e=a(t,"type");if(e==="command")return[q(a(t,"source")),a(t,"command")].filter(Boolean).join(" ");if(e==="execve"){const n=g(t,"argv")?.map(s=>f(s)).filter(Boolean)??[],r=a(t,"program"),o=n.length>0?n:[r].filter(Boolean);return[q(a(t,"source")),bt(o)].filter(Boolean).join(" ")}if(e==="applyPatch"){const n=g(t,"files")?.map(r=>f(r)).filter(Boolean)??[];return n.length===1?`apply_patch touching ${n[0]}`:`apply_patch touching ${n.length} files`}if(e==="networkAccess"){const n=a(t,"target")||a(t,"host");return n?`network access to ${n}`:"network access"}if(e==="mcpToolCall"){const n=a(t,"connectorName")||a(t,"server");return`MCP ${a(t,"toolName")} on ${n}`.trim()}return e==="requestPermissions"?a(t,"reason")||"request additional permissions":e}function q(t){return t==="shell"?"shell":t==="unifiedExec"?"exec":t}function bt(t){return t.map(Ut).join(" ")}function Ut(t){return t.length===0?"''":/^[A-Za-z0-9_/:=+.,@%-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}function xt(t){const e=w(t,"review"),n=e?L(a(e,"status")):"",r=W(w(t,"action"));return[n,r].filter(Boolean).join(" · ")||void 0}function V(t){const e=w(t,"rateLimits")??{},n=w(e,"primary"),r=w(e,"secondary");return c({sessionUpdate:"session_info_update",_meta:{rateLimits:c({planName:a(e,"planType"),limitName:a(e,"limitName"),limitId:a(e,"limitId"),fiveHour:z(n,"usedPercent")??null,sevenDay:z(r,"usedPercent")??null,fiveHourResetAt:a(n,"resetsAt")||null,sevenDayResetAt:a(r,"resetsAt")||null,raw:e})}})}function kt(t){const e=a(t,"id"),n=a(t,"cwd"),r=a(t,"command"),o=Y(t),s=o.length===1?d(o[0]):null;if(s){const l=a(s,"type");if(l==="read"){const u=a(s,"path")||a(s,"name");return c({sessionUpdate:"tool_call",toolCallId:e,status:y(a(t,"status")),kind:"read",title:`Read file '${u}'`,locations:u?[{path:u}]:void 0})}if(l==="search"){const u=a(s,"query"),p=a(s,"path");return c({sessionUpdate:"tool_call",toolCallId:e,status:y(a(t,"status")),kind:"search",title:tt(u,p)})}if(l==="listFiles"){const u=a(s,"path");return c({sessionUpdate:"tool_call",toolCallId:e,status:y(a(t,"status")),kind:"read",title:u?`List files in '${u}'`:"List files"})}}return Jt({sessionUpdate:"tool_call",toolCallId:e,status:y(a(t,"status")),kind:"execute",title:Ht(r),rawInput:c({command:r,cwd:n})},e,n)}function St(t){const e=a(t,"id"),n=i(t,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),r=z(t,"exitCode"),o={sessionUpdate:"tool_call_update",toolCallId:e,status:m(a(t,"status"),r),rawOutput:c({formatted_output:n,exit_code:r})};return Kt(t)&&(o._meta={...n?U(e,n):{},terminal_exit:{exit_code:r,signal:null,terminal_id:e}}),c(o)}function At(t){const e=a(t,"id"),n=nt(t);return c({sessionUpdate:"tool_call",toolCallId:e,title:"Editing files",kind:"edit",status:y(a(t,"status")),content:n,locations:Qt(t),rawInput:{changes:P(t)}})}function Tt(t){return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:m(a(t,"status")),content:nt(t)})}function vt(t){const e=i(t,["tool","name","server"]);return c({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:y(a(t,"status")),rawInput:d(t)})}function $t(t){return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:m(a(t,"status")),rawOutput:d(t)})}function Mt(t){const e=a(t,"server"),n=a(t,"tool");return c({...Q(t,`mcp.${e}.${n}`,X(e,n,t.arguments),Z(t.result,t.error)),_meta:{is_mcp_tool_call:!0}})}function Dt(t){const e=a(t,"server"),n=a(t,"tool");return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:m(a(t,"status")),rawInput:X(e,n,t.arguments),rawOutput:Z(t.result,t.error)})}function Pt(t){const e=a(t,"namespace"),n=a(t,"tool");return Q(t,K(e,n),{namespace:e,tool:n,arguments:t.arguments},void 0)}function zt(t){const e=a(t,"namespace"),n=a(t,"tool");return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),kind:"execute",title:K(e,n),status:m(a(t,"status")),rawInput:{namespace:e,tool:n,arguments:t.arguments},rawOutput:c({success:t.success,contentItems:t.contentItems,durationMs:t.durationMs})})}function Ot(t){const e=a(t,"tool"),n=J(t);return c({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:H(e),status:y(a(t,"status")),rawInput:{tool:e,arguments:c({...n,prompt:a(t,"prompt"),model:a(t,"model"),reasoningEffort:a(t,"reasoningEffort")})},_meta:{aca:{processKind:"subtask",action:e,collaboration:n}}})}function Ft(t){const e=a(t,"tool"),n=J(t);return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),kind:"other",title:H(e),status:m(a(t,"status")),rawOutput:c({agentsStates:t.agentsStates,...n}),_meta:{aca:{processKind:"subtask",action:e,collaboration:n}}})}function J(t){const e=new Set((g(t,"receiverThreadIds")??[]).filter(n=>typeof n=="string"&&!!n));for(const n of["receiverThreadId","newThreadId"]){const r=a(t,n);r&&e.add(r)}return c({senderThreadId:a(t,"senderThreadId"),receiverThreadIds:[...e],receiverThreadId:a(t,"receiverThreadId"),newThreadId:a(t,"newThreadId")})}function Rt(t,e){return{sessionUpdate:t==="item/started"?"tool_call":"tool_call_update",toolCallId:a(e,"id")||"codex.context_compaction",kind:"think",title:"压缩上下文",status:t==="item/started"?"in_progress":m(a(e,"status")),_meta:{aca:{processKind:"context_compaction"}}}}function K(t,e){return[t,e].filter(Boolean).join(".")||"内部工具"}function H(t){switch(t){case"spawnAgent":return"启动子任务";case"sendInput":return"发送子任务指令";case"resumeAgent":return"恢复子任务";case"wait":return"等待子任务";case"closeAgent":return"结束子任务";default:return"处理子任务"}}function jt(t){return["hookPrompt","sleep","subAgentActivity","enteredReviewMode","exitedReviewMode","plan"].includes(t)}function Q(t,e,n,r){return c({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:y(a(t,"status")),rawInput:n,rawOutput:r})}function X(t,e,n){return{server:t,tool:e,arguments:n}}function Z(t,e){if(!(t===null&&e===null)&&!(t===void 0&&e===void 0))return{result:t,error:e}}function Et(t){return c({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"search",title:et(t),status:y(a(t,"status")),rawInput:d(t)})}function Gt(t){return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),title:et(t),status:m(a(t,"status")),rawInput:d(t)})}function Nt(t){return c({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:"Image generation",status:"in_progress",rawInput:{id:a(t,"id")}})}function Bt(t){return c({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:Wt(a(t,"status")),content:qt(t),rawOutput:Vt(t)})}function Lt(t){const e=a(t,"path");return c({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"read",title:`View Image ${e}`,status:"completed",content:[{type:"content",content:{type:"resource_link",name:e,uri:e}}],locations:[{path:e}],rawInput:{path:e}})}function Wt(t){return m(t)}function qt(t){const e=d(t.result),n=i(e,["url","uri","path"]);if(n)return[{type:"content",content:{type:"resource_link",name:n,uri:n}}]}function Vt(t){const e={status:t.status,revisedPrompt:t.revisedPrompt,result:t.result};return"savedPath"in t&&(e.savedPath=t.savedPath??null),e}function Jt(t,e,n){return c({...t,content:[{type:"terminal",terminalId:e}],_meta:{terminal_info:{cwd:n,terminal_id:e}}})}function Kt(t){const e=Y(t),n=e.length===1?d(e[0]):null;return!n||a(n,"type")==="unknown"}function Y(t){return g(t,"commandActions")||g(t,"command_actions")||g(t,"actions")||[]}function y(t){switch(t){case"inProgress":case"in_progress":case"started":case"":return"in_progress";case"completed":return"completed";case"failed":case"declined":return"failed";case"cancelled":case"canceled":return"cancelled";default:return t}}function m(t,e){const n=y(t);return n==="failed"||n==="cancelled"?n:e!=null?e===0?"completed":"failed":n==="in_progress"?"completed":n}function Ht(t){const e=t.replace(/^(?:\/bin\/)?(?:bash|zsh|sh)\s+(?:-[lc]+\s+)?/,"");return e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function U(t,e){return{terminal_output_delta:{data:e,terminal_id:t}}}function tt(t,e){return t&&e?`Search for '${t}' in ${e}`:t?`Search for '${t}'`:e?`Search in '${e}'`:"Search"}function et(t){const e=d(t.action);if(!e){const r=a(t,"query");return r?`Web search: ${r}`:"Web search"}const n=a(e,"type");if(n==="search"){const r=g(e,"queries")?.map(s=>f(s)).filter(Boolean)??[],o=a(e,"query")||(r.length>0?r.join(", "):"")||a(t,"query");return o?`Web search: ${o}`:"Web search"}if(n==="openPage"){const r=a(e,"url");return r?`Open page: ${r}`:"Open page"}if(n==="findInPage"){const r=a(e,"pattern")?` for '${a(e,"pattern")}'`:"",o=a(e,"url")?` in ${a(e,"url")}`:"";return`Find in page${r}${o}`.trim()}return"Web search"}function Qt(t){const e=P(t).map(n=>d(n)).map(n=>a(n,"path")).filter(Boolean).map(n=>({path:n}));return e.length>0?e:void 0}function nt(t){const n=(g(t,"changes")??[]).map(r=>{const o=d(r);if(!o)return null;const s=f(o.path),l=o.kind&&typeof o.kind=="object"&&!Array.isArray(o.kind)?f(o.kind.type):f(o.kind),u=f(o.diff);return l==="add"?c({type:"diff",oldText:null,newText:u,path:s,_meta:{kind:"add"}}):l==="delete"?c({type:"diff",oldText:u,newText:"",path:s,_meta:{kind:"delete"}}):Xt(o,s,u,l)}).filter(Boolean);return n.length>0?n:void 0}function Xt(t,e,n,r){const o=t.kind&&typeof t.kind=="object"&&!Array.isArray(t.kind)?f(t.kind.move_path):"",s=Zt(n),l=at(e);if(l!==null){const u=D(l,s);if(u!==!1)return S(o||e,l,u,r||"update");const p=ot(s);if(p){const _=D(l,p);if(_!==!1)return S(e,_,l,r||"update")}}if(o){const u=at(o),p=ot(s);if(u!==null&&p){const _=D(u,p);if(_!==!1)return S(o,_,u,r||"update")}}return S(o||e,null,s,r||"update")}function S(t,e,n,r){return c({type:"diff",oldText:e,newText:n,path:t,_meta:{kind:r}})}function at(t){try{return ut(t,"utf8")}catch{return null}}function Zt(t){return t.replace(/\n\nMoved to: .*$/,"")}function ot(t){try{const[e]=dt(t);return e?pt(e):null}catch{return null}}function D(t,e){try{return it(t,e)}catch{return!1}}function Yt(t,e){if(t==="commandExecution")return"执行命令";if(t==="fileChange")return e.path?`编辑文件: ${ne(e.path)}`:"编辑文件";if(t==="webSearch")return e.rawInput?`搜索: ${C(e.rawInput)}`:"搜索";if(t==="mcpToolCall"||t==="dynamicToolCall"){const n=i(e.item,["tool","name","server"]);return n?`调用工具: ${n}`:"调用工具"}return $(t)}function te(t,e,n){if(e)return e;if(t==="fileChange"){const r=rt(n),o=i(n,["path","filePath","file_path","relativePath","absolutePath"])||r.path;return[i(n,["action","changeType","operation"])||r.action,o].filter(Boolean).join(" ")}return""}function rt(t){const e=g(t,"changes")??[];for(const n of e){if(!n||typeof n!="object"||Array.isArray(n))continue;const r=n,o=f(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?f(r.kind.type):f(r.kind);if(o||s)return{path:o,action:s}}return{path:"",action:""}}function P(t){return(g(t,"changes")??[]).map(n=>{if(!n||typeof n!="object"||Array.isArray(n))return null;const r=n,o=f(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?f(r.kind.type):f(r.kind);return!o&&!s?null:c({type:s||"edit",path:o})}).filter(Boolean).slice(0,50)}function i(t,e){if(!t)return"";for(const n of e){const r=f(t[n]);if(r)return r}return""}function f(t){if(typeof t=="string"&&t.trim())return t.trim();if(typeof t=="number"||typeof t=="boolean")return String(t);if(t&&typeof t=="object")try{const e=JSON.stringify(t);return e.length>2?e:""}catch{return""}return""}function g(t,e){const n=t?.[e];return Array.isArray(n)?n.slice(0,50):null}function ee(...t){return t.find(e=>e.trim())||""}function ne(t){return t.replace(/\\/g,"/").split("/").filter(Boolean).pop()||t}function c(t){for(const e of Object.keys(t)){const n=t[e];(n===void 0||n===""||Array.isArray(n)&&n.length===0)&&delete t[e]}return t}function w(t,e){if(!t||typeof t!="object"||Array.isArray(t))return null;const n=t[e];return!n||typeof n!="object"||Array.isArray(n)?null:n}function d(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function a(t,e){if(!t||typeof t!="object"||Array.isArray(t))return"";const n=t[e];return typeof n=="string"?n:""}function z(t,e){if(!t||typeof t!="object"||Array.isArray(t))return;const n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:void 0}function C(t){if(typeof t!="string")return;const e=t.replace(/\s+/g," ").trim();if(e)return e.length>120?`${e.slice(0,117)}...`:e}export{ce as codexAcpSessionUpdatesFromNotification,ie as extractAssistantTextFromTurn,ue as mapCodexNotification};
|
|
27
|
+
`;n.pushStatus("thinking","上下文已压缩",void 0,t),n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:h("agent_message_chunk",o)},atMs:Date.now()});break}case"fuzzyFileSearch/sessionUpdated":{const o=N(e);n.pushStatus("exploring",a(o,"title")||"Search",yt(e),t),n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:a(o,"title")||"Search",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"fuzzyFileSearch/sessionCompleted":{const o=B(e);n.pushUpdate({type:"tool_call_update",label:"Search",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"item/autoApprovalReview/started":{const o=k(e,"started");n.pushStatus("exploring","Guardian Review",Ut(e),t),n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:"Guardian Review",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"item/autoApprovalReview/completed":{const o=k(e,"completed");n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:"Guardian Review",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"account/updated":b(n,t,e,{account:d(e)??e});break;case"turn/started":n.pushStatus("thinking","思考中",void 0,t);break;case"turn/completed":n.pushStatus("completed","已完成",void 0,t);break;case"error":n.pushStatus("failed","执行失败",C(JSON.stringify(e)),t),n.pushUpdate({type:"error",label:"error",text:C(JSON.stringify(e)),raw:{method:t,params:e},atMs:Date.now()});break;default:R(t,e);break}}function R(t,e){if(process.env.ACA_CODEX_PROTOCOL_DEBUG!=="1")return;const n=d(e);console.debug("[codex] unhandled notification",{method:t,keys:n?Object.keys(n).slice(0,20):[],itemType:a(y(n,"item"),"type")||void 0})}function le(t){return(Array.isArray(t?.items)?t.items:[]).map(n=>a(n,"type")!=="agentMessage"?"":a(n,"text")).filter(Boolean).join(`
|
|
28
|
+
`).trim()}function $(t){switch(t){case"commandExecution":return"执行命令中";case"fileChange":return"编辑文件中";case"mcpToolCall":case"dynamicToolCall":return"调用工具中";case"collabAgentToolCall":case"collabToolCall":return"处理子任务中";case"contextCompaction":return"压缩上下文中";case"webSearch":return"搜索中";case"imageGeneration":return"生成图片中";case"reasoning":return"思考中";case"agentMessage":return"生成回复中";default:return"处理中"}}function x(t){switch(t){case"commandExecution":return"执行命令";case"fileChange":return"编辑文件";case"mcpToolCall":case"dynamicToolCall":return"调用工具";case"collabAgentToolCall":case"collabToolCall":return"处理子任务";case"contextCompaction":return"压缩上下文";case"webSearch":case"fuzzyFileSearch":return"搜索";case"imageView":return"查看图片";case"imageGeneration":return"生成图片";default:return $(t)}}function ft(t,e){const n=i(e,["kind"]);if(n==="read")return i(e,["title"])||"读取文件";if(n==="search")return i(e,["title"])||"搜索";if(n==="edit")return"编辑文件";if(n==="execute"){const r=d(e.rawInput);return a(r,"command")?"执行命令":i(e,["title"])||x(t)}return n==="think"?"思考中":n==="other"&&i(e,["title"])||x(t)}function j(t){return t==="imageGeneration"?"image_generation":t==="reasoning"||t==="agentMessage"||t==="plan"?"thinking":"exploring"}function gt(t){if(t)for(const e of["command","path","tool","server","query","text"]){const n=a(t,e);if(n)return C(n)}}function ht(t,e,n){const r=a(n,"type"),o=a(n,"id")||a(e,"itemId"),s=i(n,["rawInput","raw_input","command","query","path","text","input"]),c=r==="commandExecution"?i(n,["command","rawInput","raw_input"]):"",u=at(n),p=i(n,["path","filePath","file_path","relativePath","absolutePath"])||u.path,_=i(n,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),A=g(n,"commandActions")||g(n,"command_actions")||g(n,"actions")||P(n),ot=Xt(r,_,n),rt=Qt(r,{command:c,path:p,rawInput:s,item:n}),st=C(Zt(c,p,s,_));return l({id:o,type:r,method:t,displayName:rt,rawInput:s,raw_input:s,command:c,path:p,action:i(n,["action","changeType","operation"])||u.action,commandActions:A,command_actions:A.length>0?A:void 0,aggregatedOutput:_,aggregated_output:_,formatted_output:ot,summary:st})}function E(t,e){if(!e)return null;switch(a(e,"type")){case"commandExecution":return t==="item/started"?xt(e):kt(e);case"fileChange":return t==="item/started"?St(e):At(e);case"mcpToolCall":return t==="item/started"?$t(e):Mt(e);case"dynamicToolCall":return t==="item/started"?Dt(e):Pt(e);case"collabAgentToolCall":case"collabToolCall":case"subAgentActivity":return dt(t,e);case"contextCompaction":return zt(t,e);case"webSearch":return t==="item/started"?Ft(e):Rt(e);case"imageView":return Gt(e);case"imageGeneration":return t==="item/started"?jt(e):Et(e);default:return null}}function M(t,e){t.pushUpdate({type:e.type,label:e.label,raw:{method:e.method,params:e.params,update:e.update},atMs:Date.now()})}function b(t,e,n,r){M(t,{method:e,params:n,type:"session_info_update",label:"session_info",update:{sessionUpdate:"session_info_update",_meta:{codex:r}}})}function I(t){return{sessionUpdate:"session_info_update",_meta:{codex:t}}}function h(t,e){return{sessionUpdate:t,content:{type:"text",text:e}}}function G(t){return`fuzzyFileSearch.${t}`}function N(t){const e=a(t,"sessionId"),n=G(e),r=!v.has(n);v.add(n);const o=a(t,"query"),s=Z(o,""),c=_t(t);return l(r?{sessionUpdate:"tool_call",toolCallId:n,kind:"search",title:s,status:"in_progress",locations:c,rawInput:{query:o}}:{sessionUpdate:"tool_call_update",toolCallId:n,title:s,status:"in_progress",locations:c})}function B(t){const e=a(t,"sessionId"),n=G(e);return v.delete(n),{sessionUpdate:"tool_call_update",toolCallId:n,status:"completed"}}function _t(t){const n=(g(d(t),"files")??[]).map(r=>{const o=d(r);if(!o)return"";const s=a(o,"path"),c=a(o,"root");return s?s.startsWith("/")||!c?s:`${c.replace(/\/+$/,"")}/${s.replace(/^\/+/,"")}`:""}).filter(Boolean).map(r=>({path:r}));return n.length>0?n:void 0}function yt(t){const e=a(t,"query"),r=(g(d(t),"files")??[]).length;if(e&&r)return`${e} · ${r} files`;if(e)return e;if(r)return`${r} files`}function mt(t){return`guardian_assessment:${t}`}function k(t,e){const n=a(t,"reviewId"),r=mt(n),o=e==="started"&&!T.has(n);e==="started"&&T.add(n),e==="completed"&&T.delete(n);const s=y(t,"review")??{},c={sessionUpdate:o?"tool_call":"tool_call_update",toolCallId:r,status:wt(a(s,"status")),content:Ct(s,y(t,"action")),...o?{kind:"think",title:"Guardian Review",rawInput:t}:{rawOutput:t}};return l(c)}function wt(t){switch(t){case"inProgress":return"in_progress";case"approved":return"completed";case"denied":case"aborted":case"timedOut":return"failed";default:return t||"in_progress"}}function Ct(t,e){const n=[`Status: ${L(a(t,"status"))}`],r=W(e);r&&n.push(`Action: ${r}`);const o=a(t,"riskLevel");o&&n.push(`Risk: ${o}`);const s=a(t,"userAuthorization");s&&n.push(`Authorization: ${s}`);const c=a(t,"rationale").trim();return c&&n.push(`Rationale: ${c}`),[{type:"content",content:{type:"text",text:n.join(`
|
|
29
|
+
`)}}]}function L(t){switch(t){case"inProgress":return"In progress";case"approved":return"Approved";case"denied":return"Denied";case"aborted":return"Aborted";case"timedOut":return"Timed out";default:return t||"Unknown"}}function W(t){if(!t)return"";const e=a(t,"type");if(e==="command")return[q(a(t,"source")),a(t,"command")].filter(Boolean).join(" ");if(e==="execve"){const n=g(t,"argv")?.map(s=>f(s)).filter(Boolean)??[],r=a(t,"program"),o=n.length>0?n:[r].filter(Boolean);return[q(a(t,"source")),bt(o)].filter(Boolean).join(" ")}if(e==="applyPatch"){const n=g(t,"files")?.map(r=>f(r)).filter(Boolean)??[];return n.length===1?`apply_patch touching ${n[0]}`:`apply_patch touching ${n.length} files`}if(e==="networkAccess"){const n=a(t,"target")||a(t,"host");return n?`network access to ${n}`:"network access"}if(e==="mcpToolCall"){const n=a(t,"connectorName")||a(t,"server");return`MCP ${a(t,"toolName")} on ${n}`.trim()}return e==="requestPermissions"?a(t,"reason")||"request additional permissions":e}function q(t){return t==="shell"?"shell":t==="unifiedExec"?"exec":t}function bt(t){return t.map(It).join(" ")}function It(t){return t.length===0?"''":/^[A-Za-z0-9_/:=+.,@%-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}function Ut(t){const e=y(t,"review"),n=e?L(a(e,"status")):"",r=W(y(t,"action"));return[n,r].filter(Boolean).join(" · ")||void 0}function V(t){const e=y(t,"rateLimits")??{},n=y(e,"primary"),r=y(e,"secondary");return l({sessionUpdate:"session_info_update",_meta:{rateLimits:l({planName:a(e,"planType"),limitName:a(e,"limitName"),limitId:a(e,"limitId"),fiveHour:z(n,"usedPercent")??null,sevenDay:z(r,"usedPercent")??null,fiveHourResetAt:a(n,"resetsAt")||null,sevenDayResetAt:a(r,"resetsAt")||null,raw:e})}})}function xt(t){const e=a(t,"id"),n=a(t,"cwd"),r=a(t,"command"),o=X(t),s=o.length===1?d(o[0]):null;if(s){const c=a(s,"type");if(c==="read"){const u=a(s,"path")||a(s,"name");return l({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"read",title:`Read file '${u}'`,locations:u?[{path:u}]:void 0})}if(c==="search"){const u=a(s,"query"),p=a(s,"path");return l({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"search",title:Z(u,p)})}if(c==="listFiles"){const u=a(s,"path");return l({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"read",title:u?`List files in '${u}'`:"List files"})}}return Wt({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"execute",title:Vt(r),rawInput:l({command:r,cwd:n})},e,n)}function kt(t){const e=a(t,"id"),n=i(t,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),r=z(t,"exitCode"),o={sessionUpdate:"tool_call_update",toolCallId:e,status:w(a(t,"status"),r),rawOutput:l({formatted_output:n,exit_code:r})};return qt(t)&&(o._meta={...n?U(e,n):{},terminal_exit:{exit_code:r,signal:null,terminal_id:e}}),l(o)}function St(t){const e=a(t,"id"),n=tt(t);return l({sessionUpdate:"tool_call",toolCallId:e,title:"Editing files",kind:"edit",status:m(a(t,"status")),content:n,locations:Jt(t),rawInput:{changes:P(t)}})}function At(t){return l({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:w(a(t,"status")),content:tt(t)})}function vt(t){const e=i(t,["tool","name","server"]);return l({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:m(a(t,"status")),rawInput:d(t)})}function Tt(t){return l({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:w(a(t,"status")),rawOutput:d(t)})}function $t(t){const e=a(t,"server"),n=a(t,"tool");return l({...H(t,`mcp.${e}.${n}`,K(e,n,t.arguments),Q(t.result,t.error)),_meta:{is_mcp_tool_call:!0}})}function Mt(t){const e=a(t,"server"),n=a(t,"tool");return l({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:w(a(t,"status")),rawInput:K(e,n,t.arguments),rawOutput:Q(t.result,t.error)})}function Dt(t){const e=a(t,"namespace"),n=a(t,"tool");return H(t,J(e,n),{namespace:e,tool:n,arguments:t.arguments},void 0)}function Pt(t){const e=a(t,"namespace"),n=a(t,"tool");return l({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),kind:"execute",title:J(e,n),status:w(a(t,"status")),rawInput:{namespace:e,tool:n,arguments:t.arguments},rawOutput:l({success:t.success,contentItems:t.contentItems,durationMs:t.durationMs})})}function zt(t,e){return{sessionUpdate:t==="item/started"?"tool_call":"tool_call_update",toolCallId:a(e,"id")||"codex.context_compaction",kind:"think",title:"压缩上下文",status:t==="item/started"?"in_progress":w(a(e,"status")),_meta:{aca:{processKind:"context_compaction"}}}}function J(t,e){return[t,e].filter(Boolean).join(".")||"内部工具"}function Ot(t){return["hookPrompt","sleep","enteredReviewMode","exitedReviewMode","plan"].includes(t)}function H(t,e,n,r){return l({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:m(a(t,"status")),rawInput:n,rawOutput:r})}function K(t,e,n){return{server:t,tool:e,arguments:n}}function Q(t,e){if(!(t===null&&e===null)&&!(t===void 0&&e===void 0))return{result:t,error:e}}function Ft(t){return l({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"search",title:Y(t),status:m(a(t,"status")),rawInput:d(t)})}function Rt(t){return l({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),title:Y(t),status:w(a(t,"status")),rawInput:d(t)})}function jt(t){return l({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:"Image generation",status:"in_progress",rawInput:{id:a(t,"id")}})}function Et(t){return l({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:Nt(a(t,"status")),content:Bt(t),rawOutput:Lt(t)})}function Gt(t){const e=a(t,"path");return l({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"read",title:`View Image ${e}`,status:"completed",content:[{type:"content",content:{type:"resource_link",name:e,uri:e}}],locations:[{path:e}],rawInput:{path:e}})}function Nt(t){return w(t)}function Bt(t){const e=d(t.result),n=i(e,["url","uri","path"]);if(n)return[{type:"content",content:{type:"resource_link",name:n,uri:n}}]}function Lt(t){const e={status:t.status,revisedPrompt:t.revisedPrompt,result:t.result};return"savedPath"in t&&(e.savedPath=t.savedPath??null),e}function Wt(t,e,n){return l({...t,content:[{type:"terminal",terminalId:e}],_meta:{terminal_info:{cwd:n,terminal_id:e}}})}function qt(t){const e=X(t),n=e.length===1?d(e[0]):null;return!n||a(n,"type")==="unknown"}function X(t){return g(t,"commandActions")||g(t,"command_actions")||g(t,"actions")||[]}function m(t){switch(t){case"inProgress":case"in_progress":case"started":case"":return"in_progress";case"completed":return"completed";case"failed":case"declined":return"failed";case"cancelled":case"canceled":return"cancelled";default:return t}}function w(t,e){const n=m(t);return n==="failed"||n==="cancelled"?n:e!=null?e===0?"completed":"failed":n==="in_progress"?"completed":n}function Vt(t){const e=t.replace(/^(?:\/bin\/)?(?:bash|zsh|sh)\s+(?:-[lc]+\s+)?/,"");return e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function U(t,e){return{terminal_output_delta:{data:e,terminal_id:t}}}function Z(t,e){return t&&e?`Search for '${t}' in ${e}`:t?`Search for '${t}'`:e?`Search in '${e}'`:"Search"}function Y(t){const e=d(t.action);if(!e){const r=a(t,"query");return r?`Web search: ${r}`:"Web search"}const n=a(e,"type");if(n==="search"){const r=g(e,"queries")?.map(s=>f(s)).filter(Boolean)??[],o=a(e,"query")||(r.length>0?r.join(", "):"")||a(t,"query");return o?`Web search: ${o}`:"Web search"}if(n==="openPage"){const r=a(e,"url");return r?`Open page: ${r}`:"Open page"}if(n==="findInPage"){const r=a(e,"pattern")?` for '${a(e,"pattern")}'`:"",o=a(e,"url")?` in ${a(e,"url")}`:"";return`Find in page${r}${o}`.trim()}return"Web search"}function Jt(t){const e=P(t).map(n=>d(n)).map(n=>a(n,"path")).filter(Boolean).map(n=>({path:n}));return e.length>0?e:void 0}function tt(t){const n=(g(t,"changes")??[]).map(r=>{const o=d(r);if(!o)return null;const s=f(o.path),c=o.kind&&typeof o.kind=="object"&&!Array.isArray(o.kind)?f(o.kind.type):f(o.kind),u=f(o.diff);return c==="add"?l({type:"diff",oldText:null,newText:u,path:s,_meta:{kind:"add"}}):c==="delete"?l({type:"diff",oldText:u,newText:"",path:s,_meta:{kind:"delete"}}):Ht(o,s,u,c)}).filter(Boolean);return n.length>0?n:void 0}function Ht(t,e,n,r){const o=t.kind&&typeof t.kind=="object"&&!Array.isArray(t.kind)?f(t.kind.move_path):"",s=Kt(n),c=et(e);if(c!==null){const u=D(c,s);if(u!==!1)return S(o||e,c,u,r||"update");const p=nt(s);if(p){const _=D(c,p);if(_!==!1)return S(e,_,c,r||"update")}}if(o){const u=et(o),p=nt(s);if(u!==null&&p){const _=D(u,p);if(_!==!1)return S(o,_,u,r||"update")}}return S(o||e,null,s,r||"update")}function S(t,e,n,r){return l({type:"diff",oldText:e,newText:n,path:t,_meta:{kind:r}})}function et(t){try{return ct(t,"utf8")}catch{return null}}function Kt(t){return t.replace(/\n\nMoved to: .*$/,"")}function nt(t){try{const[e]=ut(t);return e?it(e):null}catch{return null}}function D(t,e){try{return lt(t,e)}catch{return!1}}function Qt(t,e){if(t==="commandExecution")return"执行命令";if(t==="fileChange")return e.path?`编辑文件: ${Yt(e.path)}`:"编辑文件";if(t==="webSearch")return e.rawInput?`搜索: ${C(e.rawInput)}`:"搜索";if(t==="mcpToolCall"||t==="dynamicToolCall"){const n=i(e.item,["tool","name","server"]);return n?`调用工具: ${n}`:"调用工具"}return $(t)}function Xt(t,e,n){if(e)return e;if(t==="fileChange"){const r=at(n),o=i(n,["path","filePath","file_path","relativePath","absolutePath"])||r.path;return[i(n,["action","changeType","operation"])||r.action,o].filter(Boolean).join(" ")}return""}function at(t){const e=g(t,"changes")??[];for(const n of e){if(!n||typeof n!="object"||Array.isArray(n))continue;const r=n,o=f(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?f(r.kind.type):f(r.kind);if(o||s)return{path:o,action:s}}return{path:"",action:""}}function P(t){return(g(t,"changes")??[]).map(n=>{if(!n||typeof n!="object"||Array.isArray(n))return null;const r=n,o=f(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?f(r.kind.type):f(r.kind);return!o&&!s?null:l({type:s||"edit",path:o})}).filter(Boolean).slice(0,50)}function i(t,e){if(!t)return"";for(const n of e){const r=f(t[n]);if(r)return r}return""}function f(t){if(typeof t=="string"&&t.trim())return t.trim();if(typeof t=="number"||typeof t=="boolean")return String(t);if(t&&typeof t=="object")try{const e=JSON.stringify(t);return e.length>2?e:""}catch{return""}return""}function g(t,e){const n=t?.[e];return Array.isArray(n)?n.slice(0,50):null}function Zt(...t){return t.find(e=>e.trim())||""}function Yt(t){return t.replace(/\\/g,"/").split("/").filter(Boolean).pop()||t}function l(t){for(const e of Object.keys(t)){const n=t[e];(n===void 0||n===""||Array.isArray(n)&&n.length===0)&&delete t[e]}return t}function y(t,e){if(!t||typeof t!="object"||Array.isArray(t))return null;const n=t[e];return!n||typeof n!="object"||Array.isArray(n)?null:n}function d(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function a(t,e){if(!t||typeof t!="object"||Array.isArray(t))return"";const n=t[e];return typeof n=="string"?n:""}function z(t,e){if(!t||typeof t!="object"||Array.isArray(t))return;const n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:void 0}function C(t){if(typeof t!="string")return;const e=t.replace(/\s+/g," ").trim();if(e)return e.length>120?`${e.slice(0,117)}...`:e}export{se as codexAcpSessionUpdatesFromNotification,le as extractAssistantTextFromTurn,ce as mapCodexNotification};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{JsonLineRpcClient as
|
|
2
|
-
`);this.lineBuffer=t.pop()??"";for(const s of t){const i=s.trim();if(!i)continue;let r;try{r=JSON.parse(i)}catch{continue}this.handleMessage(r)}}async handleMessage(e){if("id"in e&&("result"in e||"error"in e)&&typeof e.method!="string"){this.handleParentResponse(e);return}const t=typeof e.method=="string"?e.method:"",s=e.id;if(t){if(s===void 0){await this.handleNotification(t,u(e.params));return}try{const i=await this.handleRequest(t,u(e.params));this.write({jsonrpc:"2.0",id:s,result:i})}catch(i){this.write({jsonrpc:"2.0",id:s,error:{code:-32603,message:i instanceof Error?i.message:String(i)}})}}}async handleNotification(e,t){e==="session/cancel"&&await this.cancel(t)}async handleRequest(e,t){switch(e){case"initialize":return this.initializeResponse();case"aca/runtime_config":return this.applyRuntimeConfig(t);case"session/new":return this.newSession(t);case"session/resume":case"session/load":return this.resumeSession(t);case"session/fork":return this.forkSession(t);case"session/prompt":return this.prompt(t);case"session/compact":return this.manualCompact(t);case"session/cancel":return await this.cancel(t),{};case"session/close":return await this.closeSession(t),{};case"session/set_config_option":return this.setConfigOption(t);case"session/set_mode":return this.setMode(t);case"fs/read_text_file":case"fs/write_text_file":case"terminal/create":case"terminal/output":case"terminal/wait_for_exit":case"terminal/kill":case"terminal/release":return{};default:throw new Error(`Unsupported ACP method: ${e}`)}}initializeResponse(){return{protocolVersion:1,agentCapabilities:{loadSession:!0,sessionCapabilities:{resume:!0,close:!0}}}}applyRuntimeConfig(e){if(this.started)throw new Error("Codex runtime config must be applied before app-server starts");const t=u(e.codexProvider);if(Object.keys(t).length===0)return this.managedProvider=null,{configured:!1};const s=a(t,"baseUrl"),i=a(t,"apiKey"),r=Number(t.revision||0);if(!s||!i||!Number.isSafeInteger(r)||r<1)throw new Error("Invalid Codex managed provider runtime config");return this.managedProvider={baseUrl:s,apiKey:i,revision:r},{configured:!0,revision:r}}async newSession(e){const t=a(e,"cwd")||process.cwd();this.applyInitialConfig(e),await this.ensureCodex(t);const s=await this.requireRpc().request("thread/start",{cwd:t,approvalsReviewer:"user",...this.codexConfig(),ephemeral:!1,threadSource:"aca-codex-acp"},6e4),i=C(s);if(!i)throw new Error("Codex thread/start did not return thread id");return this.currentSessionId=i,this.currentCwd=t,this.resetSubtaskState(),this.captureThreadMetadata(s),this.sessionResponse(i)}async resumeSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const i=await this.requireRpc().request("thread/resume",{threadId:t,cwd:s,approvalsReviewer:"user",...this.codexConfig()},6e4);return this.currentSessionId=C(i)||t,this.currentCwd=s,this.resetSubtaskState(i),await this.subscribeKnownSubtasks(),this.captureThreadMetadata(i),this.sessionResponse(this.currentSessionId)}async forkSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const i=await this.requireRpc().request("thread/fork",{threadId:t,cwd:s,approvalsReviewer:"user",ephemeral:!1,threadSource:"aca-codex-acp-fork",...this.codexConfig()},12e4),r=C(i);if(!r)throw new Error("Codex thread/fork did not return thread id");return this.currentSessionId=r,this.currentCwd=s,this.resetSubtaskState(i),this.captureThreadMetadata(i),this.sessionResponse(r)}async prompt(e){const t=a(e,"sessionId")||this.currentSessionId;let s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");const i=Array.isArray(e.prompt)?e.prompt:[],r=this.requireRpc();this.currentSessionId&&this.currentSessionId!==s&&this.resetSubtaskState(),this.currentSessionId=s;const o=await this.maintainContext("before",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{allowRollover:!0});Q(o),s=this.currentSessionId||s,this.promptActive=!0,this.currentTurnId=null,this.currentPromptText=L(i),this.currentAssistantText="",this.currentAffectedFiles.clear(),this.connectionRecovery.reset(),this.agentMessagePhases.clear(),this.planDeltas.reset(),this.pendingSubtaskNotifications=[];let c;try{c=await r.request("turn/start",{threadId:s,clientUserMessageId:`aca-acp-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:K(i),cwd:this.currentCwd,...G(this.config)},q());const d=String(c?.turn?.id??"");this.currentTurnId=d||null;const l=d?await this.waitForTurnCompleted(d,q()):c?.turn;this.threadTurnCount+=1,this.previousUserText=this.currentPromptText,this.previousAssistantText=this.currentAssistantText,this.previousAffectedFiles.clear();for(const f of this.currentAffectedFiles)this.previousAffectedFiles.add(f);const p=await this.maintainContext("after",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{allowRollover:!0});return{stopReason:"end_turn",sessionId:this.currentSessionId,turn:l,_meta:{acaContextUsage:A(p)??H(this.latestTokenUsage),acaContextMaintenance:p}}}catch(d){const l=this.connectionRecovery.fail(d);throw l&&this.notifySessionUpdate(l),d}finally{this.promptActive=!1,this.currentTurnId=null,this.pendingSubtaskNotifications=[]}}resetSubtaskState(e){this.subtaskRouter.reset(),this.subtaskAgentMessagePhases.clear(),this.subtaskPlanDeltas.clear(),this.subscribedSubtaskThreadIds.clear(),this.pendingSubtaskSubscriptions.clear(),this.pendingSubtaskNotifications=[],e!==void 0&&this.subtaskRouter.restoreFromSessionSnapshot(e,this.currentSessionId)}async subscribeKnownSubtasks(){const e=this.subtaskRouter.routesForSubscription().map(t=>this.subscribeSubtask(t.sourceThreadId));await Promise.allSettled(e)}subscribeSubtask(e){if(!e||e===this.currentSessionId||this.subscribedSubtaskThreadIds.has(e))return Promise.resolve();const t=this.pendingSubtaskSubscriptions.get(e);if(t)return t;const s=this.requireRpc().request("thread/resume",{threadId:e,approvalsReviewer:"user",excludeTurns:!0},6e4).then(()=>{this.subscribedSubtaskThreadIds.add(e)}).catch(()=>{}).finally(()=>{this.pendingSubtaskSubscriptions.delete(e)});return this.pendingSubtaskSubscriptions.set(e,s),s}async cancel(e){const t=a(e,"sessionId")||this.currentSessionId;if(!(!t||!this.rpc)&&(await this.rpc.request("turn/interrupt",{threadId:t}).catch(()=>{}),this.currentTurnId)){const s=this.pendingTurnCompletions.get(this.currentTurnId);s&&(this.pendingTurnCompletions.delete(this.currentTurnId),clearTimeout(s.timer),s.reject(new Error("Codex prompt cancelled")))}}async manualCompact(e){const t=a(e,"sessionId")||this.currentSessionId,s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");if(this.promptActive||this.maintenanceActive)throw new Error("Codex session is busy");this.currentSessionId=s;const i=k(),r=await this.maintainContext("manual",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{force:!0,allowRollover:e.allowRollover===!0,compactTimeoutMs:V(e,i.compactTimeoutMs)}),o=String(r.action||"");if(o==="compact_failed"||o==="rollover_failed"){const c=String(r.compactError||"Codex 上下文压缩未完成");throw new Error(`Codex 上下文压缩失败:${c}`)}return{sessionId:this.currentSessionId,maintenance:r,contextUsage:A(r)}}async closeSession(e){await this.shutdown()}async ensureCodex(e){if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;if(this.codexStartupPromise){await this.codexStartupPromise;return}const t=(async()=>{if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;const s=U(e,this.managedProvider),i=new M(s.child,{peerName:"Codex app-server",onNotification:(r,o)=>this.handleCodexNotification(r,o),onRequest:async(r,o)=>this.handleCodexRequest(r,o)});this.started=s,this.rpc=i,this.initialized=!1,await i.request("initialize",{clientInfo:{name:"aca-codex-acp",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},6e4),this.initialized=!0})();this.codexStartupPromise=t;try{await t}catch(s){throw this.rpc&&this.started&&!this.initialized&&await x(this.started.child,1e3),this.rpc=null,this.started=null,s}finally{this.codexStartupPromise===t&&(this.codexStartupPromise=null)}}handleCodexNotification(e,t){const s=R(t);if(this.maintenanceActive&&(!s.threadId||s.threadId===this.currentSessionId)){this.captureContextNotification(e,t);return}if(!B(t,this.currentSessionId,this.currentTurnId)){if(!this.promptActive||!s.threadId||s.threadId===this.currentSessionId)return;const c=this.subtaskRouter.routeFor(s.threadId);if(!c){this.bufferPendingSubtaskNotification(e,t,s.threadId);return}this.handleSubtaskNotification(e,t,c),this.flushPendingSubtaskNotifications();return}const i=this.subtaskRouter.observe(t,this.currentSessionId);if(i>0&&this.subscribeKnownSubtasks(),this.captureContextNotification(e,t),this.maintenanceActive||!this.promptActive&&e!=="turn/completed")return;this.rpc?.refreshPendingRequestTimeout("turn/start"),this.captureAgentMessagePhase(e,t);const r=this.connectionRecovery.beforeNotification(e,t);e==="turn/completed"&&this.resolveTurnCompleted(t);const o=e==="rawResponse/completed"?X(t):T(e,t,{agentMessagePhases:this.agentMessagePhases,planDeltas:this.planDeltas});for(const c of[...r,...o])this.captureUpdateEvidence(c),this.notifySessionUpdate(c);i>0&&this.flushPendingSubtaskNotifications()}handleSubtaskNotification(e,t,s){if(!this.promptActive)return;this.rpc?.refreshPendingRequestTimeout("turn/start");const i=this.subtaskAgentMessagePhases.get(s.sourceThreadId)??new Map;this.subtaskAgentMessagePhases.set(s.sourceThreadId,i);const r=this.subtaskPlanDeltas.get(s.sourceThreadId)??new I;this.subtaskPlanDeltas.set(s.sourceThreadId,r),this.captureAgentMessagePhase(e,t,i),this.subtaskRouter.observe(t,this.currentSessionId)>0&&this.subscribeKnownSubtasks();const c=T(e,t,{agentMessagePhases:i,planDeltas:r}),d=R(t).turnId;for(const l of c){if(!Y(l))continue;const p=Z(l,s,d);w(p,this.currentAffectedFiles),this.notifySessionUpdate(p)}}bufferPendingSubtaskNotification(e,t,s){this.pendingSubtaskNotifications.push({method:e,params:t,threadId:s}),this.pendingSubtaskNotifications.length>200&&this.pendingSubtaskNotifications.shift()}flushPendingSubtaskNotifications(){if(this.pendingSubtaskNotifications.length===0)return;let e=!0;for(;e&&this.pendingSubtaskNotifications.length>0;){e=!1;const t=[];for(const s of this.pendingSubtaskNotifications){const i=this.subtaskRouter.routeFor(s.threadId);if(!i){t.push(s);continue}e=!0,this.handleSubtaskNotification(s.method,s.params,i)}this.pendingSubtaskNotifications=t}}notifySessionUpdate(e){this.notify("session/update",{sessionId:this.currentSessionId,update:e})}async handleCodexRequest(e,t){if(E(e))return N(e,t,async s=>{const i=await this.requestParent("session/request_permission",{sessionId:this.currentSessionId,request:{...s,params:t,method:e}}),r=u(i),o=u(r.outcome);return o.outcome==="selected"&&typeof o.optionId=="string"?{outcome:{outcome:"selected",optionId:o.optionId}}:{outcome:{outcome:"cancelled"}}});if(ee(e)){const s=await this.requestParent("elicitation/create",{sessionId:this.currentSessionId,request:{...u(t),method:e}}),i=u(s),r=u(i.outcome);return r.outcome==="submitted"?{outcome:{outcome:"submitted",value:typeof r.value=="string"?r.value:""}}:{outcome:{outcome:"cancelled"}}}return{}}captureAgentMessagePhase(e,t,s=this.agentMessagePhases){if(e!=="item/started"&&e!=="item/completed")return;const i=m(t,"item");if(a(i,"type")!=="agentMessage")return;const r=a(i,"id");r&&s.set(r,a(i,"phase"))}waitForTurnCompleted(e,t){const s=this.completedTurns.get(e);return s?Promise.resolve(s):new Promise((i,r)=>{const o=setTimeout(()=>{this.pendingTurnCompletions.delete(e),r(new Error("Codex app-server request timed out while waiting for turn/completed"))},t);o.unref(),this.pendingTurnCompletions.set(e,{resolve:i,reject:r,timer:o})})}resolveTurnCompleted(e){const t=m(e,"turn"),s=a(t,"id");if(!s)return;this.completedTurns.set(s,t);const i=this.pendingTurnCompletions.get(s);if(i){if(this.pendingTurnCompletions.delete(s),clearTimeout(i.timer),a(t,"status")==="failed"){i.reject(new Error(`Codex turn failed: ${JSON.stringify(t.error??{})}`));return}i.resolve(t)}}async shutdown(){return this.shutdownPromise?this.shutdownPromise:(this.shutdownPromise=this.performShutdown(),this.shutdownPromise)}async performShutdown(){this.pendingCompaction&&(clearTimeout(this.pendingCompaction.timer),this.pendingCompaction.reject(new Error("Codex ACP adapter closed")),this.pendingCompaction=null);for(const t of this.pendingParentRequests.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingParentRequests.clear();for(const t of this.pendingTurnCompletions.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingTurnCompletions.clear();const e=this.started?.child;!e||e.exitCode!==null||e.signalCode!==null||(e.stdin.end(),!await x(e,2e3)&&(e.kill("SIGTERM"),!await x(e,1e3)&&(e.kill("SIGKILL"),await x(e,1e3))))}sessionResponse(e){return{sessionId:e,modes:{currentModeId:"workspace-write",availableModes:[{id:"read-only",name:"Read Only"},{id:"workspace-write",name:"Workspace Write"},{id:"danger-full-access",name:"Full Access"}]},configOptions:[{id:"model",category:"model",type:"string"},{id:"approvalPolicy",category:"approval",type:"string"},{id:"sandbox",category:"mode",type:"string"}]}}requireRpc(){if(!this.rpc)throw new Error("Codex app-server is not started");return this.rpc}notify(e,t){this.write({jsonrpc:"2.0",method:e,params:t})}requestParent(e,t,s=600*1e3){const i=this.nextParentRequestId++;return new Promise((r,o)=>{const c=setTimeout(()=>{this.pendingParentRequests.delete(i),o(new Error(`ACP client request timed out: ${e}`))},s);c.unref(),this.pendingParentRequests.set(i,{resolve:r,reject:o,timer:c}),this.write({jsonrpc:"2.0",id:i,method:e,params:t})})}handleParentResponse(e){const t=Number(e.id),s=this.pendingParentRequests.get(t);if(s){if(this.pendingParentRequests.delete(t),clearTimeout(s.timer),"error"in e){const i=u(e.error);s.reject(new Error(a(i,"message")||"ACP client request failed"));return}s.resolve(e.result)}}setConfigOption(e){const t=a(e,"configId"),s=e.value;if(!t)throw new Error("configId is required");if(typeof s!="string"&&typeof s!="boolean")throw new Error("config value must be string or boolean");return this.config[t]=s,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"config_option_update",configId:t,value:s}}),{}}setMode(e){const t=a(e,"modeId");if(!t)throw new Error("modeId is required");return this.config.sandbox=t,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"current_mode_update",modeId:t}}),{}}applyInitialConfig(e){const t=m(e,"config");for(const[s,i]of Object.entries(t))(typeof i=="string"||typeof i=="boolean")&&(this.config[s]=i)}codexConfig(){return{...typeof this.config.model=="string"&&this.config.model?{model:this.config.model}:{},approvalPolicy:typeof this.config.approvalPolicy=="string"?this.config.approvalPolicy:"on-request",sandbox:typeof this.config.sandbox=="string"?this.config.sandbox:"workspace-write"}}captureContextNotification(e,t){if(e==="thread/tokenUsage/updated"&&(this.latestTokenUsage=$(t)??this.latestTokenUsage),e==="thread/compacted"&&this.pendingCompaction&&this.resolveCompaction(),e==="item/completed"){const s=m(t,"item"),i=a(u(t),"threadId");a(s,"type")==="contextCompaction"&&(!i||i===this.currentSessionId)&&this.resolveCompaction(),a(s,"type")==="agentMessage"&&a(s,"phase")==="final_answer"&&(this.currentAssistantText=g(s)||this.currentAssistantText)}}resolveCompaction(){if(!this.pendingCompaction)return;const e=this.pendingCompaction;this.pendingCompaction=null,clearTimeout(e.timer),e.resolve()}captureUpdateEvidence(e){String(e.sessionUpdate||"")==="agent_message_chunk"&&(this.currentAssistantText+=g(e.content)),w(e,this.currentAffectedFiles)}captureThreadMetadata(e){const t=m(e,"thread");this.currentRolloutPath=a(t,"path")||null,this.threadTurnCount=Array.isArray(t.turns)?t.turns.length:0;const s=J(t.turns);s.userRequest&&(this.previousUserText=s.userRequest),s.assistantResponse&&(this.previousAssistantText=s.assistantResponse),this.previousAffectedFiles.clear();for(const i of s.affectedFiles)this.previousAffectedFiles.add(i);this.latestTokenUsage=null}async maintainContext(e,t,s={}){const i=k(),r=this.contextState(),o=v(r,i);if(!o.compact&&!s.force||!this.currentSessionId)return this.maintenanceResult({stage:e,action:"none",reasons:o.reasons,beforeState:r});const c=this.currentSessionId;this.notifyContextStatus("正在整理会话上下文",P(r)),this.maintenanceActive=!0;let d=!1,l="",p=r,f=o,y=!1,b="";try{const h=r.usage?.observedAtMs??0;await this.compactThread(c,s.compactTimeoutMs??i.compactTimeoutMs),await this.waitForTokenUsageAfter(h,2e3)}catch(h){d=!0,l=h instanceof Error?h.message:String(h)}try{if(p=this.contextState(),f=v(p,i,{compactAttempted:!0,compactFailed:d}),f.rollover&&s.allowRollover!==!1){this.notifyContextStatus("正在创建轻量会话",f.reasons.join(", "));try{await this.rotateThread(c,t),y=!0}catch(h){b=h instanceof Error?h.message:String(h),this.notifyContextStatus("轻量会话创建失败",b)}}else d||this.notifyContextStatus("会话上下文已压缩",P(p))}finally{this.maintenanceActive=!1}return this.maintenanceResult({action:y?"rollover":b?"rollover_failed":d?"compact_failed":"compact",stage:e,reasons:f.reasons,beforeState:r,afterState:p,compactError:[l,b].filter(Boolean).join("; "),previousThreadId:c,rolloverRecommended:f.rollover&&s.allowRollover===!1})}compactThread(e,t){return this.pendingCompaction?Promise.reject(new Error("Codex context compaction is already running")):new Promise((s,i)=>{const r=setTimeout(()=>{this.pendingCompaction?.timer===r&&(this.pendingCompaction=null),i(new Error("Codex thread compaction timed out"))},t);r.unref(),this.pendingCompaction={resolve:s,reject:i,timer:r},this.requireRpc().request("thread/compact/start",{threadId:e},t).catch(o=>{this.pendingCompaction?.timer===r&&(this.pendingCompaction=null,clearTimeout(r),i(o instanceof Error?o:new Error(String(o))))})})}async rotateThread(e,t){const s=j({previousThreadId:e,cwd:this.currentCwd,userRequest:t.userRequest,assistantResponse:t.assistantResponse,affectedFiles:t.affectedFiles}),i=await this.requireRpc().request("thread/start",{cwd:this.currentCwd,approvalsReviewer:"user",...this.codexConfig(),developerInstructions:s,ephemeral:!1,threadSource:"aca-codex-acp-rollover"},6e4),r=C(i);if(!r)throw new Error("Codex rollover thread/start did not return thread id");this.sessionAliases.set(e,r),this.currentSessionId=r,this.resetSubtaskState(i),this.captureThreadMetadata(i)}async waitForTokenUsageAfter(e,t){const s=Date.now()+t;for(;Date.now()<s;){if((this.latestTokenUsage?.observedAtMs??0)>e)return;await te(50)}}resolveSessionAlias(e){if(!e)return null;let t=e;const s=new Set;for(;this.sessionAliases.has(t)&&!s.has(t);)s.add(t),t=this.sessionAliases.get(t)??t;return t}contextState(){return{usage:this.latestTokenUsage,rolloutBytes:O(this.currentRolloutPath),turnCount:this.threadTurnCount}}maintenanceResult(e){return{stage:e.stage,action:e.action,reasons:e.reasons,previousThreadId:e.previousThreadId??null,sessionId:this.currentSessionId,before:e.beforeState,after:e.afterState??null,compactError:e.compactError||null,rolloverRecommended:e.rolloverRecommended===!0}}notifyContextStatus(e,t){this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"aca_context_maintenance",label:e,detail:t}})}write(e){process.stdout.write(`${JSON.stringify(e)}
|
|
3
|
-
`)}}function
|
|
1
|
+
import{JsonLineRpcClient as F}from"../../client/json-rpc.js";import{startCodexAppServer as E}from"../codex/codex-process.js";import{CodexConnectionRecoveryTracker as N}from"../codex/connection-events.js";import{codexAcpSessionUpdatesFromNotification as C}from"../codex/events.js";import{CodexPlanDeltaState as T}from"../codex/plan-events.js";import{isCodexApprovalRequest as j,resolveCodexApprovalRequest as $}from"../codex/permissions.js";import{buildCodexContinuityInstructions as D,codexTokenUsageFromRawResponseCompleted as O,codexTokenUsageFromNotification as B,decideCodexContextMaintenance as v,readCodexContextMaintenancePolicy as k,rolloutFileSize as z}from"./context-maintenance.js";import{codexNotificationBelongsToCurrentTurn as K,codexNotificationRouting as R}from"./notification-routing.js";import{completedSubtaskHistoryUpdates as W}from"./subtask-history.js";import{CodexSubtaskRouter as L}from"./subtask-routing.js";class G{lineBuffer="";started=null;rpc=null;codexStartupPromise=null;initialized=!1;currentSessionId=null;currentCwd=process.cwd();promptActive=!1;currentTurnId=null;nextParentRequestId=1;pendingParentRequests=new Map;completedTurns=new Map;pendingTurnCompletions=new Map;agentMessagePhases=new Map;planDeltas=new T;subtaskRouter=new L;subtaskAgentMessagePhases=new Map;subtaskPlanDeltas=new Map;subscribedSubtaskThreadIds=new Set;pendingSubtaskSubscriptions=new Map;hydratedSubtaskThreadIds=new Set;seenSubtaskItemIds=new Set;pendingSubtaskNotifications=[];config={};sessionAliases=new Map;currentAffectedFiles=new Set;connectionRecovery=new N;latestTokenUsage=null;currentRolloutPath=null;threadTurnCount=0;currentPromptText="";currentAssistantText="";previousUserText="";previousAssistantText="";previousAffectedFiles=new Set;maintenanceActive=!1;pendingCompaction=null;shutdownPromise=null;managedProvider=null;constructor(){process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>this.handleInput(String(t)));const e=()=>{this.shutdown().finally(()=>process.exit(0))};process.stdin.once("end",e),process.stdin.once("close",e),process.stdin.once("error",e),process.once("SIGTERM",()=>{this.shutdown().finally(()=>process.exit(0))}),process.once("SIGINT",()=>{this.shutdown().finally(()=>process.exit(130))})}handleInput(e){this.lineBuffer+=e;const t=this.lineBuffer.split(`
|
|
2
|
+
`);this.lineBuffer=t.pop()??"";for(const s of t){const n=s.trim();if(!n)continue;let r;try{r=JSON.parse(n)}catch{continue}this.handleMessage(r)}}async handleMessage(e){if("id"in e&&("result"in e||"error"in e)&&typeof e.method!="string"){this.handleParentResponse(e);return}const t=typeof e.method=="string"?e.method:"",s=e.id;if(t){if(s===void 0){await this.handleNotification(t,u(e.params));return}try{const n=await this.handleRequest(t,u(e.params));this.write({jsonrpc:"2.0",id:s,result:n})}catch(n){this.write({jsonrpc:"2.0",id:s,error:{code:-32603,message:n instanceof Error?n.message:String(n)}})}}}async handleNotification(e,t){e==="session/cancel"&&await this.cancel(t)}async handleRequest(e,t){switch(e){case"initialize":return this.initializeResponse();case"aca/runtime_config":return this.applyRuntimeConfig(t);case"session/new":return this.newSession(t);case"session/resume":case"session/load":return this.resumeSession(t);case"session/fork":return this.forkSession(t);case"session/prompt":return this.prompt(t);case"session/compact":return this.manualCompact(t);case"session/cancel":return await this.cancel(t),{};case"session/close":return await this.closeSession(t),{};case"session/set_config_option":return this.setConfigOption(t);case"session/set_mode":return this.setMode(t);case"fs/read_text_file":case"fs/write_text_file":case"terminal/create":case"terminal/output":case"terminal/wait_for_exit":case"terminal/kill":case"terminal/release":return{};default:throw new Error(`Unsupported ACP method: ${e}`)}}initializeResponse(){return{protocolVersion:1,agentCapabilities:{loadSession:!0,sessionCapabilities:{resume:!0,close:!0}}}}applyRuntimeConfig(e){if(this.started)throw new Error("Codex runtime config must be applied before app-server starts");const t=u(e.codexProvider);if(Object.keys(t).length===0)return this.managedProvider=null,{configured:!1};const s=a(t,"baseUrl"),n=a(t,"apiKey"),r=Number(t.revision||0);if(!s||!n||!Number.isSafeInteger(r)||r<1)throw new Error("Invalid Codex managed provider runtime config");return this.managedProvider={baseUrl:s,apiKey:n,revision:r},{configured:!0,revision:r}}async newSession(e){const t=a(e,"cwd")||process.cwd();this.applyInitialConfig(e),await this.ensureCodex(t);const s=await this.requireRpc().request("thread/start",{cwd:t,approvalsReviewer:"user",...this.codexConfig(),ephemeral:!1,experimentalRawEvents:!0,threadSource:"aca-codex-acp"},6e4),n=I(s);if(!n)throw new Error("Codex thread/start did not return thread id");return this.currentSessionId=n,this.currentCwd=t,this.resetSubtaskState(),this.captureThreadMetadata(s),this.sessionResponse(n)}async resumeSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const n=await this.requireRpc().request("thread/resume",{threadId:t,cwd:s,approvalsReviewer:"user",...this.codexConfig()},6e4);return this.currentSessionId=I(n)||t,this.currentCwd=s,this.resetSubtaskState(n),await this.subscribeKnownSubtasks(!1),this.captureThreadMetadata(n),this.sessionResponse(this.currentSessionId)}async forkSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const n=await this.requireRpc().request("thread/fork",{threadId:t,cwd:s,approvalsReviewer:"user",ephemeral:!1,threadSource:"aca-codex-acp-fork",...this.codexConfig()},12e4),r=I(n);if(!r)throw new Error("Codex thread/fork did not return thread id");return this.currentSessionId=r,this.currentCwd=s,this.resetSubtaskState(n),this.captureThreadMetadata(n),this.sessionResponse(r)}async prompt(e){const t=a(e,"sessionId")||this.currentSessionId;let s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");const n=Array.isArray(e.prompt)?e.prompt:[],r=this.requireRpc();this.currentSessionId&&this.currentSessionId!==s&&this.resetSubtaskState(),this.currentSessionId=s;const o=await this.maintainContext("before",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{allowRollover:!0});Z(o),s=this.currentSessionId||s,this.promptActive=!0,this.currentTurnId=null,this.currentPromptText=H(n),this.currentAssistantText="",this.currentAffectedFiles.clear(),this.connectionRecovery.reset(),this.agentMessagePhases.clear(),this.planDeltas.reset(),this.pendingSubtaskNotifications=[];let c;try{c=await r.request("turn/start",{threadId:s,clientUserMessageId:`aca-acp-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:J(n),cwd:this.currentCwd,...V(this.config)},U());const d=String(c?.turn?.id??"");this.currentTurnId=d||null;const l=d?await this.waitForTurnCompleted(d,U()):c?.turn;this.threadTurnCount+=1,this.previousUserText=this.currentPromptText,this.previousAssistantText=this.currentAssistantText,this.previousAffectedFiles.clear();for(const f of this.currentAffectedFiles)this.previousAffectedFiles.add(f);const h=await this.maintainContext("after",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{allowRollover:!0});return{stopReason:"end_turn",sessionId:this.currentSessionId,turn:l,_meta:{acaContextUsage:A(h)??Y(this.latestTokenUsage),acaContextMaintenance:h}}}catch(d){const l=this.connectionRecovery.fail(d);throw l&&this.notifySessionUpdate(l),d}finally{this.promptActive=!1,this.currentTurnId=null,this.pendingSubtaskNotifications=[]}}resetSubtaskState(e){this.subtaskRouter.reset(),this.subtaskAgentMessagePhases.clear(),this.subtaskPlanDeltas.clear(),this.subscribedSubtaskThreadIds.clear(),this.pendingSubtaskSubscriptions.clear(),this.hydratedSubtaskThreadIds.clear(),this.seenSubtaskItemIds.clear(),this.pendingSubtaskNotifications=[],e!==void 0&&this.subtaskRouter.restoreFromSessionSnapshot(e,this.currentSessionId)}async subscribeKnownSubtasks(e=!0){const t=this.subtaskRouter.routesForSubscription().map(s=>this.subscribeSubtask(s,e));await Promise.allSettled(t)}subscribeSubtask(e,t){const s=e.sourceThreadId;if(!s||s===this.currentSessionId||this.subscribedSubtaskThreadIds.has(s))return Promise.resolve();const n=this.pendingSubtaskSubscriptions.get(s);if(n)return n;const r=this.requireRpc().request("thread/resume",{threadId:s,approvalsReviewer:"user",excludeTurns:!1},6e4).then(o=>{this.subscribedSubtaskThreadIds.add(s);const c=this.subtaskRouter.restoreFromSessionSnapshot(o,this.currentSessionId);t&&this.hydrateSubtaskHistory(o,e),c>0&&this.subscribeKnownSubtasks(t)}).catch(()=>{}).finally(()=>{this.pendingSubtaskSubscriptions.delete(s)});return this.pendingSubtaskSubscriptions.set(s,r),r}async cancel(e){const t=a(e,"sessionId")||this.currentSessionId;if(!(!t||!this.rpc)&&(await this.rpc.request("turn/interrupt",{threadId:t}).catch(()=>{}),this.currentTurnId)){const s=this.pendingTurnCompletions.get(this.currentTurnId);s&&(this.pendingTurnCompletions.delete(this.currentTurnId),clearTimeout(s.timer),s.reject(new Error("Codex prompt cancelled")))}}async manualCompact(e){const t=a(e,"sessionId")||this.currentSessionId,s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");if(this.promptActive||this.maintenanceActive)throw new Error("Codex session is busy");this.currentSessionId=s;const n=k(),r=await this.maintainContext("manual",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{force:!0,allowRollover:e.allowRollover===!0,compactTimeoutMs:X(e,n.compactTimeoutMs)}),o=String(r.action||"");if(o==="compact_failed"||o==="rollover_failed"){const c=String(r.compactError||"Codex 上下文压缩未完成");throw new Error(`Codex 上下文压缩失败:${c}`)}return{sessionId:this.currentSessionId,maintenance:r,contextUsage:A(r)}}async closeSession(e){await this.shutdown()}async ensureCodex(e){if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;if(this.codexStartupPromise){await this.codexStartupPromise;return}const t=(async()=>{if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;const s=E(e,this.managedProvider),n=new F(s.child,{peerName:"Codex app-server",onNotification:(r,o)=>this.handleCodexNotification(r,o),onRequest:async(r,o)=>this.handleCodexRequest(r,o)});this.started=s,this.rpc=n,this.initialized=!1,await n.request("initialize",{clientInfo:{name:"aca-codex-acp",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},6e4),this.initialized=!0})();this.codexStartupPromise=t;try{await t}catch(s){throw this.rpc&&this.started&&!this.initialized&&await y(this.started.child,1e3),this.rpc=null,this.started=null,s}finally{this.codexStartupPromise===t&&(this.codexStartupPromise=null)}}handleCodexNotification(e,t){const s=R(t);if(this.maintenanceActive&&(!s.threadId||s.threadId===this.currentSessionId)){this.captureContextNotification(e,t);return}if(!K(t,this.currentSessionId,this.currentTurnId)){if(!this.promptActive||!s.threadId||s.threadId===this.currentSessionId)return;const c=this.subtaskRouter.routeFor(s.threadId);if(!c){this.bufferPendingSubtaskNotification(e,t,s.threadId);return}this.handleSubtaskNotification(e,t,c),this.flushPendingSubtaskNotifications();return}const n=this.subtaskRouter.observe(t,this.currentSessionId);if(n>0&&this.subscribeKnownSubtasks(!0),this.captureContextNotification(e,t),this.maintenanceActive||!this.promptActive&&e!=="turn/completed")return;this.rpc?.refreshPendingRequestTimeout("turn/start"),this.captureAgentMessagePhase(e,t);const r=this.connectionRecovery.beforeNotification(e,t);e==="turn/completed"&&this.resolveTurnCompleted(t);const o=e==="rawResponse/completed"?ee(t):C(e,t,{agentMessagePhases:this.agentMessagePhases,planDeltas:this.planDeltas});for(const c of[...r,...o])this.captureUpdateEvidence(c),this.notifySessionUpdate(c);n>0&&this.flushPendingSubtaskNotifications()}handleSubtaskNotification(e,t,s){if(!this.promptActive)return;this.rememberSubtaskItem(s.sourceThreadId,t),this.rpc?.refreshPendingRequestTimeout("turn/start");const n=this.subtaskAgentMessagePhases.get(s.sourceThreadId)??new Map;this.subtaskAgentMessagePhases.set(s.sourceThreadId,n);const r=this.subtaskPlanDeltas.get(s.sourceThreadId)??new T;this.subtaskPlanDeltas.set(s.sourceThreadId,r),this.captureAgentMessagePhase(e,t,n),this.subtaskRouter.observe(t,this.currentSessionId)>0&&this.subscribeKnownSubtasks(!0);const c=C(e,t,{agentMessagePhases:n,planDeltas:r}),d=R(t).turnId;for(const l of c){if(!te(l))continue;const h=_(l,s,d);w(h,this.currentAffectedFiles),this.notifySessionUpdate(h)}}hydrateSubtaskHistory(e,t){if(!(!this.promptActive||this.hydratedSubtaskThreadIds.has(t.sourceThreadId))){this.hydratedSubtaskThreadIds.add(t.sourceThreadId);for(const s of W(e)){const n=M(t.sourceThreadId,s.itemId);if(this.seenSubtaskItemIds.has(n))continue;this.seenSubtaskItemIds.add(n);const r=_(s.update,t,s.sourceTurnId);w(r,this.currentAffectedFiles),this.notifySessionUpdate(r)}}}rememberSubtaskItem(e,t){const s=u(t),n=u(s.item),r=a(n,"id")||a(s,"itemId");r&&this.seenSubtaskItemIds.add(M(e,r))}bufferPendingSubtaskNotification(e,t,s){this.pendingSubtaskNotifications.push({method:e,params:t,threadId:s}),this.pendingSubtaskNotifications.length>200&&this.pendingSubtaskNotifications.shift()}flushPendingSubtaskNotifications(){if(this.pendingSubtaskNotifications.length===0)return;let e=!0;for(;e&&this.pendingSubtaskNotifications.length>0;){e=!1;const t=[];for(const s of this.pendingSubtaskNotifications){const n=this.subtaskRouter.routeFor(s.threadId);if(!n){t.push(s);continue}e=!0,this.handleSubtaskNotification(s.method,s.params,n)}this.pendingSubtaskNotifications=t}}notifySessionUpdate(e){this.notify("session/update",{sessionId:this.currentSessionId,update:e})}async handleCodexRequest(e,t){if(j(e))return $(e,t,async s=>{const n=await this.requestParent("session/request_permission",{sessionId:this.currentSessionId,request:{...s,params:t,method:e}}),r=u(n),o=u(r.outcome);return o.outcome==="selected"&&typeof o.optionId=="string"?{outcome:{outcome:"selected",optionId:o.optionId}}:{outcome:{outcome:"cancelled"}}});if(se(e)){const s=await this.requestParent("elicitation/create",{sessionId:this.currentSessionId,request:{...u(t),method:e}}),n=u(s),r=u(n.outcome);return r.outcome==="submitted"?{outcome:{outcome:"submitted",value:typeof r.value=="string"?r.value:""}}:{outcome:{outcome:"cancelled"}}}return{}}captureAgentMessagePhase(e,t,s=this.agentMessagePhases){if(e!=="item/started"&&e!=="item/completed")return;const n=m(t,"item");if(a(n,"type")!=="agentMessage")return;const r=a(n,"id");r&&s.set(r,a(n,"phase"))}waitForTurnCompleted(e,t){const s=this.completedTurns.get(e);return s?Promise.resolve(s):new Promise((n,r)=>{const o=setTimeout(()=>{this.pendingTurnCompletions.delete(e),r(new Error("Codex app-server request timed out while waiting for turn/completed"))},t);o.unref(),this.pendingTurnCompletions.set(e,{resolve:n,reject:r,timer:o})})}resolveTurnCompleted(e){const t=m(e,"turn"),s=a(t,"id");if(!s)return;this.completedTurns.set(s,t);const n=this.pendingTurnCompletions.get(s);if(n){if(this.pendingTurnCompletions.delete(s),clearTimeout(n.timer),a(t,"status")==="failed"){n.reject(new Error(`Codex turn failed: ${JSON.stringify(t.error??{})}`));return}n.resolve(t)}}async shutdown(){return this.shutdownPromise?this.shutdownPromise:(this.shutdownPromise=this.performShutdown(),this.shutdownPromise)}async performShutdown(){this.pendingCompaction&&(clearTimeout(this.pendingCompaction.timer),this.pendingCompaction.reject(new Error("Codex ACP adapter closed")),this.pendingCompaction=null);for(const t of this.pendingParentRequests.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingParentRequests.clear();for(const t of this.pendingTurnCompletions.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingTurnCompletions.clear();const e=this.started?.child;!e||e.exitCode!==null||e.signalCode!==null||(e.stdin.end(),!await y(e,2e3)&&(e.kill("SIGTERM"),!await y(e,1e3)&&(e.kill("SIGKILL"),await y(e,1e3))))}sessionResponse(e){return{sessionId:e,modes:{currentModeId:"workspace-write",availableModes:[{id:"read-only",name:"Read Only"},{id:"workspace-write",name:"Workspace Write"},{id:"danger-full-access",name:"Full Access"}]},configOptions:[{id:"model",category:"model",type:"string"},{id:"approvalPolicy",category:"approval",type:"string"},{id:"sandbox",category:"mode",type:"string"}]}}requireRpc(){if(!this.rpc)throw new Error("Codex app-server is not started");return this.rpc}notify(e,t){this.write({jsonrpc:"2.0",method:e,params:t})}requestParent(e,t,s=600*1e3){const n=this.nextParentRequestId++;return new Promise((r,o)=>{const c=setTimeout(()=>{this.pendingParentRequests.delete(n),o(new Error(`ACP client request timed out: ${e}`))},s);c.unref(),this.pendingParentRequests.set(n,{resolve:r,reject:o,timer:c}),this.write({jsonrpc:"2.0",id:n,method:e,params:t})})}handleParentResponse(e){const t=Number(e.id),s=this.pendingParentRequests.get(t);if(s){if(this.pendingParentRequests.delete(t),clearTimeout(s.timer),"error"in e){const n=u(e.error);s.reject(new Error(a(n,"message")||"ACP client request failed"));return}s.resolve(e.result)}}setConfigOption(e){const t=a(e,"configId"),s=e.value;if(!t)throw new Error("configId is required");if(typeof s!="string"&&typeof s!="boolean")throw new Error("config value must be string or boolean");return this.config[t]=s,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"config_option_update",configId:t,value:s}}),{}}setMode(e){const t=a(e,"modeId");if(!t)throw new Error("modeId is required");return this.config.sandbox=t,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"current_mode_update",modeId:t}}),{}}applyInitialConfig(e){const t=m(e,"config");for(const[s,n]of Object.entries(t))(typeof n=="string"||typeof n=="boolean")&&(this.config[s]=n)}codexConfig(){return{...typeof this.config.model=="string"&&this.config.model?{model:this.config.model}:{},approvalPolicy:typeof this.config.approvalPolicy=="string"?this.config.approvalPolicy:"on-request",sandbox:typeof this.config.sandbox=="string"?this.config.sandbox:"workspace-write"}}captureContextNotification(e,t){if(e==="thread/tokenUsage/updated"&&(this.latestTokenUsage=B(t)??this.latestTokenUsage),e==="thread/compacted"&&this.pendingCompaction&&this.resolveCompaction(),e==="item/completed"){const s=m(t,"item"),n=a(u(t),"threadId");a(s,"type")==="contextCompaction"&&(!n||n===this.currentSessionId)&&this.resolveCompaction(),a(s,"type")==="agentMessage"&&a(s,"phase")==="final_answer"&&(this.currentAssistantText=g(s)||this.currentAssistantText)}}resolveCompaction(){if(!this.pendingCompaction)return;const e=this.pendingCompaction;this.pendingCompaction=null,clearTimeout(e.timer),e.resolve()}captureUpdateEvidence(e){String(e.sessionUpdate||"")==="agent_message_chunk"&&(this.currentAssistantText+=g(e.content)),w(e,this.currentAffectedFiles)}captureThreadMetadata(e){const t=m(e,"thread");this.currentRolloutPath=a(t,"path")||null,this.threadTurnCount=Array.isArray(t.turns)?t.turns.length:0;const s=Q(t.turns);s.userRequest&&(this.previousUserText=s.userRequest),s.assistantResponse&&(this.previousAssistantText=s.assistantResponse),this.previousAffectedFiles.clear();for(const n of s.affectedFiles)this.previousAffectedFiles.add(n);this.latestTokenUsage=null}async maintainContext(e,t,s={}){const n=k(),r=this.contextState(),o=v(r,n);if(!o.compact&&!s.force||!this.currentSessionId)return this.maintenanceResult({stage:e,action:"none",reasons:o.reasons,beforeState:r});const c=this.currentSessionId;this.notifyContextStatus("正在整理会话上下文",P(r)),this.maintenanceActive=!0;let d=!1,l="",h=r,f=o,x=!1,b="";try{const p=r.usage?.observedAtMs??0;await this.compactThread(c,s.compactTimeoutMs??n.compactTimeoutMs),await this.waitForTokenUsageAfter(p,2e3)}catch(p){d=!0,l=p instanceof Error?p.message:String(p)}try{if(h=this.contextState(),f=v(h,n,{compactAttempted:!0,compactFailed:d}),f.rollover&&s.allowRollover!==!1){this.notifyContextStatus("正在创建轻量会话",f.reasons.join(", "));try{await this.rotateThread(c,t),x=!0}catch(p){b=p instanceof Error?p.message:String(p),this.notifyContextStatus("轻量会话创建失败",b)}}else d||this.notifyContextStatus("会话上下文已压缩",P(h))}finally{this.maintenanceActive=!1}return this.maintenanceResult({action:x?"rollover":b?"rollover_failed":d?"compact_failed":"compact",stage:e,reasons:f.reasons,beforeState:r,afterState:h,compactError:[l,b].filter(Boolean).join("; "),previousThreadId:c,rolloverRecommended:f.rollover&&s.allowRollover===!1})}compactThread(e,t){return this.pendingCompaction?Promise.reject(new Error("Codex context compaction is already running")):new Promise((s,n)=>{const r=setTimeout(()=>{this.pendingCompaction?.timer===r&&(this.pendingCompaction=null),n(new Error("Codex thread compaction timed out"))},t);r.unref(),this.pendingCompaction={resolve:s,reject:n,timer:r},this.requireRpc().request("thread/compact/start",{threadId:e},t).catch(o=>{this.pendingCompaction?.timer===r&&(this.pendingCompaction=null,clearTimeout(r),n(o instanceof Error?o:new Error(String(o))))})})}async rotateThread(e,t){const s=D({previousThreadId:e,cwd:this.currentCwd,userRequest:t.userRequest,assistantResponse:t.assistantResponse,affectedFiles:t.affectedFiles}),n=await this.requireRpc().request("thread/start",{cwd:this.currentCwd,approvalsReviewer:"user",...this.codexConfig(),developerInstructions:s,ephemeral:!1,experimentalRawEvents:!0,threadSource:"aca-codex-acp-rollover"},6e4),r=I(n);if(!r)throw new Error("Codex rollover thread/start did not return thread id");this.sessionAliases.set(e,r),this.currentSessionId=r,this.resetSubtaskState(n),this.captureThreadMetadata(n)}async waitForTokenUsageAfter(e,t){const s=Date.now()+t;for(;Date.now()<s;){if((this.latestTokenUsage?.observedAtMs??0)>e)return;await ne(50)}}resolveSessionAlias(e){if(!e)return null;let t=e;const s=new Set;for(;this.sessionAliases.has(t)&&!s.has(t);)s.add(t),t=this.sessionAliases.get(t)??t;return t}contextState(){return{usage:this.latestTokenUsage,rolloutBytes:z(this.currentRolloutPath),turnCount:this.threadTurnCount}}maintenanceResult(e){return{stage:e.stage,action:e.action,reasons:e.reasons,previousThreadId:e.previousThreadId??null,sessionId:this.currentSessionId,before:e.beforeState,after:e.afterState??null,compactError:e.compactError||null,rolloverRecommended:e.rolloverRecommended===!0}}notifyContextStatus(e,t){this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"aca_context_maintenance",label:e,detail:t}})}write(e){process.stdout.write(`${JSON.stringify(e)}
|
|
3
|
+
`)}}function J(i){return i.map(e=>{const t=u(e);if(t.type==="image"){const s=a(t,"uri");if(s)return{type:"localImage",path:s};const n=a(t,"data");return{type:"image",url:`data:${a(t,"mimeType")||"image/png"};base64,${n}`}}return{type:"text",text:a(t,"text"),text_elements:[]}})}function H(i){return i.map(e=>a(u(e),"text")).filter(Boolean).join(`
|
|
4
4
|
|
|
5
|
-
`)}function
|
|
5
|
+
`)}function V(i){const e={};typeof i.model=="string"&&i.model&&(e.model=i.model),typeof i.approvalPolicy=="string"&&i.approvalPolicy&&(e.approvalPolicy=i.approvalPolicy),typeof i.sandbox=="string"&&i.sandbox&&(e.sandbox=i.sandbox);const t=i.reasoning_effort??i.reasoningEffort??i.model_reasoning_effort??i.modelReasoningEffort??i.effort;return typeof t=="string"&&t&&(e.effort=t),e}function I(i){const e=m(i,"thread");return a(e,"id")||null}function m(i,e){const t=u(i);return u(t[e])}function u(i){return i&&typeof i=="object"&&!Array.isArray(i)?i:{}}function g(i){if(typeof i=="string")return i;if(Array.isArray(i))return i.map(g).filter(Boolean).join("");if(!i||typeof i!="object")return"";const e=u(i);for(const t of["text","message","content","output_text"]){const s=g(e[t]);if(s)return s}return""}function w(i,e){if(Array.isArray(i)){for(const r of i)w(r,e);return}const t=u(i),s=a(t,"type").toLowerCase(),n=a(t,"path");if(n&&["diff","resource_link","content"].includes(s)&&e.add(n),Array.isArray(t.locations))for(const r of t.locations){const o=a(u(r),"path");o&&e.add(o)}for(const r of[t.content,t.update,t.rawInput,t.rawOutput])r&&r!==i&&w(r,e)}function Q(i){if(!Array.isArray(i)||i.length===0)return{userRequest:"",assistantResponse:"",affectedFiles:[]};const e=i.at(-1),t=new Set;w(e,t);let s="",n="";const r=o=>{if(Array.isArray(o)){for(const l of o)r(l);return}if(!o||typeof o!="object")return;const c=u(o),d=a(c,"type").toLowerCase();d==="usermessage"&&(s=g(c)||s),d==="agentmessage"&&(n=g(c)||n);for(const l of["items","content","input"])c[l]&&r(c[l])};return r(e),{userRequest:s,assistantResponse:n,affectedFiles:[...t]}}function X(i,e){const t=S(i,"timeoutMs");return!Number.isFinite(t)||t<=0?e:Math.max(3e4,Math.min(59e4,t-1e4))}function A(i){const e=String(i.action||"none"),t=u(i.after),s=u(i.before),n=u(t.usage),r=u(s.usage),o=Object.keys(n).length>0?n:r,c=S(o,"contextWindow");if(e==="rollover")return{usedTokens:0,inputTokens:0,contextWindow:c,ratio:0,observedAtMs:Date.now(),state:"new_thread",maintenanceAction:e};if(Object.keys(o).length===0)return null;const d=S(o,"totalTokens"),l=S(o,"inputTokens");return{usedTokens:d||l,inputTokens:l,contextWindow:c,ratio:c>0?(d||l)/c:0,observedAtMs:S(o,"observedAtMs")||Date.now(),state:e==="compact"?"compacted":"active",maintenanceAction:e}}function Y(i){return i?{usedTokens:i.totalTokens||i.inputTokens,inputTokens:i.inputTokens,contextWindow:i.contextWindow,ratio:i.contextWindow>0?(i.totalTokens||i.inputTokens)/i.contextWindow:0,observedAtMs:i.observedAtMs,state:"active",maintenanceAction:null}:null}function P(i){const e=i.usage?`${i.usage.inputTokens} tokens`:"token unknown",t=i.rolloutBytes>0?`${Math.round(i.rolloutBytes/1024/1024)}MB rollout`:"rollout unknown";return`${e}, ${t}, ${i.turnCount} turns`}function Z(i){const e=String(i.action||"none");if(e!=="compact_failed"&&e!=="rollover_failed")return;const t=String(i.compactError||"Codex 上下文维护未完成");throw new Error(`Codex 自动上下文维护失败:${t}`)}function S(i,e){const t=u(i)[e];return typeof t=="number"&&Number.isFinite(t)?t:0}function ee(i){return O(i)?[{sessionUpdate:"aca_codex_raw_response_usage",_meta:{codex:{rawResponse:i}}}]:[]}function te(i){return["agent_message_chunk","agent_progress_chunk","agent_thought_chunk","tool_call","tool_call_update","plan","plan_update","plan_removed"].includes(String(i.sessionUpdate||""))}function _(i,e,t){const s=String(i.sessionUpdate||""),n={...i};if(s==="tool_call"||s==="tool_call_update"){const c=a(i,"toolCallId");c&&(n.toolCallId=q(e.sourceThreadId,c))}if(s==="plan"||s==="plan_update"||s==="plan_removed"){const c=a(i,"planId")||a(i,"plan_id")||a(i,"id")||"current";n.planId=q(e.sourceThreadId,c),delete n.plan_id}const r=u(i._meta),o=u(r.aca);return n._meta={...r,aca:{...o,subtask:{parentToolCallId:e.parentToolCallId,sourceThreadId:e.sourceThreadId,sourceTurnId:t,depth:e.depth}}},n}function q(i,e){return`subtask.${i}.${e}`}function M(i,e){return`${i}:${e}`}function a(i,e){const s=u(i)[e];return typeof s=="string"?s:""}function se(i){const e=i.toLowerCase();return e.includes("elicitation")||e.includes("requestuserinput")||e.includes("request_user_input")||e.includes("input/request")}function U(){const i=Number.parseInt(process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(i)&&i>=3e4?i:360*60*1e3}function y(i,e){return i.exitCode!==null||i.signalCode!==null?Promise.resolve(!0):new Promise(t=>{const s=setTimeout(()=>t(!1),e);s.unref(),i.once("close",()=>{clearTimeout(s),t(!0)})})}function ne(i){return new Promise(e=>setTimeout(e,i))}function ie(){new G}const re=process.argv[1]||"";/(?:^|[\\/])adapter\.(?:js|ts)$/.test(re)&&ie();export{ie as runCodexAcpAdapter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import p from"node:fs";import{runAbortableRequest as I}from"../../client/abortable-request.js";import{BoundedItemBuffer as T}from"../../client/bounded-buffer.js";import{promptBlocksToAcpContent as q}from"../../client/acp-content.js";import{acpSessionUpdateFromParams as U,eventFromAcpSessionUpdate as E,statusFromAcpSessionUpdate as D,subtaskContextFromAcpSessionUpdate as O}from"../../client/acp-events.js";import{defaultAcpRuntimePool as C}from"../../client/acp-runtime-pool.js";import{AcpSessionInvalidatedError as L}from"../../session-errors.js";import{resolveCodexAcpLaunch as b}from"./launch.js";import{CodexPromptPerformanceTracker as j,CodexUsageLoopDetector as F,codexRawResponseUsageFromAcpSessionUpdate as z,codexTokenUsageFromAcpSessionUpdate as N,readCodexContextMaintenancePolicy as v}from"./context-maintenance.js";import{ensureCodexProviderRuntimeConfig as A}from"../../../core/codex-provider-runtime-config.js";const $={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!0};class ce{id="codex-acp";name="Codex ACP";capabilities=$;async createSession(e){return new H(e.cwd,e.providerSessionId??null,e.timeoutMs)}async forkSession(e){if(!p.existsSync(e.cwd)||!p.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=e.sourceProviderSessionId.trim(),o=await A(),r=await C.acquire({providerId:"codex-acp",cwd:e.cwd,providerSessionId:s,runtimeIdentity:o?.runtimeIdentity||"default",env:k(o),...b(),onSessionUpdate:()=>{}});try{await x(r,o),r.initialized||(await r.client.initialize(6e4),r.markInitialized()),e.onStatus?.({phase:"forking",label:"正在分叉 Codex 会话",detail:s,updateType:"session/fork",atMs:Date.now()});const i=await r.client.forkSession({sessionId:s,cwd:e.cwd,config:P(e)},e.timeoutMs??12e4),n=h(i);if(!n)throw new Error("Codex ACP session/fork did not return sessionId");return{providerSessionId:n}}finally{r.release()}}}class H{cwd;providerSessionId;defaultTimeoutMs;lease=null;sessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;abortHandler=null;statusTimeline=[];updates=new T(16);content="";performanceTracker=null;usageLoopDetector=null;usageLoopReject=null;constructor(e,s,o=G()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=o}async sendPrompt(e){if(!p.existsSync(e.cwd)||!p.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.attachAbortSignal(e.signal),this.content="",this.updates.clear(),this.statusTimeline.length=0;const o=v();this.performanceTracker=new j(s),this.usageLoopDetector=new F(o);let r=null,i=null,n=this.providerSessionId,c,a=null;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const l=await this.acquireRuntime(e.cwd);this.lease=l,r=l.client,i=l.started,await this.initialize(l),n=await this.establishSession(l,e),await this.applyConfig(r,n,e),this.emitStatus("thinking","思考中"),a=this.startSlowStatusTimer(),c=await this.promptWithWatchdog(r,{sessionId:n,prompt:q(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const d=R(c);d&&d!==n&&(n=d,this.providerSessionId=d,l.setProviderSession({providerSessionId:d,sessionResponse:this.sessionResponse}))}finally{a&&clearInterval(a),this.usageLoopReject=null,this.usageLoopDetector=null,this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:i.command,processPid:i.child.pid??null,provider:"codex-acp",protocol:"acp"},command:i.command,args:i.args,cwd:e.cwd,exitCode:i.child.exitCode,signal:i.child.signalCode,durationMs:Date.now()-s,stdout:r.rpc.stdout,stderr:r.rpc.stderr,content:this.content.trim(),updateCount:this.updates.count(),updates:this.updates.snapshot(),statusTimeline:[...this.statusTimeline],performance:this.performanceTracker?.snapshot(),contextUsage:J(c),promptResponse:c}}async compactContext(e){if(!p.existsSync(e.cwd)||!p.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.attachAbortSignal(e.signal);let o=this.providerSessionId,r;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const n=await this.acquireRuntime(e.cwd);this.lease=n,await this.initialize(n),o=await this.establishSession(n,e),await this.applyConfig(n.client,o,e);const c=Y(e.timeoutMs);r=await this.compactWithAbort(n.client,{sessionId:o,allowRollover:e.allowRollover===!0,timeoutMs:c,signal:e.signal});const a=R(r);a&&a!==o&&(o=a,this.providerSessionId=a,n.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}))}catch(n){if(this.lease&&B(n,e.signal)){const c=this.lease;this.lease=null,await c.dispose().catch(()=>{})}throw this.emitStatus("failed","上下文压缩失败",n instanceof Error?n.message:String(n)),n}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}const i=u(r)??{};return{providerSessionId:o||this.providerSessionId||"",contextUsage:M(i.contextUsage),maintenance:u(i.maintenance)??{},durationMs:Date.now()-s}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const s=b(),o=await A(),r=await C.acquire({providerId:"codex-acp",cwd:e,providerSessionId:this.providerSessionId,runtimeIdentity:o?.runtimeIdentity||"default",env:k(o),command:s.command,args:s.args,onSessionUpdate:i=>this.handleSessionUpdate(i),onClientRequest:async(i,n)=>{if(i==="session/request_permission")return this.requestPermission(n);if(i==="elicitation/create"||i==="session/request_user_input")return this.requestUserInput(n);throw new Error(`Unsupported Codex ACP client request: ${i}`)}});try{return await x(r,o),r}catch(i){throw await r.dispose().catch(()=>{}),i}}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,s){const o=e.client,r=P(s);if(e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.sessionResponse=e.sessionResponse,e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","Codex ACP 会话恢复中","session/load");const c=await o.loadSession({sessionId:this.providerSessionId,cwd:s.cwd,config:r},6e4);this.sessionResponse=u(c);const a=h(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),a}catch(c){if(s.requireSessionResume){const a=c instanceof Error?c.message:String(c);throw new Error(`无法恢复导入的 Codex ACP Session ${this.providerSessionId}:${a}`)}this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const i=await o.newSession({cwd:s.cwd,config:r},12e4);this.sessionResponse=u(i);const n=h(i);if(!n)throw new Error("Codex ACP session/new did not return sessionId");return this.providerSessionId=n,e.setProviderSession({providerSessionId:n,sessionResponse:this.sessionResponse}),n}async applyConfig(e,s,o){o.model&&await e.setSessionConfigOption({sessionId:s,configId:"model",value:o.model},6e4).catch(()=>{});const r=g(o.mode);r&&await e.setSessionConfigOption({sessionId:s,configId:"approvalPolicy",value:r},6e4).catch(()=>{});const i=f(o.mode);i&&await e.setSessionConfigOption({sessionId:s,configId:"sandbox",value:i},6e4).catch(()=>{});for(const[n,c]of Object.entries(o.configOptionValues??{}))["model","mode","sandbox","approvalPolicy"].includes(n)||await e.setSessionConfigOption({sessionId:s,configId:n,value:c},6e4).catch(()=>{})}handleSessionUpdate(e){const s=U(e),o=String(s?.update.sessionUpdate||""),r=O(e);if(!r&&V(o))this.performanceTracker?.recordEvent(),this.usageLoopDetector?.recordMeaningfulEvent();else if(!r&&o==="aca_codex_raw_response_usage"){const c=z(e),a=c?this.usageLoopDetector?.recordUsage(c):null;a&&this.usageLoopReject?.(a)}else if(!r&&o==="usage_update"){const c=N(e),a=c?this.usageLoopDetector?.recordUsage(c):null;a&&this.usageLoopReject?.(a)}this.updates.push({method:"session/update",params:e});const i=E(e);i&&(i.type==="agent_message_chunk"&&!r&&(this.content+=i.text??""),this.updateCallback?.(i));const n=D(e);n&&this.emitStatus(n.phase,n.label,n.detail,n.updateType)}startSlowStatusTimer(){const e=v().slowEventThresholdMs,s=setInterval(()=>{const o=this.performanceTracker,r=Date.now();if(!o?.shouldReportSlow(r,e))return;const i=o.snapshot(r),n=Math.max(1,Math.round(i.silentForMs/6e4));this.emitStatus("thinking","模型长时间处理中",`已 ${n} 分钟没有收到新的 ACP 事件`,"aca.performance.slow")},Math.min(3e4,Math.max(1e3,Math.floor(e/4))));return s.unref(),s}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("Codex ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}async promptWithAbort(e,s){return I({signal:s.signal,cancelledMessage:"Codex ACP prompt cancelled",startRequest:()=>e.prompt({sessionId:s.sessionId,prompt:s.prompt},s.timeoutMs),onAbort:async()=>{e.cancel(s.sessionId),await this.lease?.dispose()}})}async promptWithWatchdog(e,s){const o=this.promptWithAbort(e,s);let r=null,i=null;const n=new Promise((c,a)=>{this.usageLoopReject=l=>{this.usageLoopReject=null;const d=`${l.sampleCount} 次请求均输入约 ${Math.round(l.maxInputTokens/1e3)}k tokens,且未产生有效过程事件`,w=new L(`Codex 内部重复请求:${d}`,s.sessionId,{source:l.source,threadId:l.threadId,turnId:l.turnId,responseIds:l.responseIds,sampleCount:l.sampleCount,windowMs:l.windowMs,minInputTokens:l.minInputTokens,maxInputTokens:l.maxInputTokens,maxOutputTokens:l.maxOutputTokens,detectedAtMs:l.detectedAtMs});r=w,this.emitStatus("failed","Codex 内部重复请求",d,"aca.performance.usage_loop");const S=this.lease;this.lease=null,this.providerSessionId=null,e.cancel(s.sessionId);const y=S?S.dispose().catch(()=>{}):Promise.resolve();i=y,y.finally(()=>a(w))}});try{return await Promise.race([o,n])}catch(c){throw r?(await i,r):c}finally{this.usageLoopReject=null}}async compactWithAbort(e,s){return I({signal:s.signal,cancelledMessage:"Codex ACP 上下文压缩已取消",startRequest:()=>e.compactSession({sessionId:s.sessionId,allowRollover:s.allowRollover,timeoutMs:s.timeoutMs},s.timeoutMs),onAbort:async()=>{e.cancel(s.sessionId),await this.lease?.dispose()}})}async requestPermission(e){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s,i=(Array.isArray(o.options)?o.options:[]).map((n,c)=>{const a=n&&typeof n=="object"&&!Array.isArray(n)?n:{};return{optionId:String(a.optionId??a.id??c),kind:String(a.kind??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.emitStatus("requestPermission","等待授权",K(o),"session/request_permission"),this.permissionCallback({requestId:String(o.requestId??o.id??`codex-acp-permission-${Date.now()}`),params:e,options:i})}async requestUserInput(e){if(!this.userInputCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s;return this.emitStatus("requestPermission","等待输入",X(o),"elicitation/create"),this.userInputCallback({requestId:String(o.requestId??o.id??`codex-acp-input-${Date.now()}`),prompt:String(o.prompt??o.message??o.question??""),params:e,...typeof o.defaultValue=="string"?{defaultValue:o.defaultValue}:{}})}emitStatus(e,s,o,r){const i={phase:e,label:s,...o?{detail:o}:{},...r?{updateType:r}:{},atMs:Date.now()},n=this.statusTimeline[this.statusTimeline.length-1];n&&n.phase===i.phase&&n.label===i.label&&n.detail===i.detail&&n.updateType===i.updateType||(this.statusTimeline.push(i),this.statusCallback?.(i))}releaseLease(){this.lease?.release(),this.lease=null}}const W=new Set(["agent_message_chunk","agent_progress_chunk","agent_thought_chunk","tool_call","tool_call_update","plan","plan_update","plan_removed","aca_context_maintenance"]);function V(t){return W.has(t)}async function x(t,e){t.runtimeConfigured||(await t.client.configureRuntime({codexProvider:e?{baseUrl:e.baseUrl,apiKey:e.apiKey,revision:e.revision}:null}),t.markRuntimeConfigured())}function k(t){return t?{OPENAI_API_KEY:t.apiKey,OPENAI_BASE_URL:t.baseUrl}:{}}function B(t,e){if(e?.aborted)return!0;const s=t instanceof Error?t.message:String(t||"");return/compact.*timed out|request timed out.*compact|adapter closed|aborted|cancelled/i.test(s)}function h(t){if(!t||typeof t!="object"||Array.isArray(t))return null;const e=t.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function u(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:null}function f(t){const e=String(t||"").trim();return e?e==="read-only"?"read-only":["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"danger-full-access":"workspace-write":null}function g(t){const e=String(t||"").trim();return e?["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"never":e==="acceptEdits"||e==="accept-edits"?"on-failure":"on-request":null}function P(t){return{...t.model?{model:t.model}:{},...g(t.mode)?{approvalPolicy:g(t.mode)}:{},...f(t.mode)?{sandbox:f(t.mode)}:{},...t.configOptionValues??{}}}function K(t){const e=t.params&&typeof t.params=="object"&&!Array.isArray(t.params)?t.params:t;for(const s of["command","cwd","reason","grantRoot","method"]){const o=e[s];if(typeof o=="string"&&o.trim())return _(o)}}function X(t){for(const e of["prompt","message","question","title"]){const s=t[e];if(typeof s=="string"&&s.trim())return _(s)}}function _(t){const e=t.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function G(){const t=Number.parseInt(process.env.ACA_CODEX_ACP_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(t)&&t>=3e4?t:360*60*1e3}function Y(t){const e=Number.isInteger(t)?Number(t):Number.parseInt(process.env.ACA_CODEX_ACP_COMPACT_TIMEOUT_MS??"",10);return Number.isFinite(e)&&e>=3e4?Math.min(e,6e5):12e4}function R(t){if(!t||typeof t!="object"||Array.isArray(t))return null;const e=t;return typeof e.sessionId=="string"&&e.sessionId.trim()?e.sessionId:null}function J(t){const e=u(t),s=u(e?._meta);return M(s?.acaContextUsage)}function M(t){const e=u(t);if(!e)return null;const s=m(e.contextWindow),o=m(e.usedTokens),r=m(e.inputTokens),i=String(e.state||"unknown"),n=["active","compacted","new_thread"].includes(i)?i:"unknown";return{usedTokens:o,inputTokens:r,contextWindow:s,ratio:s>0?Math.max(0,m(e.ratio)||o/s):0,observedAtMs:m(e.observedAtMs)||Date.now(),state:n,maintenanceAction:typeof e.maintenanceAction=="string"?e.maintenanceAction:null}}function m(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0?t:0}export{ce as CodexAcpProvider,$ as codexAcpCapabilities};
|
|
1
|
+
import u from"node:fs";import{runAbortableRequest as w}from"../../client/abortable-request.js";import{BoundedItemBuffer as M}from"../../client/bounded-buffer.js";import{promptBlocksToAcpContent as T}from"../../client/acp-content.js";import{acpSessionUpdateFromParams as q,eventFromAcpSessionUpdate as U,statusFromAcpSessionUpdate as E,subtaskContextFromAcpSessionUpdate as D}from"../../client/acp-events.js";import{defaultAcpRuntimePool as y}from"../../client/acp-runtime-pool.js";import{resolveCodexAcpLaunch as C}from"./launch.js";import{CodexPromptPerformanceTracker as O,CodexUsageLoopDetector as L,codexRawResponseUsageFromAcpSessionUpdate as F,codexTokenUsageFromAcpSessionUpdate as j,readCodexContextMaintenancePolicy as I}from"./context-maintenance.js";import{ensureCodexProviderRuntimeConfig as b}from"../../../core/codex-provider-runtime-config.js";const z={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!0};class ie{id="codex-acp";name="Codex ACP";capabilities=z;async createSession(e){return new N(e.cwd,e.providerSessionId??null,e.timeoutMs)}async forkSession(e){if(!u.existsSync(e.cwd)||!u.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const t=e.sourceProviderSessionId.trim(),o=await b(),r=await y.acquire({providerId:"codex-acp",cwd:e.cwd,providerSessionId:t,runtimeIdentity:o?.runtimeIdentity||"default",env:v(o),...C(),onSessionUpdate:()=>{}});try{await A(r,o),r.initialized||(await r.client.initialize(6e4),r.markInitialized()),e.onStatus?.({phase:"forking",label:"正在分叉 Codex 会话",detail:t,updateType:"session/fork",atMs:Date.now()});const i=await r.client.forkSession({sessionId:t,cwd:e.cwd,config:x(e)},e.timeoutMs??12e4),n=h(i);if(!n)throw new Error("Codex ACP session/fork did not return sessionId");return{providerSessionId:n}}finally{r.release()}}}class N{cwd;providerSessionId;defaultTimeoutMs;lease=null;sessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;abortHandler=null;statusTimeline=[];updates=new M(16);content="";performanceTracker=null;usageLoopDetector=null;usagePatternReport=null;constructor(e,t,o=K()){this.cwd=e,this.providerSessionId=t,this.defaultTimeoutMs=o}async sendPrompt(e){if(!u.existsSync(e.cwd)||!u.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const t=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.attachAbortSignal(e.signal),this.content="",this.updates.clear(),this.statusTimeline.length=0;const o=I();this.performanceTracker=new O(t),this.usageLoopDetector=new L(o);let r=null,i=null,n=this.providerSessionId,c,a=null;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const d=await this.acquireRuntime(e.cwd);this.lease=d,r=d.client,i=d.started,await this.initialize(d),n=await this.establishSession(d,e),await this.applyConfig(r,n,e),this.emitStatus("thinking","思考中"),a=this.startSlowStatusTimer(),this.usagePatternReport=S=>{const R=`${S.sampleCount} 次内部采样均输入约 ${Math.round(S.maxInputTokens/1e3)}k tokens`;this.emitStatus("thinking","Codex 正在进行内部续步",R,"aca.performance.multi_response")},c=await this.promptWithAbort(r,{sessionId:n,prompt:T(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const p=_(c);p&&p!==n&&(n=p,this.providerSessionId=p,d.setProviderSession({providerSessionId:p,sessionResponse:this.sessionResponse}))}finally{a&&clearInterval(a),this.usagePatternReport=null,this.usageLoopDetector=null,this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:i.command,processPid:i.child.pid??null,provider:"codex-acp",protocol:"acp"},command:i.command,args:i.args,cwd:e.cwd,exitCode:i.child.exitCode,signal:i.child.signalCode,durationMs:Date.now()-t,stdout:r.rpc.stdout,stderr:r.rpc.stderr,content:this.content.trim(),updateCount:this.updates.count(),updates:this.updates.snapshot(),statusTimeline:[...this.statusTimeline],performance:this.performanceTracker?.snapshot(),contextUsage:G(c),promptResponse:c}}async compactContext(e){if(!u.existsSync(e.cwd)||!u.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const t=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.attachAbortSignal(e.signal);let o=this.providerSessionId,r;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const n=await this.acquireRuntime(e.cwd);this.lease=n,await this.initialize(n),o=await this.establishSession(n,e),await this.applyConfig(n.client,o,e);const c=X(e.timeoutMs);r=await this.compactWithAbort(n.client,{sessionId:o,allowRollover:e.allowRollover===!0,timeoutMs:c,signal:e.signal});const a=_(r);a&&a!==o&&(o=a,this.providerSessionId=a,n.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}))}catch(n){if(this.lease&&V(n,e.signal)){const c=this.lease;this.lease=null,await c.dispose().catch(()=>{})}throw this.emitStatus("failed","上下文压缩失败",n instanceof Error?n.message:String(n)),n}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}const i=l(r)??{};return{providerSessionId:o||this.providerSessionId||"",contextUsage:k(i.contextUsage),maintenance:l(i.maintenance)??{},durationMs:Date.now()-t}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const t=C(),o=await b(),r=await y.acquire({providerId:"codex-acp",cwd:e,providerSessionId:this.providerSessionId,runtimeIdentity:o?.runtimeIdentity||"default",env:v(o),command:t.command,args:t.args,onSessionUpdate:i=>this.handleSessionUpdate(i),onClientRequest:async(i,n)=>{if(i==="session/request_permission")return this.requestPermission(n);if(i==="elicitation/create"||i==="session/request_user_input")return this.requestUserInput(n);throw new Error(`Unsupported Codex ACP client request: ${i}`)}});try{return await A(r,o),r}catch(i){throw await r.dispose().catch(()=>{}),i}}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,t){const o=e.client,r=x(t);if(e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.sessionResponse=e.sessionResponse,e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","Codex ACP 会话恢复中","session/load");const c=await o.loadSession({sessionId:this.providerSessionId,cwd:t.cwd,config:r},6e4);this.sessionResponse=l(c);const a=h(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),a}catch(c){if(t.requireSessionResume){const a=c instanceof Error?c.message:String(c);throw new Error(`无法恢复导入的 Codex ACP Session ${this.providerSessionId}:${a}`)}this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const i=await o.newSession({cwd:t.cwd,config:r},12e4);this.sessionResponse=l(i);const n=h(i);if(!n)throw new Error("Codex ACP session/new did not return sessionId");return this.providerSessionId=n,e.setProviderSession({providerSessionId:n,sessionResponse:this.sessionResponse}),n}async applyConfig(e,t,o){o.model&&await e.setSessionConfigOption({sessionId:t,configId:"model",value:o.model},6e4).catch(()=>{});const r=g(o.mode);r&&await e.setSessionConfigOption({sessionId:t,configId:"approvalPolicy",value:r},6e4).catch(()=>{});const i=f(o.mode);i&&await e.setSessionConfigOption({sessionId:t,configId:"sandbox",value:i},6e4).catch(()=>{});for(const[n,c]of Object.entries(o.configOptionValues??{}))["model","mode","sandbox","approvalPolicy"].includes(n)||await e.setSessionConfigOption({sessionId:t,configId:n,value:c},6e4).catch(()=>{})}handleSessionUpdate(e){const t=q(e),o=String(t?.update.sessionUpdate||""),r=D(e);if(!r&&H(o))this.performanceTracker?.recordEvent(),this.usageLoopDetector?.recordMeaningfulEvent();else if(!r&&o==="aca_codex_raw_response_usage"){const c=F(e),a=c?this.usageLoopDetector?.recordUsage(c):null;a&&this.usagePatternReport?.(a)}else if(!r&&o==="usage_update"){const c=j(e),a=c?this.usageLoopDetector?.recordUsage(c):null;a&&this.usagePatternReport?.(a)}this.updates.push({method:"session/update",params:e});const i=U(e);i&&(i.type==="agent_message_chunk"&&!r&&(this.content+=i.text??""),this.updateCallback?.(i));const n=E(e);n&&this.emitStatus(n.phase,n.label,n.detail,n.updateType)}startSlowStatusTimer(){const e=I().slowEventThresholdMs,t=setInterval(()=>{const o=this.performanceTracker,r=Date.now();if(!o?.shouldReportSlow(r,e))return;const i=o.snapshot(r),n=Math.max(1,Math.round(i.silentForMs/6e4));this.emitStatus("thinking","模型长时间处理中",`已 ${n} 分钟没有收到新的 ACP 事件`,"aca.performance.slow")},Math.min(3e4,Math.max(1e3,Math.floor(e/4))));return t.unref(),t}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("Codex ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}async promptWithAbort(e,t){return w({signal:t.signal,cancelledMessage:"Codex ACP prompt cancelled",startRequest:()=>e.prompt({sessionId:t.sessionId,prompt:t.prompt},t.timeoutMs),onAbort:async()=>{e.cancel(t.sessionId),await this.lease?.dispose()}})}async compactWithAbort(e,t){return w({signal:t.signal,cancelledMessage:"Codex ACP 上下文压缩已取消",startRequest:()=>e.compactSession({sessionId:t.sessionId,allowRollover:t.allowRollover,timeoutMs:t.timeoutMs},t.timeoutMs),onAbort:async()=>{e.cancel(t.sessionId),await this.lease?.dispose()}})}async requestPermission(e){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=t.request&&typeof t.request=="object"&&!Array.isArray(t.request)?t.request:t,i=(Array.isArray(o.options)?o.options:[]).map((n,c)=>{const a=n&&typeof n=="object"&&!Array.isArray(n)?n:{};return{optionId:String(a.optionId??a.id??c),kind:String(a.kind??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.emitStatus("requestPermission","等待授权",W(o),"session/request_permission"),this.permissionCallback({requestId:String(o.requestId??o.id??`codex-acp-permission-${Date.now()}`),params:e,options:i})}async requestUserInput(e){if(!this.userInputCallback)return{outcome:{outcome:"cancelled"}};const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=t.request&&typeof t.request=="object"&&!Array.isArray(t.request)?t.request:t;return this.emitStatus("requestPermission","等待输入",B(o),"elicitation/create"),this.userInputCallback({requestId:String(o.requestId??o.id??`codex-acp-input-${Date.now()}`),prompt:String(o.prompt??o.message??o.question??""),params:e,...typeof o.defaultValue=="string"?{defaultValue:o.defaultValue}:{}})}emitStatus(e,t,o,r){const i={phase:e,label:t,...o?{detail:o}:{},...r?{updateType:r}:{},atMs:Date.now()},n=this.statusTimeline[this.statusTimeline.length-1];n&&n.phase===i.phase&&n.label===i.label&&n.detail===i.detail&&n.updateType===i.updateType||(this.statusTimeline.push(i),this.statusCallback?.(i))}releaseLease(){this.lease?.release(),this.lease=null}}const $=new Set(["agent_message_chunk","agent_progress_chunk","agent_thought_chunk","tool_call","tool_call_update","plan","plan_update","plan_removed","aca_context_maintenance"]);function H(s){return $.has(s)}async function A(s,e){s.runtimeConfigured||(await s.client.configureRuntime({codexProvider:e?{baseUrl:e.baseUrl,apiKey:e.apiKey,revision:e.revision}:null}),s.markRuntimeConfigured())}function v(s){return s?{OPENAI_API_KEY:s.apiKey,OPENAI_BASE_URL:s.baseUrl}:{}}function V(s,e){if(e?.aborted)return!0;const t=s instanceof Error?s.message:String(s||"");return/compact.*timed out|request timed out.*compact|adapter closed|aborted|cancelled/i.test(t)}function h(s){if(!s||typeof s!="object"||Array.isArray(s))return null;const e=s.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function l(s){return s&&typeof s=="object"&&!Array.isArray(s)?s:null}function f(s){const e=String(s||"").trim();return e?e==="read-only"?"read-only":["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"danger-full-access":"workspace-write":null}function g(s){const e=String(s||"").trim();return e?["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"never":e==="acceptEdits"||e==="accept-edits"?"on-failure":"on-request":null}function x(s){return{...s.model?{model:s.model}:{},...g(s.mode)?{approvalPolicy:g(s.mode)}:{},...f(s.mode)?{sandbox:f(s.mode)}:{},...s.configOptionValues??{}}}function W(s){const e=s.params&&typeof s.params=="object"&&!Array.isArray(s.params)?s.params:s;for(const t of["command","cwd","reason","grantRoot","method"]){const o=e[t];if(typeof o=="string"&&o.trim())return P(o)}}function B(s){for(const e of["prompt","message","question","title"]){const t=s[e];if(typeof t=="string"&&t.trim())return P(t)}}function P(s){const e=s.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function K(){const s=Number.parseInt(process.env.ACA_CODEX_ACP_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(s)&&s>=3e4?s:360*60*1e3}function X(s){const e=Number.isInteger(s)?Number(s):Number.parseInt(process.env.ACA_CODEX_ACP_COMPACT_TIMEOUT_MS??"",10);return Number.isFinite(e)&&e>=3e4?Math.min(e,6e5):12e4}function _(s){if(!s||typeof s!="object"||Array.isArray(s))return null;const e=s;return typeof e.sessionId=="string"&&e.sessionId.trim()?e.sessionId:null}function G(s){const e=l(s),t=l(e?._meta);return k(t?.acaContextUsage)}function k(s){const e=l(s);if(!e)return null;const t=m(e.contextWindow),o=m(e.usedTokens),r=m(e.inputTokens),i=String(e.state||"unknown"),n=["active","compacted","new_thread"].includes(i)?i:"unknown";return{usedTokens:o,inputTokens:r,contextWindow:t,ratio:t>0?Math.max(0,m(e.ratio)||o/t):0,observedAtMs:m(e.observedAtMs)||Date.now(),state:n,maintenanceAction:typeof e.maintenanceAction=="string"?e.maintenanceAction:null}}function m(s){return typeof s=="number"&&Number.isFinite(s)&&s>=0?s:0}export{ie as CodexAcpProvider,z as codexAcpCapabilities};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{codexAcpSessionUpdatesFromNotification as k}from"../codex/events.js";function P(t){const n=o(t),d=o(n.thread),e=o(n.initialTurnsPage),l=[...f(d,"turns"),...f(e,"data")],a=[];for(const x of l){const m=o(x);if(i(m,"status")==="inProgress")continue;const g=i(m,"id");for(const _ of f(m,"items")){const r=o(_),p=i(r,"id"),c=i(r,"type");if(!p||!c||c==="userMessage"||c==="hookPrompt")continue;if(c==="agentMessage"){const u=i(r,"text"),s=i(r,"phase");if(!u||s&&s!=="commentary"&&s!=="final_answer")continue;a.push({itemId:p,sourceTurnId:g,update:h(s==="commentary"?"agent_progress_chunk":"agent_message_chunk",u)});continue}if(c==="reasoning"){const u=f(r,"summary").filter(s=>typeof s=="string").join(`
|
|
2
|
+
|
|
3
|
+
`).trim();u&&a.push({itemId:p,sourceTurnId:g,update:h("agent_thought_chunk",u)});continue}const y=k("item/completed",{item:r})[0];y&&a.push({itemId:p,sourceTurnId:g,update:y})}}return a}function h(t,n){return{sessionUpdate:t,content:{type:"text",text:n}}}function i(t,n){const e=o(t)[n];return typeof e=="string"?e:""}function f(t,n){const e=o(t)[n];return Array.isArray(e)?e:[]}function o(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}export{P as completedSubtaskHistoryUpdates};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
class S{routes=new Map;reset(){this.routes.clear()}routeFor(t){return t?this.routes.get(t)??null:null}routesForSubscription(){return[...this.routes.values()]}restoreFromSessionSnapshot(t,e){const n=i(t),o=i(n.thread),s=d(o,"id")||e,a=i(n.initialTurnsPage),c=[...I(o,"turns"),...I(a,"data")];let l=0;for(const p of c){const y=i(p);for(const h of I(y,"items"))l+=this.observe({threadId:s,item:h},e)}return l}observe(t,e){const n=i(t),o=i(n.item);if(d(o,"type")==="subAgentActivity")return this.observeSubAgentActivity(o,d(n,"threadId"),e);if(!b(o))return 0;const s=d(o,"id");if(!s)return 0;const a=d(o,"senderThreadId")||d(n,"threadId"),c=this.routeFor(a||null),l=c?.parentToolCallId||s,p=Math.min(8,(c?.depth??0)+1),y=g(o);let h=0;for(const u of y)!u||u===e||u===a||this.routes.has(u)||(this.routes.set(u,{parentToolCallId:l,sourceThreadId:u,depth:p}),h+=1);return h}observeSubAgentActivity(t,e,n){if(d(t,"kind")!=="started")return 0;const o=d(t,"agentThreadId"),s=this.routeFor(e||null),a=s?.parentToolCallId||d(t,"id"),c=Math.min(8,(s?.depth??0)+1);return!o||!a||o===n||this.routes.has(o)?0:(this.routes.set(o,{parentToolCallId:a,sourceThreadId:o,depth:c}),1)}}function g(r){const t=i(r),e=new Set;f(e,t.newThreadId),f(e,t.receiverThreadId),m(e,t.receiverThreadIds);const n=t.agentsStates;if(Array.isArray(n))for(const o of n)T(e,o);else{const o=i(n);for(const[s,a]of Object.entries(o))T(e,a),A(s)&&e.add(s)}return[...e]}function b(r){const t=d(i(r),"type");return t==="collabAgentToolCall"||t==="collabToolCall"}function T(r,t){const e=i(t);for(const n of["threadId","thread_id","receiverThreadId","newThreadId"])f(r,e[n])}function f(r,t){typeof t=="string"&&t.trim()&&r.add(t.trim())}function m(r,t){if(Array.isArray(t))for(const e of t)f(r,e)}function I(r,t){const e=r[t];return Array.isArray(e)?e:[]}function A(r){return r.length<8?!1:!["pending","running","completed","failed","cancelled","canceled"].includes(r.toLowerCase())}function i(r){return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}function d(r,t){const e=r[t];return typeof e=="string"?e:""}export{S as CodexSubtaskRouter,g as collaborationChildThreadIds,b as isCollaborationItem};
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const o="0.1.
|
|
1
|
+
const o="0.1.37";export{o as AICA_VERSION};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuandc/aica",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "AICA remote Agent worker",
|
|
5
5
|
"author": "yuandc",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"worker"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@openai/codex": "0.151.0",
|
|
29
30
|
"chalk": "^5.4.1",
|
|
30
31
|
"commander": "^12.1.0",
|
|
31
32
|
"diff": "^9.0.0",
|