@messenger-agent/claude-agent 0.43.0 → 0.43.1-alpha.1
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/routes/chat.js +8 -8
- package/dist/schemas.d.ts +4 -0
- package/dist/schemas.js +1 -1
- package/package.json +2 -2
package/dist/routes/chat.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{randomUUID as
|
|
2
|
-
`).trim();if(!
|
|
3
|
-
`);if(Array.isArray(e.answers))return e.answers.map(n=>{if(typeof n=="string")return n;if(
|
|
4
|
-
`)}return JSON.stringify(e)}function
|
|
5
|
-
`)}return
|
|
6
|
-
`)}function wn(e){return!!(e&&e.state==="output-available"&&(e.toolName==="AskUserQuestion"||e.toolName==="ask_user_question"))}function yn(e){return!!(e&&e.state==="approval-responded")}async function vn(e,n){return e?e.state==="approval-responded"?e.approval.reason??"":et(e.output):nn(n)}function kn(e,n){return Tt(m,e,n)}function gn(e){return e==="AskUserQuestion"}function In(e){return e==="ExitPlanMode"}function Cn(e){return e==="Agent"||e==="Task"}function Tn(e){const n="subagent_type"in e?e.subagent_type:void 0,r="parent_tool_use_id"in e?e.parent_tool_use_id:void 0;return!!n||!!r}function hn(e){return"session_id"in e?e.session_id:void 0}function _n(e){return e.subtype==="success"&&e.origin?.kind==="task-notification"&&e.num_turns===0&&e.result===""&&e.usage.input_tokens===0&&e.usage.output_tokens===0&&e.usage.cache_creation_input_tokens===0&&e.usage.cache_read_input_tokens===0&&Object.keys(e.modelUsage).length===0}function b(e,n){return e?.get(n)??void 0}function bn(e){const n=b(e,"X-Matrix-Room-Id")?.trim(),r=b(e,"X-Matrix-Thread-ID")?.trim();return n&&r?`${n}/${r}`:void 0}function xn(e){const n=b(e,"X-Matrix-Room-Id")?.trim(),r=b(e,"X-Matrix-Event-ID")?.trim(),l=b(e,"X-Matrix-Thread-ID")?.trim();if(!(!n||!r))return{roomId:n,eventId:r,...l?{threadRootEventId:l}:null}}se.post("/v1/chat/:conversation_id/cancel",e=>{const n=e.req.param("conversation_id");return Sn(n)?e.json({success:!0}):e.json({error:Zt(n)},404)});function Sn(e){return J.cancel(e)}se.get("/admin/status",e=>{const n=Ge().map(l=>({conversationId:l.conversationId,toolCallId:l.toolCallId,toolName:l.toolName,kind:l.kind,approveId:l.kind==="approval"?l.approveId:void 0,since:l.createdAt,agentMode:l.agentMode,model:l.model})),r=Yt();return e.json({activeTaskCount:r.active,waitingClientToolCount:n.length,clientToolWaits:n})});async function ot({body:e,headers:n}){const r=b(n,"X-Matrix-Workdir"),l=b(n,"X-Matrix-Workspace-ID"),p=bn(n),V=xn(n);let A,Y;try{A=kn(l,r),Y=ht(m,l)}catch(x){throw new F(400,x instanceof Error?x.message:"Invalid workspace")}if(r&&!wt(A))throw new F(400,`Workdir not found: ${A}`);if(yt(A,{recursive:!0}),e.fork&&!("sessionId"in e.fork))throw new F(400,"Claude fork requires sessionId and messageId");const Z=e.fork&&"sessionId"in e.fork?e.fork:void 0,k=on(e.message.parts),i=k&&(wn(k)||yn(k))?St(k.toolCallId):e.conversationId?xt(e.conversationId):void 0,g=i?P.get(i.conversationId):void 0,M=await vn(k,e.message.parts),v=k?void 0:i,W=i&&!g?i.conversationId:e.conversationId,le=b(n,"X-Elevo-LLM-Binding")?.trim()||void 0;let D=Z?void 0:J.get(W);const de=D?.llmProxyBinding??Ht(W);if(le&&de&&le!==de)throw new F(409,"LLM proxy binding does not match the existing conversation");const N=de??le;if(D&&N&&!D.llmProxyBinding){if(D.hasActiveOwner())throw new F(409,"Cannot attach an LLM proxy binding while the conversation is active");D.abort(),D=void 0}const Se=e.model||m.claude.defaultModel,Ae=e.effort,ee=i&&!g?i.workdir:A,q=i?.kind==="approval"&&xe(i,k,M).approved?"default":i?.agentMode?Ze(i.agentMode):Ze(b(n,"X-Matrix-Agent-Mode")),B=i&&!g?i.model??Se:Se,H=i&&!g?i.effort??Ae:Ae;return{run:async(x,X)=>{if(i&&g&&!v){const t={};z.add(t);let a=!1,s,o;const w=new Promise(y=>{o=y});let u=0;const _=async()=>{a||(a=!0,u+=1,s&&(clearTimeout(s),s=void 0),await x.writeDone(),o())},j=()=>{const y=++u;a||(s=setTimeout(()=>{s=void 0,!(a||y!==u)&&x.writeData({type:"heartbeat"}).catch(()=>{}).finally(()=>{!a&&y===u&&j()})},6e4))},ie=async y=>{s&&clearTimeout(s),await x.writeData(y),j()},He=async y=>{a||await ie(y)};try{if(await g.attach({writeData:He,writeDone:_}),j(),i.kind==="ask_user")Je(i.toolCallId,dn(i.input,k,M));else{const y=xe(i,k,M);y.approved&&await J.get(i.conversationId)?.setPermissionMode(Ut()),Qe(i.toolCallId,y)}await Promise.race([g.done,w]),a||await _()}catch(y){f.error("Claude live ask continuation failed:",y),await He({type:"error",errorText:y instanceof Error?y.message:String(y)}),await _()}finally{u+=1,s&&clearTimeout(s),z.delete(t)}return}const Me={};z.add(Me);const te=W??Xe();let c=te,Ee=!1,Pe=!1,ue=!1,U=new Set,L=new Set;const ce=new Map,pe=new Map,fe=new Map;let me=!1,we=!1,ye,ve="stop",ke,ge,$,De=new Set,Ne=!1,T;const O=Rt();let ne=!1,at=0,R=!1;const Ie=new Set;let I=!1,oe,Ce=!1,E,K;const rt=new Promise(t=>{K=t});let Oe;const it=new Promise(t=>{Oe=t}),Re=()=>{T=setTimeout(()=>{f.debug("Claude chat heartbeat",{conversationId:c,paused:R,downstreamClosed:I}),d({type:"heartbeat"}).catch(()=>{})},6e4)},st=async t=>{T&&clearTimeout(T),await x.writeData(t),I||Re()};oe={writeData:async t=>{I||await st(t)},writeDone:async()=>{I||(I=!0,T&&(clearTimeout(T),T=void 0),await x.writeDone())}};const d=async t=>{I||await oe.writeData(t)},je=async()=>{I||(await oe.writeDone(),I=!0)},lt=async()=>{$||($={activityId:Xe()},await d({type:"data",kind:"compact",data:{phase:"start",activityId:$.activityId}}))},Te=async(t,a={})=>{if(!$)return;const s=$;$=void 0,await d({type:"data",kind:"compact",data:{phase:"end",activityId:s.activityId,status:t,...a}})},Q=async t=>{if(!(ue||I)){ue=!0;for(const a of U)await d({type:"text-end",id:a});U=new Set;for(const a of L)await d({type:"reasoning-end",id:a});L=new Set,Pe&&(t==="stop"&&ke&&await d({type:"data",kind:"token_usage",data:ke}),await d({type:"finish-step"})),await d({type:"finish",finishReason:t}),await je()}},dt=async()=>{for(const t of U)await d({type:"text-end",id:t});U=new Set},ut=async()=>{for(const t of L)await d({type:"reasoning-end",id:t});L=new Set},ae=async()=>{await dt(),await ut()},S=async()=>{if(!ne)return;ne=!1,O.clearDirty(),await ae();const t=`todo-${te}-${at++}`;await d({type:"tool-input-available",toolCallId:t,toolName:"TodoWrite",input:O.snapshot()}),await d({type:"tool-output-available",toolCallId:t,output:"Task updated"})},qe=async(t,a,s,o)=>{if(Ie.has(t)){f.warn("Claude client tool pause already registered",{conversationId:c,toolCallId:t,toolName:a});return}f.info("Claude client tool pause requested",{conversationId:c,toolCallId:t,toolName:a,hasApproval:!!o,...G(s)}),Ie.add(t),R=!0,X?.removeEventListener("abort",re),o&&(f.info("Claude emitting tool approval request",{conversationId:c,toolCallId:t,approveId:o.approveId,...G(o.input)}),await d({type:"tool-approval-request",toolCallId:t,approveId:o.approveId,...pn(o.input)})),await je(),f.info("Claude client tool stream paused",{conversationId:c,toolCallId:t,toolName:a,timeoutMs:m.claude.askTimeoutMs}),E=setTimeout(()=>{f.warn(`Claude ${a} timed out after ${m.claude.askTimeoutMs}ms`,{conversationId:c,toolCallId:t}),P.delete(c),h.abort(),K()},m.claude.askTimeoutMs),E.unref?.(),Oe()},Be=async t=>{U.has(t)||(U.add(t),await d({type:"text-start",id:t}))},Ue=async t=>{L.has(t)||(L.add(t),await d({type:"reasoning-start",id:t}))},ct=t=>{if(t===c)return;const a=c;c=t,J.bind(h,t),Xt(a,t,N),Et(a,t);const s=P.get(a);s&&(P.delete(a),P.set(t,s))},Le=async t=>{Ee||(Ee=!0,ct(t),Ce||(Ce=!0,P.set(t,{attach:async a=>{E&&(clearTimeout(E),E=void 0),oe=a,I=!1,R=!1,f.info("Claude live turn sink attached",{conversationId:c})},done:rt,dispose:()=>{E&&(clearTimeout(E),E=void 0)}})),await d({type:"start",messageMetadata:{conversationId:t,threadId:t}}),await d({type:"start-step"}),Pe=!0)},$e=()=>{Ce&&(P.get(c)?.dispose(),P.delete(c));for(const t of Ie)ze(t,{rejectWait:!0})},pt=async()=>(await Q(ve),$e(),K(),!0);Re();const ft=async(t,a,s)=>{const{toolUseID:o}=s;if(f.info("Claude canUseTool invoked",{conversationId:c,toolName:t,toolCallId:o,agentMode:q,...G(a)}),gn(t)){At({conversationId:c,toolCallId:o,workdir:ee,model:B,effort:H,agentMode:q,toolName:"AskUserQuestion",input:a}),await qe(o,"AskUserQuestion",a);const w=await Dt(o);return w?"interrupted"in w?{behavior:"deny",message:"Question interrupted by text response",interrupt:!0,toolUseID:o}:{behavior:"allow",updatedInput:{...a,questions:tt(a),answers:w.answers},toolUseID:o}:{behavior:"deny",message:`${t} requires user input; session will resume after user responds.`,toolUseID:o}}if(In(t)){const w=Mt({conversationId:c,toolCallId:o,workdir:ee,model:B,effort:H,agentMode:q,toolName:"ExitPlanMode",input:a});f.info("Claude ExitPlanMode approval persisted",{conversationId:c,toolCallId:o,approveId:w.approveId,...G(a)}),await qe(o,"ExitPlanMode",a,w);const u=await Pt(o);return f.info("Claude ExitPlanMode approval received",{conversationId:c,toolCallId:o,approved:u&&"approved"in u?u.approved:void 0,interrupted:!!(u&&"interrupted"in u)}),u&&"interrupted"in u?{behavior:"deny",message:"Approval interrupted by text response",interrupt:!0,toolUseID:o,decisionClassification:"user_reject"}:u?.approved?{behavior:"allow",updatedInput:{...a,approval:u},toolUseID:o}:{behavior:"deny",message:u?.reason||"Denied by user",toolUseID:o,decisionClassification:"user_reject"}}return Cn(t)?{behavior:"allow",updatedInput:{...a,model:B},toolUseID:o}:{behavior:"allow",toolUseID:o}},mt=async t=>{if(Tn(t))return!1;const a=hn(t);if(a&&(await Le(a),O.setSessionId(a)),t.type==="system"&&t.subtype==="background_tasks_changed")return De=new Set(t.tasks.map(s=>s.task_id)),!1;if(R)return!1;switch(t.type){case"system":return t.subtype==="status"?(t.status==="compacting"&&await lt(),t.compact_result==="success"?await Te("completed"):t.compact_result==="failed"&&await Te("failed",{error:t.compact_error})):t.subtype==="compact_boundary"&&await Te("completed",{trigger:t.compact_metadata.trigger,preTokens:t.compact_metadata.pre_tokens,postTokens:t.compact_metadata.post_tokens,durationMs:t.compact_metadata.duration_ms}),!1;case"stream_event":{const s=t.event;switch(s.type){case"message_start":{ye=s.message.id,me=!1,we=!1;break}case"content_block_start":{const o=`${ye??t.session_id}:${s.index}`;s.content_block.type==="text"?(await S(),ce.set(o,t.uuid),await Be(t.uuid)):s.content_block.type==="thinking"&&(await S(),pe.set(o,t.uuid),await Ue(t.uuid));break}case"content_block_delta":{const o=s.delta,w=`${ye??t.session_id}:${s.index}`;if(o.type==="text_delta"){await S(),me=!0;const u=ce.get(w);if(!u){f.warn("Ignoring Claude text delta without content_block_start",{conversationId:c,blockKey:w});break}await d({type:"text-delta",id:u,delta:o.text})}else if(o.type==="thinking_delta"){await S(),we=!0;const u=pe.get(w);if(!u){f.warn("Ignoring Claude reasoning delta without content_block_start",{conversationId:c,blockKey:w});break}await d({type:"reasoning-delta",id:u,delta:o.thinking})}break}case"content_block_stop":break}return!1}case"assistant":{ge=$t(t.message)??ge,t.session_id&&t.uuid&&await d({type:"data",kind:"agent_session",data:{agentType:"claude",sessionId:t.session_id,messageId:t.uuid}});const s=t.message.content;if(typeof s=="string")break;for(const o of s)switch(o.type){case"thinking":{if(we||!o.thinking)break;await S(),await Ue(t.uuid),await d({type:"reasoning-delta",id:t.uuid,delta:o.thinking});break}case"text":{if(me||!o.text)break;await S(),await Be(t.uuid),await d({type:"text-delta",id:t.uuid,delta:o.text});break}case"tool_use":{if(await ae(),fe.set(o.id,o.name),(o.name==="EnterPlanMode"||o.name==="ExitPlanMode")&&f.info("Claude plan tool_use received",{conversationId:c,toolCallId:o.id,toolName:o.name,...G(o.input)}),O.isTaskTool(o.name)){O.applyToolUse(o.id,o.name,o.input)&&(ne=!0);break}await S(),await ae(),await d({type:"tool-input-available",toolCallId:o.id,toolName:o.name,input:o.input});break}}return await ae(),ce.clear(),pe.clear(),!1}case"user":{const s=t.message.content;if(typeof s=="string")break;const o=s.filter(u=>u.type==="tool_result"),w=o.length===1?Vt(t.tool_use_result):void 0;for(const u of o){const _=u.tool_use_id,j=u.content;if(O.isTaskToolCall(_)){O.applyToolResult(_,j)&&(ne=!0);continue}if(await S(),u.is_error===!0)await d({type:"tool-output-error",toolCallId:_,errorText:an(j)});else{const ie=fe.get(_);await d({type:"tool-output-available",toolCallId:_,output:ie&&Gt(ie)&&w!==void 0?w:j})}fe.delete(_)}return!1}case"result":{if(De.size>0)return t.origin?.kind!=="task-notification"&&(Ne=!0),!1;if(_n(t)&&!Ne)return!1;ve=t.subtype==="success"||h.wasCancelled?"stop":"error";const s=Ft(t,ge);return ke=ve==="stop"?s:void 0,await S(),t.subtype!=="success"&&!h.wasCancelled&&await d({type:"error",errorText:t.errors?.filter(o=>o.trim()).join(`
|
|
7
|
-
`)||`Claude Code failed: ${t.subtype}`}),
|
|
8
|
-
`)}:null,CLAUDE_AGENT_SDK_CLIENT_APP:"coding-agent/claude-agent"}})});
|
|
1
|
+
import{randomUUID as Ke}from"node:crypto";import{existsSync as yt,mkdirSync as vt}from"node:fs";import{join as kt}from"node:path";import{Hono as gt}from"hono";import{HTTPException as _e}from"hono/http-exception";import{zValidator as It}from"@hono/zod-validator";import{streamSSE as Ct}from"hono/streaming";import{loadClaudePlatformInstructions as ht}from"../platform-instructions.js";import{logger as f}from"@messenger-agent/shared/logger";import{appConfig as m}from"../config.js";import{resolveAgentWorkdir as Tt,resolveAgentWorkspaceRoot as _t,workspaceIdFromHeader as bt}from"@messenger-agent/shared/agent-workspaces";import{isManagedTaskToolName as Qe}from"@messenger-agent/shared/managed-task-tools";import{saveUploadedFilePart as xt}from"@messenger-agent/shared/uploaded-files";import{WakeupIdempotencyStore as St}from"@messenger-agent/shared/wakeup-idempotency";import{answerPendingApproval as ze,answerPendingAsk as Je,deletePendingClientTool as Ge,findPendingClientToolByConversation as At,listPendingClientTools as Ve,loadPendingClientTool as Mt,savePendingAsk as Et,savePendingApproval as Pt,updatePendingAskConversation as Dt,waitPendingApproval as Nt,waitPendingAsk as Ot}from"../pending-asks.js";import{AgentAnswerToolPartSchema as Rt,ChatBodySchema as jt}from"../schemas.js";import{createTaskAggregator as qt}from"../task-aggregator.js";import{createManagedTaskMcpServer as Bt,MANAGED_TASK_MCP_SERVER_NAME as Ye}from"../managed-task-mcp.js";import{createScheduleMcpServer as Ut,SCHEDULE_MCP_SERVER_NAME as Lt}from"../schedule-mcp.js";import{claudeExecutionPermissionMode as $t,claudePermissionOptions as Ft}from"../permission.js";import{claudeContextSnapshot as Wt,claudeTokenUsage as Ht}from"../token-usage.js";import{SessionManager as Xt}from"../session-manager.js";import{getLlmProxyBinding as Kt,moveLlmProxyBinding as Qt,setLlmProxyBinding as zt}from"../llm-proxy-bindings.js";const le=new gt;let Jt;function be(){return Jt??=new St(kt(m.dataDir,"wakeup-idempotency.sqlite"))}const z=new Xt(()=>m.claude.sessionIdleTimeoutMs??36e5),Gt=ht(void 0,m.schedule?.enabled===!0),J=new Set;function Ze(){return{...m.claude.apiKey?{ANTHROPIC_API_KEY:m.claude.apiKey,ANTHROPIC_AUTH_TOKEN:""}:null,...m.claude.baseUrl?{ANTHROPIC_BASE_URL:m.claude.baseUrl}:null}}function Vt(){const e=Ze();return Object.keys(e).length>0?{env:e}:void 0}function Yt(e){if(Qe(e))return!0;const n=`mcp__${Ye}__`;return e.startsWith(n)&&Qe(e.slice(n.length))}function Zt(e){if(!e||typeof e!="object"||Array.isArray(e))return;const n=e.structuredContent;return n&&typeof n=="object"&&!Array.isArray(n)?n:void 0}function en(){const e=new Set(Ve().map(n=>n.conversationId));return{active:J.size,waiting:e.size}}class F extends Error{status;constructor(n,r){super(r),this.status=n,this.name="ChatRequestError"}}const P=new Map;function et(e){return e?.trim().toLowerCase()==="plan"?"plan":"default"}function tn(e){return{type:"not_found_error",code:"conversation_not_found",message:`Conversation not found or already completed: ${e}`,param:"conversation_id"}}function h(e){return!!(e&&typeof e=="object")}function nn(e){return e.type==="file"&&"mediaType"in e&&typeof e.mediaType=="string"&&"url"in e&&typeof e.url=="string"&&(!("attachmentId"in e)||e.attachmentId===void 0||typeof e.attachmentId=="string")&&(!("originalFilename"in e)||e.originalFilename===void 0||typeof e.originalFilename=="string")&&(!("filename"in e)||e.filename===void 0||typeof e.filename=="string")}async function on(e,n){if(e.type==="text"&&typeof e.text=="string")return e.text;if(nn(e))return xt(e,m.fileUploads.tempDir,n);if(e.type!=="step-start")throw new _e(400,{message:`Unsupported message part type: ${e.type}`})}async function an(e,n){const l=(await Promise.all(e.map(p=>on(p,n)))).filter(p=>!!(p&&p.trim().length>0)).join(`
|
|
2
|
+
`).trim();if(!l)throw new _e(400,{message:"No supported message content found"});return l}function rn(e){for(const n of e){const r=Rt.safeParse(n);if(r.success)return r.data}}function xe(e){if(typeof e=="string")return e;if(h(e)){if(typeof e.answer=="string")return e.answer;if(typeof e.text=="string")return e.text;if(h(e.answers))return Object.values(e.answers).map(n=>String(n)).join(`
|
|
3
|
+
`);if(Array.isArray(e.answers))return e.answers.map(n=>{if(typeof n=="string")return n;if(h(n)){if(typeof n.answer=="string")return n.answer;if(typeof n.text=="string")return n.text}return JSON.stringify(n)}).join(`
|
|
4
|
+
`)}return JSON.stringify(e)}function tt(e){if(h(e)&&h(e.answers)){const n=Object.entries(e.answers).map(([r,l])=>`- ${r}:${String(l)}`);if(n.length>0)return["User answered previous question:",...n].join(`
|
|
5
|
+
`)}return xe(e)}function sn(e){return typeof e=="string"?e:JSON.stringify(e)}function ln(e,n){return h(e)&&typeof e.question=="string"?e.question:`Question ${n+1}`}function nt(e){return h(e)&&Array.isArray(e.questions)?e.questions:[]}function dn(e,n){const r=nt(e);return h(n)&&h(n.answers)?Object.fromEntries(Object.entries(n.answers).map(([l,p])=>[l,String(p)])):r.length>0?Object.fromEntries(r.map((l,p)=>[ln(l,p),xe(n)])):{answer:xe(n)}}function un(e,n,r){return n&&n.state==="output-available"?n.output:{answers:r}}function cn(e,n,r){return n&&n.state==="output-available"?{answers:dn(e,n.output),output:n.output}:{answers:r}}function pn(e,n){return!e||e.state!=="output-available"?`User answered previous question: ${n}`:tt(e.output)}function fn(e){if(h(e)){if(typeof e.planContent=="string"&&e.planContent)return e.planContent;if(typeof e.plan=="string")return e.plan}return JSON.stringify(e)}function mn(e){if(!h(e))return{};const n=typeof e.planContent=="string"&&e.planContent?e.planContent:typeof e.plan=="string"&&e.plan?e.plan:void 0,r=typeof e.planFilePath=="string"&&e.planFilePath?e.planFilePath:void 0;return{...n?{plan:n}:null,...r?{planFilePath:r}:null}}function G(e){return h(e)?{inputKeys:Object.keys(e),planContentLength:typeof e.planContent=="string"?e.planContent.length:void 0,hasPlan:typeof e.plan=="string",hasPlanFilePath:typeof e.planFilePath=="string"}:{inputType:typeof e}}function wn(e){return{approved:!1,reason:e.trim()||void 0}}function ot(e,n,r){return n&&n.state==="approval-responded"?n.approval:{id:e.approveId,...wn(r)}}function Se(e,n,r){const l=ot(e,n,r);if(l.id!==e.approveId)throw new _e(400,{message:"Tool approval id does not match pending approval"});return{approved:l.approved,reason:l.reason}}function yn(e,n,r){const l=Se(e,n,r),p=[l.approved?`User approved tool ${e.toolName} plan:`:`User rejected tool ${e.toolName} plan:`,fn(e.input)];return l.reason&&p.push(`Reason: ${l.reason}`),p.join(`
|
|
6
|
+
`)}function vn(e){return!!(e&&e.state==="output-available"&&(e.toolName==="AskUserQuestion"||e.toolName==="ask_user_question"))}function kn(e){return!!(e&&e.state==="approval-responded")}async function gn(e,n,r){return e?e.state==="approval-responded"?e.approval.reason??"":tt(e.output):an(n,r)}function In(e,n){return Tt(m,e,n)}function Cn(e){return e==="AskUserQuestion"}function hn(e){return e==="ExitPlanMode"}function Tn(e){return e==="Agent"||e==="Task"}function _n(e){const n="subagent_type"in e?e.subagent_type:void 0,r="parent_tool_use_id"in e?e.parent_tool_use_id:void 0;return!!n||!!r}function bn(e){return"session_id"in e?e.session_id:void 0}function xn(e){return e.subtype==="success"&&e.origin?.kind==="task-notification"&&e.num_turns===0&&e.result===""&&e.usage.input_tokens===0&&e.usage.output_tokens===0&&e.usage.cache_creation_input_tokens===0&&e.usage.cache_read_input_tokens===0&&Object.keys(e.modelUsage).length===0}function x(e,n){return e?.get(n)??void 0}function Sn(e){const n=x(e,"X-Matrix-Room-Id")?.trim(),r=x(e,"X-Matrix-Thread-ID")?.trim();return n&&r?`${n}/${r}`:void 0}function An(e){const n=x(e,"X-Matrix-Room-Id")?.trim(),r=x(e,"X-Matrix-Event-ID")?.trim(),l=x(e,"X-Matrix-Thread-ID")?.trim();if(!(!n||!r))return{roomId:n,eventId:r,...l?{threadRootEventId:l}:null}}le.post("/v1/chat/:conversation_id/cancel",e=>{const n=e.req.param("conversation_id");return Mn(n)?e.json({success:!0}):e.json({error:tn(n)},404)});function Mn(e){return z.cancel(e)}le.get("/admin/status",e=>{const n=Ve().map(l=>({conversationId:l.conversationId,toolCallId:l.toolCallId,toolName:l.toolName,kind:l.kind,approveId:l.kind==="approval"?l.approveId:void 0,since:l.createdAt,agentMode:l.agentMode,model:l.model})),r=en();return e.json({activeTaskCount:r.active,waitingClientToolCount:n.length,clientToolWaits:n})});async function at({body:e,headers:n}){const r=x(n,"X-Matrix-Workdir"),l=x(n,"X-Matrix-Workspace-ID"),p=Sn(n),V=An(n);let A,Y,Z;try{const I=bt(l);if(!I)throw new Error("Missing workspace id");Z=I,A=In(Z,r),Y=_t(m,Z)}catch(I){throw new F(400,I instanceof Error?I.message:"Invalid workspace")}if(r&&!yt(A))throw new F(400,`Workdir not found: ${A}`);if(vt(A,{recursive:!0}),e.fork&&!("sessionId"in e.fork))throw new F(400,"Claude fork requires sessionId and messageId");const ee=e.fork&&"sessionId"in e.fork?e.fork:void 0,k=rn(e.message.parts),i=k&&(vn(k)||kn(k))?Mt(k.toolCallId):e.conversationId?At(e.conversationId):void 0,g=i?P.get(i.conversationId):void 0,M=await gn(k,e.message.parts,Z),v=k?void 0:i,W=i&&!g?i.conversationId:e.conversationId,de=x(n,"X-Elevo-LLM-Binding")?.trim()||void 0;let D=ee?void 0:z.get(W);const ue=D?.llmProxyBinding??Kt(W);if(de&&ue&&de!==ue)throw new F(409,"LLM proxy binding does not match the existing conversation");const N=ue??de;if(D&&N&&!D.llmProxyBinding){if(D.hasActiveOwner())throw new F(409,"Cannot attach an LLM proxy binding while the conversation is active");D.abort(),D=void 0}const Ae=e.model||m.claude.defaultModel,Me=e.effort,te=i&&!g?i.workdir:A,q=i?.kind==="approval"&&Se(i,k,M).approved?"default":i?.agentMode?et(i.agentMode):et(x(n,"X-Matrix-Agent-Mode")),B=i&&!g?i.model??Ae:Ae,H=i&&!g?i.effort??Me:Me;return{run:async(I,X)=>{if(i&&g&&!v){const t={};J.add(t);let a=!1,s,o;const w=new Promise(y=>{o=y});let u=0;const b=async()=>{a||(a=!0,u+=1,s&&(clearTimeout(s),s=void 0),await I.writeDone(),o())},j=()=>{const y=++u;a||(s=setTimeout(()=>{s=void 0,!(a||y!==u)&&I.writeData({type:"heartbeat"}).catch(()=>{}).finally(()=>{!a&&y===u&&j()})},6e4))},se=async y=>{s&&clearTimeout(s),await I.writeData(y),j()},Xe=async y=>{a||await se(y)};try{if(await g.attach({writeData:Xe,writeDone:b}),j(),i.kind==="ask_user")Je(i.toolCallId,cn(i.input,k,M));else{const y=Se(i,k,M);y.approved&&await z.get(i.conversationId)?.setPermissionMode($t()),ze(i.toolCallId,y)}await Promise.race([g.done,w]),a||await b()}catch(y){f.error("Claude live ask continuation failed:",y),await Xe({type:"error",errorText:y instanceof Error?y.message:String(y)}),await b()}finally{u+=1,s&&clearTimeout(s),J.delete(t)}return}const Ee={};J.add(Ee);const ne=W??Ke();let c=ne,Pe=!1,De=!1,ce=!1,U=new Set,L=new Set;const pe=new Map,fe=new Map,me=new Map;let we=!1,ye=!1,ve,ke="stop",ge,Ie,$,Ne=new Set,Oe=!1,T;const O=qt();let oe=!1,rt=0,R=!1;const Ce=new Set;let C=!1,ae,he=!1,E,K;const it=new Promise(t=>{K=t});let Re;const st=new Promise(t=>{Re=t}),je=()=>{T=setTimeout(()=>{f.debug("Claude chat heartbeat",{conversationId:c,paused:R,downstreamClosed:C}),d({type:"heartbeat"}).catch(()=>{})},6e4)},lt=async t=>{T&&clearTimeout(T),await I.writeData(t),C||je()};ae={writeData:async t=>{C||await lt(t)},writeDone:async()=>{C||(C=!0,T&&(clearTimeout(T),T=void 0),await I.writeDone())}};const d=async t=>{C||await ae.writeData(t)},qe=async()=>{C||(await ae.writeDone(),C=!0)},dt=async()=>{$||($={activityId:Ke()},await d({type:"data",kind:"compact",data:{phase:"start",activityId:$.activityId}}))},Te=async(t,a={})=>{if(!$)return;const s=$;$=void 0,await d({type:"data",kind:"compact",data:{phase:"end",activityId:s.activityId,status:t,...a}})},Q=async t=>{if(!(ce||C)){ce=!0;for(const a of U)await d({type:"text-end",id:a});U=new Set;for(const a of L)await d({type:"reasoning-end",id:a});L=new Set,De&&(t==="stop"&&ge&&await d({type:"data",kind:"token_usage",data:ge}),await d({type:"finish-step"})),await d({type:"finish",finishReason:t}),await qe()}},ut=async()=>{for(const t of U)await d({type:"text-end",id:t});U=new Set},ct=async()=>{for(const t of L)await d({type:"reasoning-end",id:t});L=new Set},re=async()=>{await ut(),await ct()},S=async()=>{if(!oe)return;oe=!1,O.clearDirty(),await re();const t=`todo-${ne}-${rt++}`;await d({type:"tool-input-available",toolCallId:t,toolName:"TodoWrite",input:O.snapshot()}),await d({type:"tool-output-available",toolCallId:t,output:"Task updated"})},Be=async(t,a,s,o)=>{if(Ce.has(t)){f.warn("Claude client tool pause already registered",{conversationId:c,toolCallId:t,toolName:a});return}f.info("Claude client tool pause requested",{conversationId:c,toolCallId:t,toolName:a,hasApproval:!!o,...G(s)}),Ce.add(t),R=!0,X?.removeEventListener("abort",ie),o&&(f.info("Claude emitting tool approval request",{conversationId:c,toolCallId:t,approveId:o.approveId,...G(o.input)}),await d({type:"tool-approval-request",toolCallId:t,approveId:o.approveId,...mn(o.input)})),await qe(),f.info("Claude client tool stream paused",{conversationId:c,toolCallId:t,toolName:a,timeoutMs:m.claude.askTimeoutMs}),E=setTimeout(()=>{f.warn(`Claude ${a} timed out after ${m.claude.askTimeoutMs}ms`,{conversationId:c,toolCallId:t}),P.delete(c),_.abort(),K()},m.claude.askTimeoutMs),E.unref?.(),Re()},Ue=async t=>{U.has(t)||(U.add(t),await d({type:"text-start",id:t}))},Le=async t=>{L.has(t)||(L.add(t),await d({type:"reasoning-start",id:t}))},pt=t=>{if(t===c)return;const a=c;c=t,z.bind(_,t),Qt(a,t,N),Dt(a,t);const s=P.get(a);s&&(P.delete(a),P.set(t,s))},$e=async t=>{Pe||(Pe=!0,pt(t),he||(he=!0,P.set(t,{attach:async a=>{E&&(clearTimeout(E),E=void 0),ae=a,C=!1,R=!1,f.info("Claude live turn sink attached",{conversationId:c})},done:it,dispose:()=>{E&&(clearTimeout(E),E=void 0)}})),await d({type:"start",messageMetadata:{conversationId:t,threadId:t}}),await d({type:"start-step"}),De=!0)},Fe=()=>{he&&(P.get(c)?.dispose(),P.delete(c));for(const t of Ce)Ge(t,{rejectWait:!0})},ft=async()=>(await Q(ke),Fe(),K(),!0);je();const mt=async(t,a,s)=>{const{toolUseID:o}=s;if(f.info("Claude canUseTool invoked",{conversationId:c,toolName:t,toolCallId:o,agentMode:q,...G(a)}),Cn(t)){Et({conversationId:c,toolCallId:o,workdir:te,model:B,effort:H,agentMode:q,toolName:"AskUserQuestion",input:a}),await Be(o,"AskUserQuestion",a);const w=await Ot(o);return w?"interrupted"in w?{behavior:"deny",message:"Question interrupted by text response",interrupt:!0,toolUseID:o}:{behavior:"allow",updatedInput:{...a,questions:nt(a),answers:w.answers},toolUseID:o}:{behavior:"deny",message:`${t} requires user input; session will resume after user responds.`,toolUseID:o}}if(hn(t)){const w=Pt({conversationId:c,toolCallId:o,workdir:te,model:B,effort:H,agentMode:q,toolName:"ExitPlanMode",input:a});f.info("Claude ExitPlanMode approval persisted",{conversationId:c,toolCallId:o,approveId:w.approveId,...G(a)}),await Be(o,"ExitPlanMode",a,w);const u=await Nt(o);return f.info("Claude ExitPlanMode approval received",{conversationId:c,toolCallId:o,approved:u&&"approved"in u?u.approved:void 0,interrupted:!!(u&&"interrupted"in u)}),u&&"interrupted"in u?{behavior:"deny",message:"Approval interrupted by text response",interrupt:!0,toolUseID:o,decisionClassification:"user_reject"}:u?.approved?{behavior:"allow",updatedInput:{...a,approval:u},toolUseID:o}:{behavior:"deny",message:u?.reason||"Denied by user",toolUseID:o,decisionClassification:"user_reject"}}return Tn(t)?{behavior:"allow",updatedInput:{...a,model:B},toolUseID:o}:{behavior:"allow",toolUseID:o}},wt=async t=>{if(_n(t))return!1;const a=bn(t);if(a&&(await $e(a),O.setSessionId(a)),t.type==="system"&&t.subtype==="background_tasks_changed")return Ne=new Set(t.tasks.map(s=>s.task_id)),!1;if(R)return!1;switch(t.type){case"system":return t.subtype==="status"?(t.status==="compacting"&&await dt(),t.compact_result==="success"?await Te("completed"):t.compact_result==="failed"&&await Te("failed",{error:t.compact_error})):t.subtype==="compact_boundary"&&await Te("completed",{trigger:t.compact_metadata.trigger,preTokens:t.compact_metadata.pre_tokens,postTokens:t.compact_metadata.post_tokens,durationMs:t.compact_metadata.duration_ms}),!1;case"stream_event":{const s=t.event;switch(s.type){case"message_start":{ve=s.message.id,we=!1,ye=!1;break}case"content_block_start":{const o=`${ve??t.session_id}:${s.index}`;s.content_block.type==="text"?(await S(),pe.set(o,t.uuid),await Ue(t.uuid)):s.content_block.type==="thinking"&&(await S(),fe.set(o,t.uuid),await Le(t.uuid));break}case"content_block_delta":{const o=s.delta,w=`${ve??t.session_id}:${s.index}`;if(o.type==="text_delta"){await S(),we=!0;const u=pe.get(w);if(!u){f.warn("Ignoring Claude text delta without content_block_start",{conversationId:c,blockKey:w});break}await d({type:"text-delta",id:u,delta:o.text})}else if(o.type==="thinking_delta"){await S(),ye=!0;const u=fe.get(w);if(!u){f.warn("Ignoring Claude reasoning delta without content_block_start",{conversationId:c,blockKey:w});break}await d({type:"reasoning-delta",id:u,delta:o.thinking})}break}case"content_block_stop":break}return!1}case"assistant":{Ie=Wt(t.message)??Ie,t.session_id&&t.uuid&&await d({type:"data",kind:"agent_session",data:{agentType:"claude",sessionId:t.session_id,messageId:t.uuid}});const s=t.message.content;if(typeof s=="string")break;for(const o of s)switch(o.type){case"thinking":{if(ye||!o.thinking)break;await S(),await Le(t.uuid),await d({type:"reasoning-delta",id:t.uuid,delta:o.thinking});break}case"text":{if(we||!o.text)break;await S(),await Ue(t.uuid),await d({type:"text-delta",id:t.uuid,delta:o.text});break}case"tool_use":{if(await re(),me.set(o.id,o.name),(o.name==="EnterPlanMode"||o.name==="ExitPlanMode")&&f.info("Claude plan tool_use received",{conversationId:c,toolCallId:o.id,toolName:o.name,...G(o.input)}),O.isTaskTool(o.name)){O.applyToolUse(o.id,o.name,o.input)&&(oe=!0);break}await S(),await re(),await d({type:"tool-input-available",toolCallId:o.id,toolName:o.name,input:o.input});break}}return await re(),pe.clear(),fe.clear(),!1}case"user":{const s=t.message.content;if(typeof s=="string")break;const o=s.filter(u=>u.type==="tool_result"),w=o.length===1?Zt(t.tool_use_result):void 0;for(const u of o){const b=u.tool_use_id,j=u.content;if(O.isTaskToolCall(b)){O.applyToolResult(b,j)&&(oe=!0);continue}if(await S(),u.is_error===!0)await d({type:"tool-output-error",toolCallId:b,errorText:sn(j)});else{const se=me.get(b);await d({type:"tool-output-available",toolCallId:b,output:se&&Yt(se)&&w!==void 0?w:j})}me.delete(b)}return!1}case"result":{if(Ne.size>0)return t.origin?.kind!=="task-notification"&&(Oe=!0),!1;if(xn(t)&&!Oe)return!1;ke=t.subtype==="success"||_.wasCancelled?"stop":"error";const s=Ht(t,Ie);return ge=ke==="stop"?s:void 0,await S(),t.subtype!=="success"&&!_.wasCancelled&&await d({type:"error",errorText:t.errors?.filter(o=>o.trim()).join(`
|
|
7
|
+
`)||`Claude Code failed: ${t.subtype}`}),ft()}}return!1},We={threadRef:p,matrixEvent:V,llmProxyBinding:N},_=D??z.create({conversationId:ne,workdir:te,model:B,effort:H,agentMode:q,managedTaskContext:We,llmProxyBinding:N,buildOptions:(t,a,s)=>({abortController:t,cwd:te,includePartialMessages:!0,model:B,effort:H,maxTurns:m.claude.maxTurns,settings:Vt(),systemPrompt:{type:"preset",preset:"claude_code",append:Gt},...Ft(q),tools:{type:"preset",preset:"claude_code"},mcpServers:{[Ye]:Bt({workspaceRoot:Y,context:s}),...m.schedule?.enabled===!0?{[Lt]:Ut({config:m.schedule,context:s})}:null},disallowedTools:["EnterWorktree","ExitWorktree"],...ee?{resume:ee.sessionId,resumeSessionAt:ee.messageId,forkSession:!0}:W?{resume:W}:null,canUseTool:a,env:{...process.env,...Ze(),...N?{ANTHROPIC_CUSTOM_HEADERS:[process.env.ANTHROPIC_CUSTOM_HEADERS,`X-Elevo-LLM-Binding: ${N}`].filter(Boolean).join(`
|
|
8
|
+
`)}:null,CLAUDE_AGENT_SDK_CLIENT_APP:"coding-agent/claude-agent"}})});zt(ne,N);const ie=()=>_.abort();let He=!1;try{v&&g&&(f.info("Claude resuming interrupted client tool",{conversationId:c,toolCallId:v.toolCallId,toolName:v.toolName,kind:v.kind}),await g.attach({writeData:async()=>{},writeDone:async()=>{}}),v.kind==="ask_user"?Je(v.toolCallId,{interrupted:!0}):ze(v.toolCallId,{interrupted:!0}),await g.done),i&&(!g||v)&&(f.info("Claude emitting resumed client tool result",{conversationId:c,toolCallId:i.toolCallId,toolName:i.toolName,kind:i.kind,interrupted:!!v}),i.kind==="ask_user"?await d(v?{type:"tool-output-error",toolCallId:i.toolCallId,toolName:i.toolName,errorText:"Question interrupted by text response"}:{type:"tool-output-available",toolCallId:i.toolCallId,output:un(i,k,M)}):await d(v?{type:"tool-output-error",toolCallId:i.toolCallId,toolName:i.toolName,errorText:"Approval interrupted by text response"}:{type:"tool-output-available",toolCallId:i.toolCallId,output:ot(i,k,M)}),(!v||!g)&&Ge(i.toolCallId));const t=i&&!g&&!v?i.kind==="ask_user"?pn(k,M):yn(i,k,M):M,a=await _.reserveTurn(t,wt,mt,{model:B,effort:H,agentMode:q,managedTaskContext:We});if(f.info("Claude turn reservation completed",{conversationId:c,kind:a.kind,resumedToolCallId:i?.toolCallId,resumedToolName:i?.toolName}),a.kind==="interjection"){T&&clearTimeout(T),await I.writeDone();return}He=!0,X?.aborted&&ie(),X?.addEventListener("abort",ie,{once:!0}),await Promise.race([a.done,st]),!R&&!ce&&!C&&await Q(_.wasCancelled||!_.isDead?"stop":"error")}catch(t){C?(f.error("Claude stream failed after downstream closed:",t),K()):(await $e(c),X?.aborted||_.wasCancelled?await Q("stop"):_.isDead?await Q("error"):(f.error("Claude stream failed:",t),await d({type:"error",errorText:t instanceof Error?t.message:String(t)}),await Q("error")))}finally{He&&X?.removeEventListener("abort",ie),T&&clearTimeout(T),J.delete(Ee),R||Fe(),R||K()}}}}async function eo(e,n){await(await at(e)).run(n,e.signal)}le.post("/v1/chat/stream",It("json",jt),async e=>{const n=x(e.req.raw.headers,"X-Elevo-Wakeup-Key")?.trim()||void 0;let r;if(n){const p=be().claim(n);if(p.status!=="claimed")return e.header("X-Elevo-Wakeup-Duplicate","true"),e.json({error:"Scheduled wakeup was already accepted"},409);r=p.token}let l;try{l=await at({body:e.req.valid("json"),headers:e.req.raw.headers})}catch(p){if(n&&r&&be().release(n,r),p instanceof F)return e.json({error:p.message},p.status);throw p}return Ct(e,async p=>{let V=!1;const A=()=>{!n||!r||V||(V=!0,be().markStarted(n,r))};await l.run({writeData:async Y=>{A(),await p.writeSSE({data:JSON.stringify(Y)})},writeDone:async()=>{A(),await p.writeSSE({data:"[DONE]"})}},e.req.raw.signal)})});var to=le;export{F as ChatRequestError,Mn as cancelClaudeConversation,en as claudeActivitySnapshot,to as default,eo as handleClaudeChatStream,at as prepareClaudeChatStream};
|
package/dist/schemas.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export declare const ChatFilePartSchema: z.ZodObject<{
|
|
|
7
7
|
type: z.ZodLiteral<"file">;
|
|
8
8
|
mediaType: z.ZodString;
|
|
9
9
|
filename: z.ZodOptional<z.ZodString>;
|
|
10
|
+
originalFilename: z.ZodOptional<z.ZodString>;
|
|
11
|
+
attachmentId: z.ZodOptional<z.ZodString>;
|
|
10
12
|
url: z.ZodString;
|
|
11
13
|
}, z.core.$strip>;
|
|
12
14
|
export declare const ChatStepStartPartSchema: z.ZodObject<{
|
|
@@ -151,6 +153,8 @@ export declare const ChatBodySchema: z.ZodObject<{
|
|
|
151
153
|
type: z.ZodLiteral<"file">;
|
|
152
154
|
mediaType: z.ZodString;
|
|
153
155
|
filename: z.ZodOptional<z.ZodString>;
|
|
156
|
+
originalFilename: z.ZodOptional<z.ZodString>;
|
|
157
|
+
attachmentId: z.ZodOptional<z.ZodString>;
|
|
154
158
|
url: z.ZodString;
|
|
155
159
|
}, z.core.$strip>, z.ZodObject<{
|
|
156
160
|
type: z.ZodLiteral<"step-start">;
|
package/dist/schemas.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as t}from"zod";const o=t.object({type:t.literal("text"),text:t.string()}),e=t.object({type:t.literal("file"),mediaType:t.string(),filename:t.string().optional(),url:t.string()}),a=t.object({type:t.literal("step-start")}),n=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.string(),title:t.string().optional(),state:t.string(),input:t.unknown().optional(),output:t.unknown().optional()}),r=t.object({answers:t.record(t.string(),t.string())}),
|
|
1
|
+
import{z as t}from"zod";const o=t.object({type:t.literal("text"),text:t.string()}),e=t.object({type:t.literal("file"),mediaType:t.string(),filename:t.string().optional(),originalFilename:t.string().optional(),attachmentId:t.string().min(1).optional(),url:t.string()}),a=t.object({type:t.literal("step-start")}),n=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.string(),title:t.string().optional(),state:t.string(),input:t.unknown().optional(),output:t.unknown().optional()}),r=t.object({answers:t.record(t.string(),t.string())}),i=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.enum(["AskUserQuestion","ask_user_question"]),state:t.literal("output-available"),output:r}),l=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.enum(["ExitPlanMode","exit_plan_mode"]),state:t.literal("output-available"),output:t.unknown()}),s=t.object({id:t.string(),approved:t.boolean(),reason:t.string().optional()}),p=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.string(),state:t.literal("approval-responded"),input:t.unknown().optional(),approval:s}),c=t.union([i,l,p]),m=t.looseObject({type:t.string()}),u=t.strictObject({threadId:t.string().min(1),turnId:t.string().min(1)}),g=t.strictObject({sessionId:t.string().min(1),messageId:t.string().min(1)}),h=t.union([u,g]),d=t.enum(["low","medium","high","xhigh","max"]),S=t.object({conversationId:t.string().optional(),fork:h.optional(),model:t.string(),effort:d.default("medium"),message:t.object({id:t.string().optional(),role:t.enum(["user","assistant"]).optional(),parts:t.array(t.union([o,e,a,c,n,m]))})});export{c as AgentAnswerToolPartSchema,d as AgentEffortSchema,i as AskUserQuestionToolPartSchema,S as ChatBodySchema,m as ChatCustomPartSchema,e as ChatFilePartSchema,h as ChatForkSchema,a as ChatStepStartPartSchema,o as ChatTextPartSchema,n as ChatToolPartSchema,r as ClaudeAskUserQuestionOutputSchema,g as ClaudeChatForkSchema,u as CodexChatForkSchema,l as ExitPlanModeToolPartSchema,p as ToolApprovalPartSchema,s as ToolApprovalSchema};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@messenger-agent/claude-agent",
|
|
3
|
-
"version": "0.43.
|
|
3
|
+
"version": "0.43.1-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"ws": "^8.21.0",
|
|
20
20
|
"yaml": "^2.9.0",
|
|
21
21
|
"zod": "^4.4.3",
|
|
22
|
-
"@messenger-agent/shared": "0.43.
|
|
22
|
+
"@messenger-agent/shared": "0.43.1-alpha.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/ws": "^8.18.1"
|