@dcrays/mbh-chat 0.1.5-beta.7 → 0.1.5-beta.8
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/bridge/index.js +2 -2
- package/package.json +1 -1
package/bridge/index.js
CHANGED
|
@@ -575,7 +575,7 @@ ${Vj}`}async function Sne(e){let t=Tt.join(e,"AGENTS.md"),r="";try{r=await Dt.re
|
|
|
575
575
|
WHERE status = 'awaiting_ack' AND sent_at <= ?`).all(t),n=this.db.prepare(`SELECT delivery_id, logical_key, attempt_count, sent_at, content_json
|
|
576
576
|
FROM event_outbox
|
|
577
577
|
WHERE status = 'awaiting_ack' AND sent_at <= ?`).all(t),o=i.map(c=>{let u=JSON.parse(c.context_json),l=JSON.parse(c.payload_json),d={kind:"chat",deliveryId:c.delivery_id,logicalKey:c.logical_key,requestId:c.request_id,attemptCount:c.attempt_count,sentAt:c.sent_at,messageId:u.messageId,sessionId:u.sessionId};return typeof l.state=="string"&&(d.payloadKind=l.state),d}),s=n.map(c=>{let u=JSON.parse(c.content_json),l={kind:"event",deliveryId:c.delivery_id,logicalKey:c.logical_key,attemptCount:c.attempt_count,sentAt:c.sent_at};return typeof u.event_type=="string"&&(l.payloadKind=u.event_type),l}),a=[...o,...s];return{deadCandidates:a.filter(c=>c.attemptCount>=r),requeueCandidates:a.filter(c=>c.attemptCount<r)}}requeueAwaitingDeliveries(t=Number.MAX_SAFE_INTEGER,r=Number.MAX_SAFE_INTEGER){let i=0,n=0;for(let o of["delivery_outbox","event_outbox"]){let s=this.db.prepare(`UPDATE ${o} SET status = 'dead', last_error = 'delivery acknowledgement timed out', updated_at = ? WHERE status = 'awaiting_ack' AND sent_at <= ? AND attempt_count >= ?`).run(Date.now(),t,r),a=this.db.prepare(`UPDATE ${o} SET status = 'pending', last_error = 'delivery acknowledgement timed out', updated_at = ? WHERE status = 'awaiting_ack' AND sent_at <= ? AND attempt_count < ?`).run(Date.now(),t,r);n+=Number(s.changes),i+=Number(a.changes)}return{requeued:i,dead:n}}listProcessingRequests(){return this.listRunningRequests()}parseDelivery(t){return{deliveryId:t.delivery_id,requestId:t.request_id,accountId:t.account_id,logicalKey:t.logical_key,context:JSON.parse(t.context_json),payload:JSON.parse(t.payload_json),attemptCount:t.attempt_count}}parseEventDelivery(t){return{deliveryId:t.delivery_id,logicalKey:t.logical_key,content:JSON.parse(t.content_json),attemptCount:t.attempt_count}}};import{createHash as moe,randomUUID as goe}from"node:crypto";var coe=Br(rL(),1),uoe=Br(vh(),1),loe=Br(Oa(),1),foe=Br(yE(),1),doe=Br(_E(),1),poe=Br(TE(),1),fL=Br(xh(),1),hoe=Br(lL(),1);var rr=fL.default;var yoe=3e4,Eh=15e3,voe=512*1024,boe=50,OE=1e3,il=10,kh=15e3,_oe=4*1024*1024,ol="openclaw_bot_event with content.event_type=delivery, content.operation_type=ack, content.delivery_id=<id>";function woe(e,t,r){let i=Math.min(r,t*2**Math.min(e,8));return i+Math.floor(Math.random()*Math.max(1,Math.min(1e3,i/5)))}var Th=class{config;store;logger;onChat;onSkill;onState;onEvent;socket;reconnectTimer;heartbeatTimer;flushRetryTimer;ackRetryTimer;flushPromise;flushRequested=!1;stopped=!0;reconnectAttempt=0;pongPending=!1;constructor(t,r,i,n,o=async()=>{},s=()=>{},a=async()=>{}){this.config=t,this.store=r,this.logger=i,this.onChat=n,this.onSkill=o,this.onState=s,this.onEvent=a}start(){if(!this.stopped)throw new Error("mbh-chat socket already started");this.stopped=!1,this.connect()}async stop(){this.stopped=!0,this.onState("stopped"),this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.flushRetryTimer&&clearTimeout(this.flushRetryTimer),this.ackRetryTimer&&clearTimeout(this.ackRetryTimer),this.reconnectTimer=void 0,this.heartbeatTimer=void 0,this.flushRetryTimer=void 0,this.ackRetryTimer=void 0,this.flushRequested=!1;let t=this.socket;this.socket=void 0,t&&(t.readyState===rr.OPEN||t.readyState===rr.CONNECTING)&&await new Promise(r=>{let i=()=>r();t.once("close",i),t.close(1e3,"bridge stopped"),setTimeout(i,2e3).unref()})}enqueue(t,r,i){let n=this.store.enqueueDelivery(t,r,i);return this.triggerFlush(),n}enqueueTerminal(t,r,i,n,o){let s=r.message_tags&&typeof r.message_tags=="object"&&!Array.isArray(r.message_tags)?r.message_tags:{},a=r.state==="final"?{...r,message_tags:{...s,isFinal:1}}:r,c=this.store.completeRequestWithDelivery(t,a,i,n,o);return this.triggerFlush(),c}enqueueEvent(t,r){try{return this.enqueueManagementEvent({...r,domain_id:t.domainId??this.config.domainId,app_id:t.appId??this.config.appId,bot_id:t.botId,agent_id:t.agentId,session_id:t.sessionId,user_id:t.userId}),!0}catch(i){return this.logger.warn("mbh-chat event could not be persisted",{error:ne(i),sessionId:t.sessionId}),!1}}flush(){return this.flushPromise?(this.flushRequested=!0,this.flushPromise):(this.flushRequested=!1,this.flushPromise=this.flushPending().finally(()=>{this.flushPromise=void 0,this.flushRequested&&!this.stopped&&this.socket?.readyState===rr.OPEN&&(this.flushRequested=!1,queueMicrotask(()=>this.triggerFlush()))}),this.flushPromise)}async sendEvent(t){try{return this.enqueueManagementEvent(t),await this.flush(),!0}catch(r){return this.logger.error("mbh-chat management feedback could not be persisted",{error:ne(r)}),!1}}connect(){if(this.stopped)return;this.onState("connecting"),this.logger.info("connecting to mbh-chat",{endpoint:this.config.wsUrl});let t=new rr(this.config.wsUrl,{maxPayload:_oe});this.socket=t,t.on("open",()=>{if(!(this.socket!==t||this.stopped)){if(this.reconnectAttempt=0,this.logger.info("connected to mbh-chat"),this.config.deliveryAckMode==="business"){let r=this.store.requeueAwaitingDeliveries();(r.requeued>0||r.dead>0)&&this.logger.info("restored unacknowledged mbh-chat deliveries",r)}else{let r=this.store.finalizeAwaitingDeliveries();r>0&&this.logger.info("finalized legacy awaiting-ack mbh-chat deliveries in transport mode",{count:r})}this.onState("awaiting-heartbeat"),this.startHeartbeat(),this.sendHeartbeat({first:!0}),this.triggerFlush()}}),t.on("pong",()=>{this.socket===t&&(this.pongPending=!1)}),t.on("message",(r,i)=>{if(i){this.logger.warn("ignoring binary mbh-chat frame");return}try{let n=iM(r.toString());if("kind"in n){if(n.kind==="heartbeat"){this.onState("connected");return}if(n.kind==="skill"){let o=n.content.operation_type;if(!["install","enable","update","remove","disable"].includes(o)){this.logger.error("unsupported mbh-chat skill operation",{operationType:o,bytes:Buffer.byteLength(r.toString())}),this.sendEvent({...n.content,status:"fail",error:`unsupported skill operation: ${o}`});return}this.onSkill(n).catch(s=>{this.logger.error("inbound mbh-chat skill handler failed",{error:ne(s)})});return}if(n.kind==="event"){let o=rM(n);if(o){for(let s of o)this.store.acknowledgeDelivery(s)||this.logger.warn("ignored unknown mbh-chat delivery acknowledgement",{deliveryId:s,expectedAck:ol});return}this.onEvent(n).catch(s=>{this.logger.error("inbound mbh-chat event handler failed",{error:ne(s)})});return}n.kind==="ignored"&&this.logger.warn("ignoring unsupported mbh-chat event",{messageType:n.messageType});return}this.onChat(n).catch(o=>{this.logger.error("inbound mbh-chat handler failed",{error:ne(o)}),this.replyToFailedChat(n,"bridge_error","\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")})}catch(n){if(n instanceof Xu&&n.reply){this.logger.warn("invalid mbh-chat chat frame; returning terminal feedback",{error:n.message,messageId:n.reply.content.message_id}),this.replyToFailedChat(n.reply,"invalid_input",n.userMessage);return}this.logger.warn("invalid mbh-chat frame",{error:ne(n)})}}),t.on("error",r=>{this.onState("error"),this.logger.warn("mbh-chat WebSocket error",{error:r.message})}),t.on("close",(r,i)=>{if(this.socket===t&&(this.socket=void 0,this.config.deliveryAckMode==="business"&&this.store.requeueAwaitingDeliveries(),this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0,this.onState("disconnected"),this.logger.warn("mbh-chat disconnected",{code:r,reason:i.toString()}),!this.stopped)){let n=woe(this.reconnectAttempt++,this.config.reconnectMinMs,this.config.reconnectMaxMs);this.logger.info("reconnecting to mbh-chat",{delayMs:n,attempt:this.reconnectAttempt}),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.connect()},n)}})}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.pongPending=!1,this.heartbeatTimer=setInterval(()=>{let t=this.socket;if(t?.readyState===rr.OPEN){if(this.pongPending){this.logger.warn("mbh-chat heartbeat pong timeout; terminating stale connection"),t.terminate();return}this.pongPending=!0;try{t.ping()}catch(r){this.pongPending=!1,this.logger.warn("mbh-chat heartbeat ping threw",{error:ne(r)})}this.sendHeartbeat()}},yoe)}sendHeartbeat(t){let r=this.socket;if(r?.readyState===rr.OPEN)try{r.send(JSON.stringify({messageType:"openclaw_bot_heartbeat",_userId:Number(this.config.userId)||0,source:"client",content:{bot_token:this.config.botToken,status:"1"}}),i=>{i?this.logger.warn("mbh-chat heartbeat send failed",{error:i.message}):t?.first&&this.logger.info("mbh-chat first heartbeat sent")})}catch(i){this.logger.warn("mbh-chat heartbeat send threw",{error:ne(i)})}}replyToFailedChat(t,r,i){let n=Yn(this.config.accountId,t.content.message_id.trim());try{let o=ah(t,this.config.accountId,n);this.enqueueTerminal(o,{response:i,state:"final",final_tag:r,is_finish:1},"final","failed",r)}catch(o){this.logger.error("could not persist mbh-chat failure feedback",{requestId:n,tag:r,error:ne(o)})}}async flushPending(){let t=0;for(;;){let r=this.socket;if(r?.readyState!==rr.OPEN)return t;if(r.bufferedAmount>voe)return this.scheduleFlush(boe),t;let i=this.store.listPendingDeliveries(200),n=this.store.listPendingEventDeliveries(200);if(i.length===0&&n.length===0)return t;let o=0;for(let s of i){if(this.socket!==r||r.readyState!==rr.OPEN)return t;s.attemptCount>=1&&this.config.deliveryAckMode==="business"&&this.logger.warn("mbh-chat resending chat delivery without business acknowledgement",{attempt:s.attemptCount+1,expectedAck:ol}),this.store.markDeliveryAttempt(s.deliveryId);try{await this.sendDelivery(r,s),this.config.deliveryAckMode==="business"?(this.store.markDeliverySent(s.deliveryId),this.scheduleAcknowledgementRetry()):this.store.markDeliveryDelivered(s.deliveryId),t+=1,o+=1}catch(a){let c=this.store.markDeliveryFailed(s.deliveryId,ne(a),il);if(this.logger.warn(c?"mbh-chat delivery moved to dead letter":"mbh-chat delivery remains pending",{deliveryId:s.deliveryId,attemptCount:s.attemptCount+1,error:ne(a)}),c)continue;return this.scheduleFlush(OE),t}}for(let s of n){if(this.socket!==r||r.readyState!==rr.OPEN)return t;s.attemptCount>=1&&this.config.deliveryAckMode==="business"&&this.logger.warn("mbh-chat resending event delivery without business acknowledgement",{...this.deliveryDiagnosticFields(s),attempt:s.attemptCount+1,expectedAck:ol}),this.store.markDeliveryAttempt(s.deliveryId,!0);try{await this.sendEventDelivery(r,s),this.config.deliveryAckMode==="business"?(this.store.markDeliverySent(s.deliveryId,!0),this.scheduleAcknowledgementRetry()):this.store.markDeliveryDelivered(s.deliveryId,!0),t+=1,o+=1}catch(a){let c=this.store.markDeliveryFailed(s.deliveryId,ne(a),il,!0);if(this.logger.warn(c?"mbh-chat event delivery moved to dead letter":"mbh-chat event delivery remains pending",{deliveryId:s.deliveryId,attemptCount:s.attemptCount+1,error:ne(a)}),c)continue;return this.scheduleFlush(OE),t}}if(o===0)return t}}scheduleFlush(t){this.stopped||this.flushRetryTimer||(this.flushRetryTimer=setTimeout(()=>{this.flushRetryTimer=void 0,this.triggerFlush()},t),this.flushRetryTimer.unref())}triggerFlush(){if(!this.stopped){if(this.flushPromise){this.flushRequested=!0;return}this.flush().catch(t=>{this.logger.error("mbh-chat Outbox flush failed",{error:ne(t)}),this.scheduleFlush(OE)})}}scheduleAcknowledgementRetry(){this.config.deliveryAckMode!=="business"||this.stopped||this.ackRetryTimer||(this.ackRetryTimer=setTimeout(()=>{this.ackRetryTimer=void 0;let t=Date.now()-kh,r=this.store.listExpiredAwaitingDeliveries(t,il),i=this.store.requeueAwaitingDeliveries(t,il);i.dead>0&&this.logger.error("mbh-chat deliveries exhausted acknowledgement retries",{count:i.dead,ackTimeoutMs:kh,maxAttempts:il,expectedAck:ol,deliveries:this.deliveryDiagnosticFieldsList(r.deadCandidates)}),i.requeued>0?(this.logger.warn("mbh-chat delivery acknowledgement timed out; will resend",{count:i.requeued,ackTimeoutMs:kh,expectedAck:ol,deliveries:this.deliveryDiagnosticFieldsList(r.requeueCandidates)}),this.triggerFlush()):this.store.countAwaitingDeliveries()>0&&this.scheduleAcknowledgementRetry()},kh),this.ackRetryTimer.unref())}deliveryDiagnosticFields(t){return"requestId"in t?{kind:"chat",deliveryId:t.deliveryId,logicalKey:t.logicalKey,requestId:t.requestId,attemptCount:t.attemptCount,payloadState:t.payload.state,messageId:t.context.messageId,sessionId:t.context.sessionId}:{kind:"event",deliveryId:t.deliveryId,logicalKey:t.logicalKey,attemptCount:t.attemptCount,eventType:typeof t.content.event_type=="string"?t.content.event_type:void 0}}deliveryDiagnosticFieldsList(t,r=20){return t.slice(0,r).map(i=>({kind:i.kind,deliveryId:i.deliveryId,logicalKey:i.logicalKey,requestId:i.requestId,attemptCount:i.attemptCount,payloadKind:i.payloadKind,messageId:i.messageId,sessionId:i.sessionId,sentAt:i.sentAt}))}enqueueManagementEvent(t){let r={...t};for(let s of["bot_token","token","authorization"])delete r[s];let i=typeof r.websocket_trace_id=="string"?r.websocket_trace_id.trim():"",n=i?`event:${moe("sha256").update(`${String(r.event_type??"")}\0${String(r.operation_type??"")}\0${i}\0${String(r.status??"")}`).digest("hex")}`:`event:${goe()}`,o=this.store.enqueueEventDelivery(r,n);return this.triggerFlush(),o}sendDelivery(t,r){let i=r.context,n={...r.payload,bot_token:this.config.botToken,domain_id:i.domainId??this.config.domainId,app_id:i.appId??this.config.appId,bot_id:i.botId,agent_id:i.agentId,session_id:i.sessionId,message_id:i.messageId,delivery_id:r.deliveryId,idempotency_key:r.deliveryId,request_id:r.requestId},o=JSON.stringify({messageType:"openclaw_bot_chat",_userId:i.userId,source:"client",content:JSON.stringify(n)});return new Promise((s,a)=>{let c=!1,u=d=>{c||(c=!0,clearTimeout(l),d?a(d):s())},l=setTimeout(()=>u(new Error(`send callback timed out after ${Eh}ms`)),Eh);try{t.send(o,d=>u(d))}catch(d){u(d instanceof Error?d:new Error(String(d)))}})}sendEventDelivery(t,r){let i=JSON.stringify({messageType:"openclaw_bot_event",_userId:Number(r.content.user_id)||Number(this.config.userId)||0,source:"client",content:{bot_token:this.config.botToken,...r.content,delivery_id:r.deliveryId,idempotency_key:r.deliveryId}});return new Promise((n,o)=>{let s=!1,a=u=>{s||(s=!0,clearTimeout(c),u?o(u):n())},c=setTimeout(()=>a(new Error(`send callback timed out after ${Eh}ms`)),Eh);try{t.send(i,u=>a(u))}catch(u){a(u instanceof Error?u:new Error(String(u)))}})}};var dL="MBHCHAT_DSH_SESSION_COOKIE",xoe=/^dsh-auth-[A-Za-z0-9_-]+=[A-Za-z0-9._-]+$/u;function Ih(e=process.env){let t=e[dL]?.trim();if(t){if(!xoe.test(t))throw new Error(`${dL} is not a valid DSH authentication cookie`);return t}}function vn(e,t={}){return e?{...t,cookie:e}:{...t}}var Na="dsh/cron.list",Fi="/api/cron-automations",pL="mbh-chat";function sl(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0}function Soe(e){if(!Dr(e)||e.status==="deleted")return;let t=e;return{id:t.id,name:t.name,description:t.prompt,enabled:t.status==="active"||t.status==="dispatching",createdAtMs:Date.parse(t.createdAt),updatedAtMs:Date.parse(t.updatedAt),schedule:{kind:"cron",expr:t.cron,tz:t.timezone},payload:{kind:"agentTurn",message:t.prompt,timeoutSeconds:600},agentId:t.agentId,sessionTarget:"isolated",wakeMode:"now",delivery:{mode:"announce",bestEffort:!0},state:{nextRunAtMs:Date.parse(t.nextRunAt),...t.lastRunAt?{lastRunAtMs:Date.parse(t.lastRunAt)}:{}}}}function Eoe(e){return Dr(e)&&typeof e.id=="string"&&typeof e.name=="string"&&typeof e.agentId=="string"&&typeof e.enabled=="boolean"&&sl(e.createdAtMs)&&sl(e.updatedAtMs)&&Dr(e.schedule)&&typeof e.schedule.kind=="string"&&Dr(e.payload)&&typeof e.payload.kind=="string"&&Dr(e.state)&&(e.state.nextRunAtMs===void 0||sl(e.state.nextRunAtMs))&&(e.state.runningAtMs===void 0||sl(e.state.runningAtMs))&&(e.state.lastRunAtMs===void 0||sl(e.state.lastRunAtMs))}function al(e){if(!Dr(e)||e.type!==Na||e.version!==1)throw new Error("cron list snapshot must be a dsh/cron.list document");let t=Array.isArray(e.jobs)?e.jobs:Array.isArray(e.crons)?e.crons.map(Soe).filter(i=>i!==void 0):void 0;if(!t)throw new Error("cron list snapshot must contain jobs");let r=t.filter(Eoe);return{type:Na,version:1,sequence:typeof e.sequence=="number"?e.sequence:0,generatedAt:typeof e.generatedAt=="string"?e.generatedAt:new Date().toISOString(),reason:typeof e.reason=="string"?e.reason:"unknown",jobs:r,invalidJobCount:t.length-r.length}}function zi(e){let t=e.split(":").filter(i=>i.length>0),r=t.map(i=>i.toLowerCase());return t.length>=6&&r[0]==="agent"&&r[2]==="mobook"&&r[3]==="direct"?{agentId:t[4]??"",sessionId:t[5]??""}:{agentId:t.at(-2)??"",sessionId:t.at(-1)??""}}function bn(e){let t=e.split(":").filter(i=>i.length>0),r=t.map(i=>i.toLowerCase());return t.length>=6&&r[0]==="agent"&&r[2]==="mobook"&&r[3]==="direct"}function $E(e,t){return{version:1,jobs:e.flatMap(r=>{let i=(r.sessionKey??t(r))?.trim();if(!i||!bn(i))return[];let n=zi(i),{dshSessionId:o,...s}=r;return[{...s,description:r.description??(typeof r.payload.message=="string"?r.payload.message:""),sessionKey:i,sessionTarget:r.payload.kind==="systemEvent"?"main":"isolated",wakeMode:"now",delivery:{...r.delivery,mode:"announce",to:`dcg-cron:${i}`,channel:pL,bestEffort:!0,...n.agentId?{accountId:n.agentId}:{}}}]})}}function koe(e){let t=[],r=e;for(;;){let i=/\r?\n\r?\n/.exec(r);if(!i||i.index<0)return{events:t,rest:r};let n=r.slice(0,i.index);r=r.slice(i.index+i[0].length);let o="message",s=[];for(let a of n.split(/\r?\n/))a.startsWith("event:")?o=a.slice(6).trim():a.startsWith("data:")&&s.push(a.slice(5).trimStart());s.length>0&&t.push({event:o,data:s.join(`
|
|
578
|
-
`)})}}var cl=class{baseUrl;fetchImpl;sessionCookie;constructor(t,r=fetch,i=Ih()){this.baseUrl=t,this.fetchImpl=r,this.sessionCookie=i}url(t){return new URL(t,this.baseUrl.endsWith("/")?this.baseUrl:`${this.baseUrl}/`)}async patch(t,r){return(await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}`),{method:"PATCH",headers:vn(this.sessionCookie,{"content-type":"application/json"}),body:JSON.stringify(r),signal:AbortSignal.timeout(15e3)})).ok}async patchJob(t,r){let i=await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}`),{method:"PATCH",headers:vn(this.sessionCookie,{"content-type":"application/json"}),body:JSON.stringify(r),signal:AbortSignal.timeout(15e3)});if(!i.ok)return;let n=await i.json().catch(()=>{});return al({type:Na,version:1,jobs:[n]}).jobs.find(o=>o.id===t)}setEnabled(t,r){return this.patch(t,{enabled:r})}async delete(t){let r=await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}`),{method:"DELETE",headers:vn(this.sessionCookie),signal:AbortSignal.timeout(15e3)});return r.ok?"deleted":r.status===404?"not_found":"failed"}async runOnce(t){let r=await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}/run`),{method:"POST",headers:vn(this.sessionCookie),signal:AbortSignal.timeout(15e3)}),i=await r.json().catch(()=>{}),n=Dr(i)&&typeof i.status=="string"?i.status:void 0;return n==="dispatched"||n==="not_found"||n==="already_running"||n==="delivery_unavailable"?n:r.status===404?"not_found":r.status===202?"already_running":r.ok&&Dr(i)&&i.delivered===!0?"dispatched":"delivery_unavailable"}async list(){let t=await this.fetchImpl(this.url(`${Fi}`),{method:"GET",headers:vn(this.sessionCookie),signal:AbortSignal.timeout(15e3)});if(!t.ok)return;let r=await t.json().catch(()=>{});if(!(!Dr(r)||!Array.isArray(r.jobs)))return al({type:Na,version:1,sequence:0,generatedAt:new Date().toISOString(),reason:"fetch",jobs:r.jobs})}async subscribe(t,r,i=()=>{}){let n=await this.fetchImpl(this.url(`${Fi}/events`),{method:"GET",headers:vn(this.sessionCookie,{accept:"text/event-stream"}),signal:r});if(!n.ok||!n.body)throw new Error(`cron SSE failed with HTTP ${n.status}`);let o=n.body.getReader(),s=new TextDecoder,a="";for(;;){let{value:c,done:u}=await o.read();if(u){if(!r.aborted)throw new Error("cron SSE stream ended");return}a+=s.decode(c,{stream:!0});let{events:l,rest:d}=koe(a);a=d;for(let p of l)if(p.event==="cron-list")try{t(al(JSON.parse(p.data)))}catch(f){i(f)}}}};var Toe=100,Ioe=1e3,Ooe=3e4;function CE(e){let{updatedAtMs:t,state:r,...i}=e;return JSON.stringify(i,(n,o)=>o&&typeof o=="object"&&!Array.isArray(o)?Object.fromEntries(Object.entries(o).sort(([s],[a])=>s.localeCompare(a))):o)}function $oe(e,t){return new Promise(r=>{if(e.aborted){r();return}let i=()=>{clearTimeout(n),e.removeEventListener("abort",i),r()},n=setTimeout(i,t);n.unref(),e.addEventListener("abort",i,{once:!0})})}var Oh=class{options;client;abort;loop;debounce;publishTail=Promise.resolve();lastFingerprint;lastContext;lastSnapshot;lastJobs=new Map;lastContexts=new Map;constructor(t){this.options=t,this.client=new cl(t.dshBaseUrl,t.fetchImpl)}start(){if(this.loop)return;let t=this.options.store.getLatestContext();t&&(this.lastContext=t),this.abort=new AbortController,this.loop=this.run(this.abort.signal)}async stop(){this.abort?.abort(),this.debounce&&clearTimeout(this.debounce),this.debounce=void 0,await this.loop?.catch(()=>{}),await this.publishTail,this.loop=void 0,this.abort=void 0}async applyControl(t,r){if(t==="remove"){let n=await this.client.delete(r);return{applied:n!=="failed",...n==="not_found"?{reconciled:!0}:{}}}if(t==="enable")return{applied:await this.client.setEnabled(r,!0)};if(t==="disable")return{applied:await this.client.setEnabled(r,!1)};await this.ensureSessionForCron(r),await this.ensureSessionFollowed(r);let i=await this.client.runOnce(r);return i==="delivery_unavailable"&&(i=await this.rebindAndRetryRun(r,i)),{applied:i==="dispatched"||i==="already_running",runStatus:i}}notifySessionAvailable(){this.lastSnapshot&&this.schedulePublish(this.lastSnapshot)}businessKeyForCronId(t){let r=this.lastSnapshot?.jobs.find(i=>i.id===t);if(r)return this.sessionKeyFor(r)}async bindDshSessionId(t,r){if(!bn(t))return;let i=this.lastSnapshot??await this.client.list();if(!i)return;let n=i.jobs.filter(o=>o.sessionKey===t&&(!o.dshSessionId||o.dshSessionId!==r));n.length!==0&&await Promise.all(n.map(async o=>{await this.client.patch(o.id,{dshSessionId:r})?(this.options.logger.info("bound cron job to mbh-chat session",{cronId:o.id,sessionKey:t,dshSessionId:r}),this.followCronSession(r)):this.options.logger.warn("failed to patch cron dshSessionId binding",{cronId:o.id,sessionKey:t,dshSessionId:r})}))}async bindAllKnownDshSessions(){let t=this.lastSnapshot??await this.client.list();if(!t)return;let r=new Map;for(let i of t.jobs){if(!i.sessionKey||!bn(i.sessionKey))continue;let n=this.options.store.getSession(i.sessionKey);!n||i.dshSessionId===n||r.set(i.id,n)}r.size!==0&&await Promise.all([...r.entries()].map(async([i,n])=>{await this.client.patch(i,{dshSessionId:n})?(this.options.logger.info("bound cron job to pre-existing mbh-chat session",{cronId:i,dshSessionId:n}),this.followCronSession(n)):this.options.logger.warn("failed to patch cron dshSessionId binding",{cronId:i,dshSessionId:n})}))}async run(t){let r=0;for(;!t.aborted;)try{await this.client.subscribe(i=>this.schedulePublish(i),t,i=>this.options.logger.warn("ignored invalid cron catalog SSE event",{error:ne(i)})),r=0}catch(i){if(t.aborted)return;r+=1;let n=Math.min(Ooe,Ioe*2**Math.min(r-1,8));this.options.logger.warn("cron catalog SSE disconnected; retrying",{delayMs:n,error:ne(i)}),await $oe(t,n)}}schedulePublish(t){this.lastSnapshot=t,this.debounce&&clearTimeout(this.debounce),this.debounce=setTimeout(()=>{this.debounce=void 0,this.publishTail=this.publishTail.then(()=>this.publish(t)).catch(r=>this.options.logger.warn("failed to publish cron catalog to Mobook",{error:ne(r)}))},this.options.debounceMs??Toe),this.debounce.unref()}async rebindAndRetryRun(t,r){let n=(await this.client.list().catch(()=>{}))?.jobs.find(s=>s.id===t);if(!n?.sessionKey||!bn(n.sessionKey))return r;let o=this.options.store.getSession(n.sessionKey);return!o||o===n.dshSessionId||!await this.client.patch(t,{dshSessionId:o})?r:(this.options.logger.info("rebound stale cron DSH session before manual run",{cronId:t,dshSessionId:o}),await this.followCronSession(o),this.client.runOnce(t))}async ensureSessionForCron(t){let i=(await this.client.list().catch(()=>{}))?.jobs.find(o=>o.id===t);if(!i?.sessionKey||!bn(i.sessionKey))return;let n=this.options.store.getSession(i.sessionKey);n||(n=await this.options.provisionSession?.(i)),n&&i.dshSessionId!==n&&await this.client.patch(t,{dshSessionId:n})&&this.options.logger.info("provisioned cron DSH session before dispatch",{cronId:t,dshSessionId:n})}contextFor(t){if(t.sessionKey){let i=this.options.store.getLatestContextForBusinessKey(t.sessionKey);if(i)return i}let r=this.options.store.getBusinessKeyByDshSessionId(t.dshSessionId??t.agentId);return r?this.options.store.getLatestContextForBusinessKey(r):void 0}sessionKeyFor(t){return t.sessionKey?t.sessionKey:this.options.store.getBusinessKeyByDshSessionId(t.dshSessionId??t.agentId)}adoptionOwner(){let t=this.lastContext??this.options.store.getLatestContext?.();if(!t||!bn(t.businessKey))return;let r=zi(t.businessKey).agentId;return r?{businessKey:t.businessKey,agentId:r}:void 0}isForeignOwner(t,r){return!t||!bn(t)?!0:zi(t).agentId!==r}send(t,r){return this.options.dcg.enqueueEvent(t,r)!==!1}async publish(t){let r=this.adoptionOwner(),i=[];for(let l of t.jobs){let d=this.sessionKeyFor(l);if(r&&this.isForeignOwner(d,r.agentId)&&(d=r.businessKey),!d){i.push(l);continue}let p=zi(d),f=this.options.store.getSession(d),h={...l.sessionKey===d?{}:{sessionKey:d},...f&&l.dshSessionId!==f?{dshSessionId:f}:{},...p.agentId&&l.agentId!==p.agentId?{agentId:p.agentId}:{}};if(Object.keys(h).length>0){let m=await this.client.patchJob(l.id,h);if(!m){this.options.logger.warn("failed to persist cron sessionKey binding",{cronId:l.id});return}i.push(m)}else i.push(l)}let n=$E(i,l=>this.sessionKeyFor(l)),o=JSON.stringify(n.jobs.map(l=>[l.id,CE(l)]).sort());if(o===this.lastFingerprint)return;if(t.jobs.length>0&&n.jobs.length===0){this.options.logger.warn("skipping Mobook cron catalog publish; no mbh-chat session mapping is available yet");return}let s=new Set(n.jobs.map(l=>l.id)),a=new Set,c=new Set;for(let l of n.jobs){let d=CE(l);if(this.lastJobs.get(l.id)===d)continue;let p=i.find(h=>h.id===l.id),f=p?this.contextFor(p):void 0;if(!f&&p?.sessionKey&&bn(p.sessionKey)&&(await this.ensureSessionForCron(p.id),f=this.contextFor(p)),!f){this.options.logger.warn("skipping cron install; no mapped mbh-chat session is available",{cronId:l.id}),a.add(l.id);continue}if(!this.send(f,{event_type:"cron",operation_type:"install",data:l})){this.options.logger.warn("cron install event was not sent; will retry",{cronId:l.id});return}this.lastJobs.set(l.id,d),this.lastContexts.set(l.id,f),this.lastContext=f,this.lastFingerprint=void 0,this.options.logger.info("enqueued cron install to Mobook",{cronId:l.id,sequence:t.sequence})}if(t.invalidJobCount===0)for(let l of this.lastJobs.keys()){if(s.has(l))continue;let d=this.lastContexts.get(l);if(!d){this.options.logger.warn("skipping cron remove; no mapped mbh-chat session is available",{cronId:l}),c.add(l);continue}if(!this.send(d,{event_type:"cron",operation_type:"remove",data:{id:l,jobId:l,action:"removed"}})){this.options.logger.warn("cron remove event was not sent; will retry",{cronId:l});return}this.lastJobs.delete(l),this.lastContexts.delete(l),this.lastFingerprint=void 0}else this.options.logger.warn("cron snapshot contained invalid jobs; preserving previously published jobs",{invalidJobCount:t.invalidJobCount});let u=new Map([...this.lastJobs].filter(([l])=>s.has(l)||c.has(l)));for(let l of n.jobs)a.has(l.id)||u.set(l.id,CE(l));if(t.invalidJobCount>0)for(let[l,d]of this.lastJobs)u.has(l)||u.set(l,d);this.lastJobs=u,this.lastFingerprint=t.invalidJobCount===0&&a.size===0&&c.size===0?o:void 0,this.followBoundJobs(i),this.options.logger.info("published cron catalog to Mobook",{jobs:n.jobs.length,sequence:t.sequence})}async ensureSessionFollowed(t){let i=(this.lastSnapshot??await this.client.list().catch(()=>{}))?.jobs.find(s=>s.id===t);if(!i)return;let n=this.sessionKeyFor(i),o=(n?this.options.store.getSession(n):void 0)||i.dshSessionId;o&&await this.followCronSession(o)}followBoundJobs(t){let r=new Set;for(let i of t){let n=this.sessionKeyFor(i),o=(n?this.options.store.getSession(n):void 0)||i.dshSessionId;!o||r.has(o)||(r.add(o),this.followCronSession(o))}}async followCronSession(t){this.options.followSession&&await this.options.followSession(t)}};import{timingSafeEqual as Coe}from"node:crypto";import Pa from"node:fs";import Aoe from"node:http";import Roe from"node:path";var hL=1024*1024,Wke=64*1024;function Doe(e,t){if(!e?.startsWith("Bearer "))return!1;let r=Buffer.from(e.slice(7)),i=Buffer.from(t);return r.length===i.length&&Coe(r,i)}async function Noe(e){let t=[],r=0;for await(let i of e){let n=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=n.length,r>hL)throw new Error(`request body exceeds ${hL} bytes`);t.push(n)}return JSON.parse(Buffer.concat(t).toString("utf8"))}function qa(e,t,r){let i=JSON.stringify(r);e.writeHead(t,{"content-type":"application/json; charset=utf-8","content-length":Buffer.byteLength(i)}),e.end(i)}var $h=class{socketPath;token;handler;statusProvider;server;constructor(t,r,i,n){this.socketPath=t,this.token=r,this.handler=i,this.statusProvider=n}async start(){if(this.server)throw new Error("message control server already started");if(process.platform!=="win32"){Pa.mkdirSync(Roe.dirname(this.socketPath),{recursive:!0});try{if(!Pa.lstatSync(this.socketPath).isSocket())throw new Error(`refusing to replace non-socket control path: ${this.socketPath}`);Pa.unlinkSync(this.socketPath)}catch(r){if(r.code!=="ENOENT")throw r}}let t=Aoe.createServer((r,i)=>{this.handle(r,i)});this.server=t,await new Promise((r,i)=>{let n=s=>{t.off("listening",o),i(s)},o=()=>{t.off("error",n),r()};t.once("error",n),t.once("listening",o),t.listen(this.socketPath)}),process.platform!=="win32"&&Pa.chmodSync(this.socketPath,384)}async stop(){let t=this.server;if(this.server=void 0,t&&await new Promise(r=>t.close(()=>r())),process.platform!=="win32")try{Pa.lstatSync(this.socketPath).isSocket()&&Pa.unlinkSync(this.socketPath)}catch(r){if(r.code!=="ENOENT")throw r}}async handle(t,r){let i=t.method==="POST"&&t.url==="/v1/message",n=t.method==="GET"&&t.url==="/v1/status";if(!i&&!n){qa(r,404,{error:"not found"});return}if(!Doe(t.headers.authorization,this.token)){qa(r,401,{error:"unauthorized"});return}if(n){if(!this.statusProvider){qa(r,404,{error:"not found"});return}qa(r,200,this.statusProvider());return}let o=new AbortController,s=()=>o.abort(new Error("control client disconnected"));t.once("aborted",s);try{let a=await Noe(t),c=await this.handler(a,o.signal);qa(r,c.success?200:422,c)}catch(a){qa(r,400,{success:!1,sentMediaCount:0,queued:!1,error:a instanceof Error?a.message:String(a)})}finally{t.off("aborted",s)}}};import{createHash as Poe}from"node:crypto";var jo=class extends Error{status;constructor(t,r){super(t),this.status=r,this.name="DcgApiRequestError"}};function qoe(e){return e!==null&&typeof e=="object"?JSON.stringify(e):String(e)}function joe(e,t,r,i,n="1.0.0"){let o={timestamp:t,path:r,version:n,...e},s=Object.keys(o).sort().map(a=>o[a]===void 0?"":`${a}${qoe(o[a])}`).join("")+i;return Poe("md5").update(s).digest("hex").toUpperCase()}function Moe(e,t){try{let r=new URL(t,e);return`POST ${r.origin}${r.pathname}`}catch{return`POST ${t.split("?",1)[0]??""}`}}var Ch=class{config;logger;fetchImpl;timeoutMs;constructor(t,r,i=fetch,n=6e4){this.config=t,this.logger=r,this.fetchImpl=i,this.timeoutMs=n}async post(t,r,i={}){if(!t.startsWith("/")||t.startsWith("//"))throw new Error("mbh-chat API request path must be an origin-relative path");let n=new URL(this.config.apiBaseUrl),o=new URL(t,n);if(o.origin!==n.origin)throw new Error("mbh-chat API request path must stay on the configured origin");let s=typeof i.appId=="number"&&Number.isFinite(i.appId)?Math.trunc(i.appId):typeof i.appId=="string"&&i.appId.trim()?i.appId.trim():this.config.appId,a={...r,_appId:s},c=Date.now(),u=AbortSignal.timeout(this.timeoutMs),l=i.signal?AbortSignal.any([i.signal,u]):u,d=Moe(this.config.apiBaseUrl,t);try{let p=await this.fetchImpl(o,{method:"POST",signal:l,headers:{"content-type":"application/json",appKey:this.config.apiAppKey,sign:joe(a,c,t,this.config.apiSignKey,this.config.apiVersion),timestamp:String(c),version:this.config.apiVersion,...i.userToken?{authorization:i.userToken}:{}},body:JSON.stringify(a)});if(!p.ok)throw await p.body?.cancel(),new jo(`mbh-chat API request failed with HTTP ${p.status}`,p.status);let f=await p.json();if(!f||typeof f!="object"||Array.isArray(f))throw new jo("mbh-chat API returned a non-object JSON response",p.status);return f}catch(p){let f=p instanceof jo?p.status:void 0;throw this.logger.warn("mbh-chat API request failed",{request:d,...f!==void 0?{status:f}:{},error:p instanceof Error?p.message:String(p)}),p}}};var Ah=class{ttlMs;tokens=new Map;pending=new Map;constructor(t=3600*1e3){if(this.ttlMs=t,!Number.isFinite(t)||t<=0)throw new Error("user-token cache ttlMs must be positive")}key(t,r){return`${t}\0${r.userId}\0${r.appId}`}get(t,r){let i=this.key(t,r),n=this.tokens.get(i);if(n){if(Date.now()>=n.expiresAt){this.tokens.delete(i);return}return n.token}}set(t,r,i){this.tokens.set(this.key(t,r),{token:i,expiresAt:Date.now()+this.ttlMs})}delete(t,r){this.tokens.delete(this.key(t,r))}async getOrLoad(t,r,i){let n=this.get(t,r);if(n)return n;let o=this.key(t,r),s=this.pending.get(o);if(s)return s;let a=i().then(c=>{if(!c)throw new Error("mbh-chat user-token lookup returned an empty token");return this.set(t,r,c),c}).finally(()=>this.pending.delete(o));return this.pending.set(o,a),a}clear(){this.tokens.clear(),this.pending.clear()}};var Loe=1001;function Rh(e,t){let r=t.code===void 0?"unknown":String(t.code),i=typeof t.message=="string"?t.message.replace(/[\u0000-\u001f\u007f]+/g," ").slice(0,300):"";return new Error(`${e} failed (code=${r})${i?`: ${i}`:""}`)}function AE(e,t,r){let i=e==null||e===""?t:e,n=typeof i=="number"?i:Number(String(i).trim());if(!Number.isSafeInteger(n)||n<0)throw new Error(`${r} must be a non-negative safe integer`);return n}function Foe(e){let t=e.match(/^(.*?)-(\d+(?:-\d+)*)$/);return t?t[1]??"":""}function zoe(e){if(e==null||e==="")return;let t=typeof e=="number"?e:Number(String(e).trim());return Number.isSafeInteger(t)&&t>=0?t:void 0}var Dh=class{config;client;tokenCache;constructor(t,r,i){this.config=t,this.client=new Ch(t,r,i?.fetchImpl,i?.timeoutMs),this.tokenCache=i?.tokenCache??new Ah}context(t){return{appId:typeof t?.appId=="number"&&Number.isFinite(t.appId)?String(Math.trunc(t.appId)):typeof t?.appId=="string"&&t.appId.trim()?t.appId.trim():this.config.appId,userId:Number.isFinite(t?.userId)?t?.userId??0:Number(this.config.userId)||0}}async queryUserTokenByBotToken(t,r){let i=this.context(r),n=await this.client.post("/organization/queryUserTokenByBotTokenV2",{botToken:t,_userId:i.userId},{appId:i.appId,...r?.signal?{signal:r.signal}:{}});if(!n.data?.token)throw Rh("mbh-chat user-token lookup",n);return n.data.token}async getUserToken(t,r){let i=t.trim();if(!i)throw new Error("botToken is required for mbh-chat API authentication");let n=this.context(r);return this.tokenCache.getOrLoad(i,n,()=>this.queryUserTokenByBotToken(i,r))}async withUserToken(t,r,i){let n=t.trim(),o=this.context(r),s=await this.getUserToken(n,r);try{return await i(s)}catch(a){if(!(a instanceof jo)||a.status!==401)throw a;return this.tokenCache.delete(n,o),s=await this.getUserToken(n,r),i(s)}}async generateSignUrl(t,r,i){if(!t.trim())throw new Error("fileUrl is required for mbh-chat generateSignUrl");let n=this.context(i),o=await this.withUserToken(r,i,s=>this.client.post("/user/generateSignUrl",{loudPlatform:0,fileName:t},{appId:n.appId,userToken:s,...i?.signal?{signal:i.signal}:{}}));if(Number(o.code)!==0||!o.data?.filePath)throw Rh("mbh-chat generateSignUrl",o);return o.data.filePath}async getMyExpertDownloadUrl(t,r,i={}){let n=t.trim(),o=r.trim();if(!n)throw new Error("cloneCode is required for Agent package lookup");if(!o)throw new Error("botToken is required for mbh-chat Agent package lookup");let s=this.context(i),a=AE(i.userId,s.userId,"_userId"),c=zoe(i.businessUserId)??a,u=AE(i.domainId,this.config.domainId,"_domainId"),l=AE(i.appId,this.config.appId,"_appId"),d=await this.withUserToken(o,i,h=>this.client.post("/skill-market/v1/user_expert/get_my_expert_list",{_orgId:Loe,_domainId:u,user_id:c,bot_token:o,page_no:1,key_word:Foe(n),page_size:200,with_download:!0,_userId:a},{appId:l,userToken:h,...i.signal?{signal:i.signal}:{}}));if(Number(d.code)!==0)throw Rh("mbh-chat Agent package lookup",d);let p=ye(d.data)?.list;if(!Array.isArray(p))throw new Error("mbh-chat Agent package lookup returned an invalid list");let f=p.map(h=>ye(h)).map(h=>nt(h?Ae(h,"downloadUrl","download_url"):void 0)).find(Boolean);if(!f)throw new Error(`Agent ${n} has no downloadable package`);return f}async getStsToken(t,r,i,n){if(!t.trim())throw new Error("sourceFileName is required for mbh-chat STS credentials");let o=this.context(n),s=await this.withUserToken(r,n,a=>this.client.post("/user/getStsTokenByAsync",{sourceFileName:t,isPrivate:i},{appId:o.appId,userToken:a,...n?.signal?{signal:n.signal}:{}}));if(!s.data?.bucket)throw Rh("mbh-chat STS credential lookup",s);return s.data}};var vV=Br(yV(),1);import{extname as Fye}from"node:path";import{fileURLToPath as zye}from"node:url";var Uye=vV.default,Bye=1024*1024,Wye=900*1e3;function Vye(e){if(typeof e=="string"){let t=e.trim();if(t.startsWith("file:"))try{return zye(t)}catch{return e}return e}if(Buffer.isBuffer(e))return e;if(e&&typeof e=="object"){if(ArrayBuffer.isView(e)&&!(e instanceof DataView)&&!Buffer.isBuffer(e)){let i=e;return Buffer.from(i.buffer,i.byteOffset,i.byteLength)}let t=e,r=t.path??t.filePath;if(typeof r=="string"&&r.trim())return r.trim()}return e}var Zye={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".bmp":"image/bmp",".svg":"image/svg+xml",".ico":"image/x-icon",".avif":"image/avif",".heic":"image/heic",".heif":"image/heif",".pdf":"application/pdf",".mp4":"video/mp4",".webm":"video/webm",".mov":"video/quicktime",".mp3":"audio/mpeg",".wav":"audio/wav",".ogg":"audio/ogg",".opus":"audio/opus",".m4a":"audio/mp4",".aac":"audio/aac",".flac":"audio/flac",".txt":"text/plain; charset=utf-8",".log":"text/plain; charset=utf-8",".csv":"text/csv; charset=utf-8",".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"text/javascript; charset=utf-8",".mjs":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".xml":"application/xml; charset=utf-8",".md":"text/markdown; charset=utf-8",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation"};function YT(e){let t=e.split(/[/\\]/).pop()??e,r=Fye(t).toLowerCase();return r?Zye[r]:void 0}function Hye(e,t){if(typeof e=="string")return YT(e)??"application/octet-stream";if(Buffer.isBuffer(e)){if(t){let n=YT(t);if(n)return n}return"application/octet-stream"}let r=e.type?.trim();if(r&&r!=="application/octet-stream")return r;let i=typeof e.name=="string"&&e.name?e.name:"";if(i){let n=YT(i);if(n)return n}return r||"application/octet-stream"}function Gye(e){let t=e.split(";",1)[0]?.trim().toLowerCase()??"";return t==="image/svg+xml"||t==="application/xml"||t==="text/javascript"||t==="application/javascript"?"attachment":"inline"}async function Kye(e){if(Buffer.isBuffer(e))return{content:e,fileName:"file"};if(typeof e=="string")return{content:e,fileName:e.split(/[/\\]/).pop()??"file"};let t=Buffer.from(await e.arrayBuffer()),r=e.name;return{content:t,fileName:typeof r=="string"&&r?r:"file"}}var QT=class{api;logger;constructor(t,r){this.api=t,this.logger=r}async upload(t,r,i=1,n,o){let s=Vye(t),{content:a,fileName:c}=await Kye(s),u=await this.api.getStsToken(c,r,i,o),l=Hye(s,c),d=n?.onProgress,p={accessKeyId:u.tempAccessKeyId,accessKeySecret:u.tempAccessKeySecret,stsToken:u.tempSecurityToken,bucket:u.bucket,endpoint:u.endPoint,region:u.region,secure:!0,cname:!0,authorizationV4:!0,timeout:n?.timeoutMs??Wye},f=new Uye(p),h=`${u.uploadDir}${u.ossFileKey}`;try{let m,_={progress:y=>{d?.(y)},parallel:4,partSize:Bye,mime:l,headers:{"Content-Disposition":Gye(l)}};if(m=await f.multipartUpload(h,a,_),m?.res?.status!==200)throw new Error(`OSS upload failed with status ${m?.res?.status??"unknown"}`);let x=(m?.res?.requestUrls||[])[0]||"",v=i===1&&m.name||x;if(!v)throw new Error("OSS upload succeeded but returned no object name or URL");let g=i===1?await this.api.generateSignUrl(v,r,o):v;if(!g)throw new Error("OSS upload succeeded but returned no signed URL");return this.logger.info("OSS upload succeeded",{private:i===1}),g}catch(m){throw this.logger.error("OSS upload failed",{error:m instanceof Error?m.message:String(m)}),m}}};function bV(e,t){let r=new QT(e,t);return r.upload.bind(r)}var Yg=class{tails=new Map;generations=new Map;enqueue(t,r){let i=this.tails.get(t)??Promise.resolve(),n=this.generations.get(t)??0,o=i.catch(()=>{}).then(async()=>{(this.generations.get(t)??0)===n&&await r()});return this.tails.set(t,o),o.finally(()=>{this.tails.get(t)===o&&(this.tails.delete(t),this.generations.delete(t))}).catch(()=>{}),o}cancelPending(t){this.tails.has(t)&&this.generations.set(t,(this.generations.get(t)??0)+1)}cancelAllPending(){for(let t of this.tails.keys())this.cancelPending(t)}};import{randomUUID as tI}from"node:crypto";import nve from"node:fs";import Tr from"node:fs/promises";import ive from"node:os";import li from"node:path";import{resolveDshHome as ove,dshHomePath as sve,dshHomeDisplay as ave}from"@deepseek-ai/dsh-home-paths";var xV=Br(Y0(),1);import Xye from"node:fs";import _V from"node:fs/promises";import Vl from"node:path";import{Transform as Jye}from"node:stream";import{pipeline as Yye}from"node:stream/promises";var SV=500*1024*1024,eI=1024*1024*1024,wV=2e4;function Qye(e){if((e.flags&2048)!==0)return new TextDecoder("utf-8").decode(e.pathBuffer);try{return new TextDecoder("utf-8",{fatal:!0}).decode(e.pathBuffer)}catch{return new TextDecoder("gbk").decode(e.pathBuffer)}}function eve(e){let t=e.replaceAll("\\","/"),r=t.split("/").filter(Boolean);if(t.startsWith("/")||/^[a-z]:\//i.test(t)||r.some(i=>i==="."||i===".."))throw new Error(`skill archive contains an unsafe path: ${e}`);return t}function tve(e){let t=e.map(n=>n.replaceAll("\\","/").replace(/\/+$/,"")).filter(Boolean);if(t.length===0)return;let r=new Set(t.map(n=>n.split("/").filter(Boolean)[0]).filter(Boolean));if(r.size!==1)return;let i=[...r][0];return i&&t.some(n=>n.startsWith(`${i}/`))&&t.every(n=>n===i||n.startsWith(`${i}/`))?i:void 0}function rve(e,t){let r=Vl.resolve(e,t),i=Vl.relative(Vl.resolve(e),r);if(!i||i.startsWith("..")||Vl.isAbsolute(i))throw new Error(`skill archive contains an unsafe path: ${t}`);return r}var Qg=class extends Jye{limitBytes;budget;constructor(t,r){super(),this.limitBytes=t,this.budget=r}_transform(t,r,i){if(this.budget.used+=t.length,this.budget.used>this.limitBytes){i(new Error(`skill archive expands beyond ${this.limitBytes} bytes`));return}i(null,t)}};async function EV(e,t){let r=await xV.default.Open.buffer(e);if(r.files.length>wV)throw new Error(`skill archive exceeds ${wV} entries`);let i=r.files.reduce((a,c)=>a+c.uncompressedSize,0);if(!Number.isSafeInteger(i)||i>eI)throw new Error(`skill archive expands beyond ${eI} bytes`);let n=r.files.map(a=>eve(Qye(a))),o=tve(n),s={used:0};for(let a=0;a<r.files.length;a+=1){let c=r.files[a],u=n[a];if(!c||!u)continue;let l=u.replaceAll("\\","/");if(o&&(l===o||l===`${o}/`)||(o&&l.startsWith(`${o}/`)&&(l=l.slice(o.length+1)),l=l.replace(/\/+$/,""),!l))continue;let d=rve(t,l);if(c.type==="Directory"){await _V.mkdir(d,{recursive:!0});continue}if(c.type!=="File")throw new Error(`skill archive contains an unsupported entry: ${u}`);await _V.mkdir(Vl.dirname(d),{recursive:!0}),await Yye(c.stream(),new Qg(eI,s),Xye.createWriteStream(d,{mode:384}))}}var cve=/^[a-z0-9]+(?:-[a-z0-9]+)*$/;function ty(e){let t=Array.isArray(e.skills_scope)?ye(e.skills_scope[0]):void 0,r=Array.isArray(e.intent_recognition)?e.intent_recognition.map(ye).filter(c=>!!c).find(c=>nt(Ae(c,"biz_type","bizType")).toLowerCase()==="skill"):void 0,i=t??r;if(!i)return;let n=nt(Ae(i,"skill_code","skillCode"))||(i===r?nt(i.name):"");if(!n)return;let o=nt(Ae(i,"short_name","shortName","name"))||n,s=nt(Ae(i,"url","download_url","downloadUrl","skill_url","skillUrl")),a=Ae(i,"skill_id","skillId","id");return{code:n,url:s,name:o,...typeof a=="string"||typeof a=="number"?{id:a}:{}}}var ey=class{logger;options;dshHome;skillsRoot;skillsDisplayRoot;operations=new Map;constructor(t,r={}){this.logger=t,this.options=r,this.dshHome=ove(),this.skillsRoot=sve("skills"),this.skillsDisplayRoot=li.join(ave(this.dshHome),"skills")}normalizeCode(t){let r=t.trim();if(!cve.test(r))throw new Error(`invalid mbh-chat skill code: ${r||"<empty>"}`);return r}skillPath(t){return li.join(this.skillsRoot,this.normalizeCode(t))}skillDisplayPath(t){return li.join(this.skillsDisplayRoot,this.normalizeCode(t))}exists(t){try{return nve.existsSync(li.join(this.skillPath(t),"SKILL.md"))}catch{return!1}}install(t,r){return this.serialized(r,async()=>{let i,n;try{if(i=this.normalizeCode(r),n=this.skillPath(i),!t.trim())throw new Error("skill url is empty")}catch(c){return{success:!1,status:"fail",error:ne(c)}}let o=li.dirname(n),s=li.join(o,`.${i}.${tI()}.tmp`),a=li.join(o,`.${i}.${tI()}.bak`);try{await Tr.mkdir(o,{recursive:!0,mode:448}),await Hu(async()=>{await Tr.rm(s,{recursive:!0,force:!0}),await Tr.mkdir(s,{recursive:!0,mode:448});let u=await this.download(t);await EV(u,s);let l=li.join(s,"SKILL.md");if(!(await Tr.stat(l).catch(()=>{}))?.isFile())throw new Error("skill archive does not contain a root SKILL.md")});let c=await Tr.stat(n).then(()=>!0,()=>!1);c&&await Tr.rename(n,a);try{await Tr.rename(s,n)}catch(u){throw c&&await Tr.rename(a,n).catch(()=>{}),u}return await Tr.rm(a,{recursive:!0,force:!0}).catch(u=>{this.logger.warn("could not remove the previous mbh-chat skill backup",{code:i,error:ne(u)})}),this.logger.info("installed mbh-chat skill",{code:i,path:this.skillDisplayPath(i)}),{success:!0,status:"ok"}}catch(c){return await Tr.rm(s,{recursive:!0,force:!0}).catch(()=>{}),this.logger.error("mbh-chat skill installation failed",{code:i,error:ne(c)}),{success:!1,status:"fail",error:ne(c)}}})}uninstall(t){return this.serialized(t,async()=>{try{let r=this.normalizeCode(t),i=this.skillPath(r);return await Tr.rm(i,{recursive:!0,force:!0}),this.logger.info("uninstalled mbh-chat skill",{code:r,path:this.skillDisplayPath(r)}),{success:!0,status:"ok"}}catch(r){return this.logger.error("mbh-chat skill removal failed",{code:t,error:ne(r)}),{success:!1,status:"fail",error:ne(r)}}})}eventContent(t,r){return{event_type:"skill",operation_type:"install",skill_url:t.url,skill_code:t.code,...t.id!==void 0?{skill_id:t.id}:{},...r?{bot_token:r}:{}}}serialized(t,r){let i=t.trim(),o=(this.operations.get(i)??Promise.resolve({success:!0,status:"ok"})).catch(()=>{}).then(r);return this.operations.set(i,o),o.finally(()=>{this.operations.get(i)===o&&this.operations.delete(i)}),o}async download(t){let r=await Tr.mkdtemp(li.join(ive.tmpdir(),"mbh-chat-skill-"));try{let i=await Vs([{url:t,name:"skill.zip"}],{storageRoot:r,requestId:tI(),maxBytes:SV,maxFiles:1,maxInlineImageBytes:1,fetchTimeoutMs:18e4,concurrency:1,allowPrivateNetwork:this.options.allowPrivateNetwork??!1,...this.options.fetchImpl?{fetchImpl:this.options.fetchImpl}:{}}),n=i.media[0];if(!n)throw new Error(i.failures[0]?.reason||"skill download failed");return await Tr.readFile(n.localPath)}finally{await Tr.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}};import{randomUUID as kV}from"node:crypto";var rI=class{baseUrl;logger;sessionCookie;socket;streams=new Map;opening;closed;constructor(t,r,i){this.baseUrl=t,this.logger=r,this.sessionCookie=i}async*open(t,r,i,n){let o=kV(),s=[],a,c=l=>{s.push(l),a?.(),a=void 0};this.streams.set(o,c);let u=()=>{this.send({type:"cancel",streamId:o}),c({kind:"end"})};i.addEventListener("abort",u,{once:!0});try{if(await this.ensureOpen(),this.closed)throw this.closed;for(this.send({type:"open",streamId:o,endpoint:t,payload:r}),n?.(),i.aborted&&u();;){for(;s.length>0;){let l=s.shift();if(!l||l.kind==="end")return;if(l.kind==="error")throw l.error;yield l.value}await new Promise(l=>{a=l})}}finally{i.removeEventListener("abort",u),this.streams.delete(o),i.aborted||this.send({type:"cancel",streamId:o})}}close(t){this.closed=t??new Error("mbh-chat Remote mux closed");for(let i of this.streams.values())i({kind:"end"});this.streams.clear();let r=this.socket;this.socket=void 0,this.opening=void 0,r&&(r.readyState===rr.CONNECTING?r.terminate():r.readyState===rr.OPEN&&r.close(1e3,"bridge stream stopped"))}async ensureOpen(){if(this.socket?.readyState===rr.OPEN)return;if(this.opening)return this.opening;let t=new URL("/api/remote.mux",this.baseUrl);t.protocol=t.protocol==="https:"?"wss:":"ws:";let r=new rr(t,{headers:vn(this.sessionCookie)});this.socket=r,this.opening=new Promise((i,n)=>{let o=s=>{this.close(s),n(s)};r.once("open",()=>{r.once("close",()=>this.close(new Error("mbh-chat Remote mux closed"))),i()}),r.once("error",s=>o(s instanceof Error?s:new Error(String(s))))}),r.on("message",(i,n)=>{if(n){this.logger.warn("dropping binary mbh-chat WebSocket frame",{path:"/api/remote.mux"});return}let o;try{o=JSON.parse(i.toString())}catch(a){this.logger.warn("dropping malformed mbh-chat Remote mux frame",{error:a instanceof Error?a.message:String(a)});return}let s=this.streams.get(o.streamId);s&&(o.type==="item"?s({kind:"frame",value:o.value}):o.type==="error"?s({kind:"error",error:new Error(`mbh-chat ${o.error.code}: ${o.error.message}`)}):s({kind:"end"}))}),await this.opening}send(t){this.socket?.readyState===rr.OPEN&&this.socket.send(JSON.stringify(t))}},ry=class{baseUrl;logger;timeoutMs;sessionCookie;mux;eventClientId;constructor(t,r,i=3e4,n=Ih()){this.baseUrl=t,this.logger=r,this.timeoutMs=i,this.sessionCookie=n}sessions={create:(t,r)=>this.invoke("session/create",{request:t},r),prompt:(t,r)=>this.invoke("session/prompt",{request:t},r),cancel:(t,r)=>this.invoke("session/cancel",{request:t},r),selectModel:(t,r)=>this.invoke("session/selectModel",{request:t},r),modelCatalog:t=>this.invoke("session/modelCatalog",{},t),follow:(t,r,i)=>this.openStream("session/follow",{request:t},r,i)};openEvents(t,r){return this.openStream("$events",{},t,r)}respondEvent(t,r){let i=t.clientId??this.eventClientId;if(!i)throw new Error("mbh-chat event stream is not ready");return this.invoke("$events/result",{clientId:i,eventId:t.eventId,outcome:t.outcome},r)}disconnect(){this.eventClientId=void 0,this.mux?.close(),this.mux=void 0}async invoke(t,r,i){let n=kV(),o=await fetch(new URL(`/api/${t}`,this.baseUrl),{method:"POST",headers:vn(this.sessionCookie,{"Content-Type":"application/json"}),body:JSON.stringify({type:"client-request",rpcId:n,method:t,payload:{args:r}}),signal:i?AbortSignal.any([i,AbortSignal.timeout(this.timeoutMs)]):AbortSignal.timeout(this.timeoutMs)});if(!o.ok)throw Object.assign(new Error(`mbh-chat ${t} returned HTTP ${o.status}`),{code:"http-error"});return await o.json()}openStream(t,r,i,n){return this.mux??=new rI(this.baseUrl,this.logger,this.sessionCookie),this.mux.open(t,{args:r},i,n)}};function An(e){if(e.result.ok)return e.result.value;let t=new Error(`mbh-chat ${e.result.error.code}: ${e.result.error.message}`);throw Object.assign(t,{code:e.result.error.code}),t}function uve(e){if(!(typeof e!="object"||e===null||!("code"in e)))return typeof e.code=="string"?e.code:void 0}var lve=new Set(["session/not-found","session-not-found"]);function nI(e){return e!==void 0&&lve.has(e)}function iI(e){return nI(uve(e))}function TV(){let e,t;return{promise:new Promise((i,n)=>{e=i,t=n}),resolve:e,reject:t}}var fve=3e3;function dve(e,t,r){let i=Math.min(r,t*2**Math.min(e,8));return i+Math.floor(Math.random()*Math.max(1,Math.min(1e3,i/5)))}function IV(e,t){return new Promise(r=>{if(t.aborted)return r();let i=setTimeout(n,e);function n(){clearTimeout(i),t.removeEventListener("abort",n),r()}t.addEventListener("abort",n,{once:!0})})}var ny=class{reconnectMinMs;reconnectMaxMs;logger;api;rootAbort;generationAbort;handlers;loopPromise;connected=!1;followedSessions=new Set;followAborts=new Map;followReadiness=new Map;liveFollows=new Set;connectionWaiters=new Set;constructor(t,r,i,n){this.reconnectMinMs=r,this.reconnectMaxMs=i,this.logger=n,this.api=new ry(t,n)}start(t){if(this.loopPromise)throw new Error("mbh-chat connection already started");this.handlers=t,this.rootAbort=new AbortController,this.loopPromise=this.run(t,this.rootAbort.signal)}async stop(){this.rootAbort?.abort();let t=new Error("mbh-chat connection stopped before becoming ready");for(let r of this.connectionWaiters)r.reject(t);this.connectionWaiters.clear();for(let r of this.followReadiness.values())r.reject(t);this.followReadiness.clear(),this.liveFollows.clear(),await this.loopPromise,this.loopPromise=void 0,this.rootAbort=void 0,this.handlers=void 0,this.api.disconnect()}isConnected(){return this.connected}followSession(t){if(this.followedSessions.add(t),this.liveFollows.has(t))return Promise.resolve();let r=this.followReadiness.get(t);r||(r=TV(),this.followReadiness.set(t,r)),this.connected&&this.generationAbort&&!this.followAborts.has(t)&&this.startFollow(t,this.generationAbort.signal);let i=r.promise;return i.catch(()=>{}),Promise.race([i,IV(fve,this.generationAbort?.signal??new AbortController().signal).then(()=>{this.liveFollows.has(t)||this.logger.warn("mbh-chat session follow was not ready before timeout",{sessionId:t})})])}unfollowSession(t){this.followedSessions.delete(t),this.liveFollows.delete(t),this.followAborts.get(t)?.abort(),this.followAborts.delete(t),this.followReadiness.get(t)?.reject(new Error(`mbh-chat stopped following session ${t}`)),this.followReadiness.delete(t)}whenConnected(t){return this.connected?Promise.resolve():new Promise((r,i)=>{let n=()=>{a(),r()},o=u=>{a(),i(u)},s=()=>o(t?.reason??new Error("waiting for mbh-chat connection was aborted")),a=()=>{this.connectionWaiters.delete(c),t?.removeEventListener("abort",s)},c={resolve:n,reject:o};this.connectionWaiters.add(c),t?.addEventListener("abort",s,{once:!0}),t?.aborted&&s()})}async setConnected(t,r){if(t||(this.connected=!1),await r.onConnection?.(t),t){this.connected=!0;for(let i of this.connectionWaiters)i.resolve();this.connectionWaiters.clear()}}async run(t,r){let i=0;for(;!r.aborted;){let n=new AbortController;this.generationAbort=n;let o=()=>n.abort();r.addEventListener("abort",o,{once:!0});let s=TV(),a=!1,c;try{c=this.pumpEvents(t,n.signal,s.resolve);let u=c.then(()=>{throw new Error("a mbh-chat event stream closed")});await Promise.race([s.promise,u]),a=!0,i=0,await this.setConnected(!0,t);for(let l of this.followedSessions)this.startFollow(l,n.signal);await u}catch(u){r.aborted||this.logger.warn("mbh-chat connection lost",{error:ne(u)})}finally{if(this.generationAbort=void 0,n.abort(),this.stopFollows(),this.api.disconnect(),await Promise.allSettled(c?[c]:[]),r.removeEventListener("abort",o),a)try{await this.setConnected(!1,t)}catch(u){this.logger.error("mbh-chat connection-state handler failed during disconnect",{error:ne(u)})}}if(!r.aborted){let u=dve(i++,this.reconnectMinMs,this.reconnectMaxMs);this.logger.info("reconnecting to mbh-chat Host",{delayMs:u,attempt:i}),await IV(u,r)}}}async pumpEvents(t,r,i){let n=!1;for await(let o of this.api.openEvents(r)){if(o.type==="ready"){this.api.eventClientId=o.clientId,n||(n=!0,i());continue}try{await t.onRemoteEvent(o)}catch(s){this.logger.error("mbh-chat event handler failed",{error:ne(s)})}}}markFollowReady(t){this.liveFollows.add(t),this.followReadiness.get(t)?.resolve()}async startFollow(t,r){if(this.followAborts.has(t))return;let i=new AbortController;this.followAborts.set(t,i);let n=AbortSignal.any([r,i.signal]),o=!1;try{for await(let s of this.api.sessions.follow({address:{kind:"session",sessionId:t}},n)){if(s.type==="snapshot"){o=!0,this.markFollowReady(t);continue}if(s.type==="event")try{this.handlers?.onSessionEvent(t,s.event)}catch(a){this.logger.error("mbh-chat session event handler failed",{sessionId:t,error:ne(a)})}}if(!n.aborted&&!o)throw new Error(`mbh-chat session follow ended before receiving a snapshot for ${t}`)}catch(s){!r.aborted&&!i.signal.aborted&&(this.followReadiness.get(t)?.reject(s),this.logger.warn("mbh-chat session follow ended",{sessionId:t,error:ne(s)}))}finally{this.followAborts.get(t)===i&&this.followAborts.delete(t),this.liveFollows.delete(t)}}stopFollows(){for(let t of this.followAborts.values())t.abort();this.followAborts.clear(),this.liveFollows.clear()}};async function OV(e,t,r,i){let n=new Map;for(let u of e.store.listActiveSubagentsForRoot(t))(!r||u.requestId===r)&&n.set(u.childSessionId,u.parentSessionId);for(let[u,l]of i??[])n.set(u,l);let o=!1,s=!1,a,c=u=>{e.store.settleSubagent(u,"cancelled"),n.delete(u)};for(let u=1;u<=e.config.task.maxAttempts;u+=1){let l=p=>{let f=0,h=p,m=new Set;for(;!m.has(h);){m.add(h);let _=n.get(h);if(!_)break;f+=1,h=_}return f},d=[...n].sort(([p],[f])=>l(f)-l(p));for(let[p,f]of d)try{An(await e.dsh.api.sessions.cancel({sessionId:p})),c(p)}catch(h){if(iI(h)){c(p);continue}a=h,e.logger.warn("subagent interrupt failed",{parentSessionId:f,childSessionId:p,attempt:u,error:ne(h)})}if(!o)try{An(await e.dsh.api.sessions.cancel({sessionId:t})),o=!0}catch(p){iI(p)?(o=!0,s=!0):(a=p,e.logger.warn("model/tool cancellation failed",{dshSessionId:t,attempt:u,error:ne(p)}))}if(o&&n.size===0)return s?"absent":"cancelled";if(u<e.config.task.maxAttempts){let p=Math.min(e.config.task.retryMaxMs,e.config.task.retryBaseMs*2**(u-1));await new Promise(f=>setTimeout(f,p))}}throw a instanceof Error?a:new Error("execution cancellation could not be confirmed")}var pve=/request id\s*:\s*([a-z0-9_-]{1,128})/iu,hve=new RegExp("\\p{Script=Han}","u");function mve(e){let t=pve.exec(e)?.[1];return t?`\uFF08\u8BF7\u6C42 ID\uFF1A${t}\uFF09`:""}function gve(e,t){let r=e?.trim();return r?r.slice(0,120):t}function yve(e){let t=ne(e).trim(),r=mve(t),i=/range of max_tokens should be \[\s*(\d+)\s*,\s*(\d+)\s*\]/iu.exec(t);if(i)return`\u6A21\u578B\u751F\u6210\u957F\u5EA6\u53C2\u6570\uFF08max_tokens\uFF09\u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF0C\u6709\u6548\u8303\u56F4\u4E3A ${i[1]}\u2013${i[2]}\u3002${r}`;let n=/no available channel for model\s+(.+?)\s+under group\b/iu.exec(t);return n?`\u6A21\u578B ${gve(n[1],"\u5F53\u524D\u6A21\u578B")} \u5F53\u524D\u6682\u65E0\u53EF\u7528\u670D\u52A1\u901A\u9053\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/no available channel/iu.test(t)?`\u5F53\u524D\u6A21\u578B\u6682\u65E0\u53EF\u7528\u670D\u52A1\u901A\u9053\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/tokenization failed/iu.test(t)?`\u6A21\u578B\u65E0\u6CD5\u5904\u7406\u5F53\u524D\u8F93\u5165\uFF0C\u8BF7\u7F29\u77ED\u5185\u5BB9\u6216\u5207\u6362\u6A21\u578B\u540E\u91CD\u8BD5\u3002${r}`:/completed response with no content|empty response|no content returned/iu.test(t)?`\u6A21\u578B\u672A\u8FD4\u56DE\u6709\u6548\u5185\u5BB9\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/context length|maximum context|context window|too many tokens/iu.test(t)?`\u5BF9\u8BDD\u5185\u5BB9\u8D85\u8FC7\u6A21\u578B\u53EF\u5904\u7406\u7684\u957F\u5EA6\uFF0C\u8BF7\u7F29\u77ED\u5185\u5BB9\u6216\u65B0\u5EFA\u4F1A\u8BDD\u3002${r}`:/\b(401|unauthorized|invalid api.?key|authentication)\b/iu.test(t)?`\u6A21\u578B\u670D\u52A1\u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u670D\u52A1\u914D\u7F6E\u3002${r}`:/\b(403|forbidden|permission denied)\b/iu.test(t)?`\u5F53\u524D\u8D26\u53F7\u65E0\u6743\u8BBF\u95EE\u8BE5\u6A21\u578B\uFF0C\u8BF7\u68C0\u67E5\u6A21\u578B\u6743\u9650\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/\b(429|rate.?limit|too many requests|overload|busy)\b/iu.test(t)?`\u6A21\u578B\u670D\u52A1\u5F53\u524D\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`:/timeout|timed out/iu.test(t)?`\u6A21\u578B\u670D\u52A1\u54CD\u5E94\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`:/\b5\d\d\b|bad gateway|service unavailable|upstream.*(?:error|failed)/iu.test(t)?`\u4E0A\u6E38\u6A21\u578B\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`:/invalidparameter|invalid parameter|\b400\b|bad request/iu.test(t)?`\u6A21\u578B\u8BF7\u6C42\u53C2\u6570\u4E0D\u6B63\u786E\uFF0C\u8BF7\u68C0\u67E5\u6A21\u578B\u914D\u7F6E\u3002${r}`:hve.test(t)?t.replace(/^\[错误\]\s*/u,""):`\u6A21\u578B\u670D\u52A1\u8C03\u7528\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`}function bc(e){return`[\u9519\u8BEF] ${yve(e)}`}var $V=2e3;function Qi(e){return e.time/1e3+e.seq/1e9}function iy(e,t){return Array.isArray(e)?e.map(r=>{let i=ye(r);return i?.type===t&&typeof i.text=="string"?i.text:""}).join(""):""}function oI(e,t){let r=e.trim()||t;return r.length<=$V?r:`${r.slice(0,$V)}\u2026\u2026\uFF08\u5185\u5BB9\u5DF2\u622A\u65AD\uFF09`}function sI(e){return Array.isArray(e)?e.map(t=>{let r=ye(t);if(!r)return"";if((r.type==="text"||r.type==="reasoning")&&typeof r.text=="string")return r.text;if(r.type==="image")return"[\u56FE\u7247]";try{return JSON.stringify(r)}catch{return"[\u65E0\u6CD5\u5C55\u793A\u7684\u5DE5\u5177\u7ED3\u679C]"}}).filter(Boolean).join(`
|
|
578
|
+
`)})}}var cl=class{baseUrl;fetchImpl;sessionCookie;constructor(t,r=fetch,i=Ih()){this.baseUrl=t,this.fetchImpl=r,this.sessionCookie=i}url(t){return new URL(t,this.baseUrl.endsWith("/")?this.baseUrl:`${this.baseUrl}/`)}async patch(t,r){return(await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}`),{method:"PATCH",headers:vn(this.sessionCookie,{"content-type":"application/json"}),body:JSON.stringify(r),signal:AbortSignal.timeout(15e3)})).ok}async patchJob(t,r){let i=await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}`),{method:"PATCH",headers:vn(this.sessionCookie,{"content-type":"application/json"}),body:JSON.stringify(r),signal:AbortSignal.timeout(15e3)});if(!i.ok)return;let n=await i.json().catch(()=>{});return al({type:Na,version:1,jobs:[n]}).jobs.find(o=>o.id===t)}setEnabled(t,r){return this.patch(t,{enabled:r})}async delete(t){let r=await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}`),{method:"DELETE",headers:vn(this.sessionCookie),signal:AbortSignal.timeout(15e3)});return r.ok?"deleted":r.status===404?"not_found":"failed"}async runOnce(t){let r=await this.fetchImpl(this.url(`${Fi}/${encodeURIComponent(t)}/run`),{method:"POST",headers:vn(this.sessionCookie),signal:AbortSignal.timeout(15e3)}),i=await r.json().catch(()=>{}),n=Dr(i)&&typeof i.status=="string"?i.status:void 0;return n==="dispatched"||n==="not_found"||n==="already_running"||n==="delivery_unavailable"?n:r.status===404?"not_found":r.status===202?"already_running":r.ok&&Dr(i)&&i.delivered===!0?"dispatched":"delivery_unavailable"}async list(){let t=await this.fetchImpl(this.url(`${Fi}`),{method:"GET",headers:vn(this.sessionCookie),signal:AbortSignal.timeout(15e3)});if(!t.ok)return;let r=await t.json().catch(()=>{});if(!(!Dr(r)||!Array.isArray(r.jobs)))return al({type:Na,version:1,sequence:0,generatedAt:new Date().toISOString(),reason:"fetch",jobs:r.jobs})}async subscribe(t,r,i=()=>{}){let n=await this.fetchImpl(this.url(`${Fi}/events`),{method:"GET",headers:vn(this.sessionCookie,{accept:"text/event-stream"}),signal:r});if(!n.ok||!n.body)throw new Error(`cron SSE failed with HTTP ${n.status}`);let o=n.body.getReader(),s=new TextDecoder,a="";for(;;){let{value:c,done:u}=await o.read();if(u){if(!r.aborted)throw new Error("cron SSE stream ended");return}a+=s.decode(c,{stream:!0});let{events:l,rest:d}=koe(a);a=d;for(let p of l)if(p.event==="cron-list")try{t(al(JSON.parse(p.data)))}catch(f){i(f)}}}};var Toe=100,Ioe=1e3,Ooe=3e4;function CE(e){let{updatedAtMs:t,state:r,...i}=e;return JSON.stringify(i,(n,o)=>o&&typeof o=="object"&&!Array.isArray(o)?Object.fromEntries(Object.entries(o).sort(([s],[a])=>s.localeCompare(a))):o)}function $oe(e,t){return new Promise(r=>{if(e.aborted){r();return}let i=()=>{clearTimeout(n),e.removeEventListener("abort",i),r()},n=setTimeout(i,t);n.unref(),e.addEventListener("abort",i,{once:!0})})}var Oh=class{options;client;abort;loop;debounce;publishTail=Promise.resolve();lastFingerprint;lastContext;lastSnapshot;lastJobs=new Map;lastContexts=new Map;constructor(t){this.options=t,this.client=new cl(t.dshBaseUrl,t.fetchImpl)}start(){if(this.loop)return;let t=this.options.store.getLatestContext();t&&(this.lastContext=t),this.abort=new AbortController,this.loop=this.run(this.abort.signal)}async stop(){this.abort?.abort(),this.debounce&&clearTimeout(this.debounce),this.debounce=void 0,await this.loop?.catch(()=>{}),await this.publishTail,this.loop=void 0,this.abort=void 0}async applyControl(t,r){if(t==="remove"){let n=await this.client.delete(r);return{applied:n!=="failed",...n==="not_found"?{reconciled:!0}:{}}}if(t==="enable")return{applied:await this.client.setEnabled(r,!0)};if(t==="disable")return{applied:await this.client.setEnabled(r,!1)};await this.ensureSessionForCron(r),await this.ensureSessionFollowed(r);let i=await this.client.runOnce(r);return i==="delivery_unavailable"&&(i=await this.rebindAndRetryRun(r,i)),{applied:i==="dispatched"||i==="already_running",runStatus:i}}notifySessionAvailable(){this.lastSnapshot&&this.schedulePublish(this.lastSnapshot)}businessKeyForCronId(t){let r=this.lastSnapshot?.jobs.find(i=>i.id===t);if(r)return this.sessionKeyFor(r)}async bindDshSessionId(t,r){if(!bn(t))return;let i=this.lastSnapshot??await this.client.list();if(!i)return;let n=i.jobs.filter(o=>o.sessionKey===t&&(!o.dshSessionId||o.dshSessionId!==r));n.length!==0&&await Promise.all(n.map(async o=>{await this.client.patch(o.id,{dshSessionId:r})?(this.options.logger.info("bound cron job to mbh-chat session",{cronId:o.id,sessionKey:t,dshSessionId:r}),this.followCronSession(r)):this.options.logger.warn("failed to patch cron dshSessionId binding",{cronId:o.id,sessionKey:t,dshSessionId:r})}))}async bindAllKnownDshSessions(){let t=this.lastSnapshot??await this.client.list();if(!t)return;let r=new Map;for(let i of t.jobs){if(!i.sessionKey||!bn(i.sessionKey))continue;let n=this.options.store.getSession(i.sessionKey);!n||i.dshSessionId===n||r.set(i.id,n)}r.size!==0&&await Promise.all([...r.entries()].map(async([i,n])=>{await this.client.patch(i,{dshSessionId:n})?(this.options.logger.info("bound cron job to pre-existing mbh-chat session",{cronId:i,dshSessionId:n}),this.followCronSession(n)):this.options.logger.warn("failed to patch cron dshSessionId binding",{cronId:i,dshSessionId:n})}))}async run(t){let r=0;for(;!t.aborted;)try{await this.client.subscribe(i=>this.schedulePublish(i),t,i=>this.options.logger.warn("ignored invalid cron catalog SSE event",{error:ne(i)})),r=0}catch(i){if(t.aborted)return;r+=1;let n=Math.min(Ooe,Ioe*2**Math.min(r-1,8));this.options.logger.warn("cron catalog SSE disconnected; retrying",{delayMs:n,error:ne(i)}),await $oe(t,n)}}schedulePublish(t){this.lastSnapshot=t,this.debounce&&clearTimeout(this.debounce),this.debounce=setTimeout(()=>{this.debounce=void 0,this.publishTail=this.publishTail.then(()=>this.publish(t)).catch(r=>this.options.logger.warn("failed to publish cron catalog to Mobook",{error:ne(r)}))},this.options.debounceMs??Toe),this.debounce.unref()}async rebindAndRetryRun(t,r){let n=(await this.client.list().catch(()=>{}))?.jobs.find(s=>s.id===t);if(!n?.sessionKey||!bn(n.sessionKey))return r;let o=this.options.store.getSession(n.sessionKey);return!o||o===n.dshSessionId||!await this.client.patch(t,{dshSessionId:o})?r:(this.options.logger.info("rebound stale cron DSH session before manual run",{cronId:t,dshSessionId:o}),await this.followCronSession(o),this.client.runOnce(t))}async ensureSessionForCron(t){let i=(await this.client.list().catch(()=>{}))?.jobs.find(o=>o.id===t);if(!i?.sessionKey||!bn(i.sessionKey))return;let n=this.options.store.getSession(i.sessionKey);n||(n=await this.options.provisionSession?.(i)),n&&i.dshSessionId!==n&&await this.client.patch(t,{dshSessionId:n})&&this.options.logger.info("provisioned cron DSH session before dispatch",{cronId:t,dshSessionId:n})}contextFor(t){if(t.sessionKey){let i=this.options.store.getLatestContextForBusinessKey(t.sessionKey);if(i)return i}let r=this.options.store.getBusinessKeyByDshSessionId(t.dshSessionId??t.agentId);return r?this.options.store.getLatestContextForBusinessKey(r):void 0}sessionKeyFor(t){return t.sessionKey?t.sessionKey:this.options.store.getBusinessKeyByDshSessionId(t.dshSessionId??t.agentId)}adoptionOwner(){let t=this.lastContext??this.options.store.getLatestContext?.();if(!t||!bn(t.businessKey))return;let r=zi(t.businessKey).agentId;return r?{businessKey:t.businessKey,agentId:r}:void 0}isForeignOwner(t,r){return!t||!bn(t)?!0:zi(t).agentId!==r}send(t,r){return this.options.dcg.enqueueEvent(t,r)!==!1}async publish(t){let r=this.adoptionOwner(),i=[];for(let l of t.jobs){let d=this.sessionKeyFor(l);if(r&&this.isForeignOwner(d,r.agentId)&&(d=r.businessKey),!d){i.push(l);continue}let p=zi(d),f=this.options.store.getSession(d),h={...l.sessionKey===d?{}:{sessionKey:d},...f&&l.dshSessionId!==f?{dshSessionId:f}:{},...p.agentId&&l.agentId!==p.agentId?{agentId:p.agentId}:{}};if(Object.keys(h).length>0){let m=await this.client.patchJob(l.id,h);if(!m){this.options.logger.warn("failed to persist cron sessionKey binding",{cronId:l.id});return}i.push(m)}else i.push(l)}let n=$E(i,l=>this.sessionKeyFor(l)),o=JSON.stringify(n.jobs.map(l=>[l.id,CE(l)]).sort());if(o===this.lastFingerprint)return;if(t.jobs.length>0&&n.jobs.length===0){this.options.logger.warn("skipping Mobook cron catalog publish; no mbh-chat session mapping is available yet");return}let s=new Set(n.jobs.map(l=>l.id)),a=new Set,c=new Set;for(let l of n.jobs){let d=CE(l);if(this.lastJobs.get(l.id)===d)continue;let p=i.find(h=>h.id===l.id),f=p?this.contextFor(p):void 0;if(!f&&p?.sessionKey&&bn(p.sessionKey)&&(await this.ensureSessionForCron(p.id),f=this.contextFor(p)),!f){this.options.logger.warn("skipping cron install; no mapped mbh-chat session is available",{cronId:l.id}),a.add(l.id);continue}if(!this.send(f,{event_type:"cron",operation_type:"install",data:l})){this.options.logger.warn("cron install event was not sent; will retry",{cronId:l.id});return}this.lastJobs.set(l.id,d),this.lastContexts.set(l.id,f),this.lastContext=f,this.lastFingerprint=void 0,this.options.logger.info("enqueued cron install to Mobook",{cronId:l.id,sequence:t.sequence})}if(t.invalidJobCount===0)for(let l of this.lastJobs.keys()){if(s.has(l))continue;let d=this.lastContexts.get(l);if(!d){this.options.logger.warn("skipping cron remove; no mapped mbh-chat session is available",{cronId:l}),c.add(l);continue}if(!this.send(d,{event_type:"cron",operation_type:"remove",data:{id:l,jobId:l,action:"removed"}})){this.options.logger.warn("cron remove event was not sent; will retry",{cronId:l});return}this.lastJobs.delete(l),this.lastContexts.delete(l),this.lastFingerprint=void 0}else this.options.logger.warn("cron snapshot contained invalid jobs; preserving previously published jobs",{invalidJobCount:t.invalidJobCount});let u=new Map([...this.lastJobs].filter(([l])=>s.has(l)||c.has(l)));for(let l of n.jobs)a.has(l.id)||u.set(l.id,CE(l));if(t.invalidJobCount>0)for(let[l,d]of this.lastJobs)u.has(l)||u.set(l,d);this.lastJobs=u,this.lastFingerprint=t.invalidJobCount===0&&a.size===0&&c.size===0?o:void 0,this.followBoundJobs(i),this.options.logger.info("published cron catalog to Mobook",{jobs:n.jobs.length,sequence:t.sequence})}async ensureSessionFollowed(t){let i=(this.lastSnapshot??await this.client.list().catch(()=>{}))?.jobs.find(s=>s.id===t);if(!i)return;let n=this.sessionKeyFor(i),o=(n?this.options.store.getSession(n):void 0)||i.dshSessionId;o&&await this.followCronSession(o)}followBoundJobs(t){let r=new Set;for(let i of t){let n=this.sessionKeyFor(i),o=(n?this.options.store.getSession(n):void 0)||i.dshSessionId;!o||r.has(o)||(r.add(o),this.followCronSession(o))}}async followCronSession(t){this.options.followSession&&await this.options.followSession(t)}};import{timingSafeEqual as Coe}from"node:crypto";import Pa from"node:fs";import Aoe from"node:http";import Roe from"node:path";var hL=1024*1024,Wke=64*1024;function Doe(e,t){if(!e?.startsWith("Bearer "))return!1;let r=Buffer.from(e.slice(7)),i=Buffer.from(t);return r.length===i.length&&Coe(r,i)}async function Noe(e){let t=[],r=0;for await(let i of e){let n=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=n.length,r>hL)throw new Error(`request body exceeds ${hL} bytes`);t.push(n)}return JSON.parse(Buffer.concat(t).toString("utf8"))}function qa(e,t,r){let i=JSON.stringify(r);e.writeHead(t,{"content-type":"application/json; charset=utf-8","content-length":Buffer.byteLength(i)}),e.end(i)}var $h=class{socketPath;token;handler;statusProvider;server;constructor(t,r,i,n){this.socketPath=t,this.token=r,this.handler=i,this.statusProvider=n}async start(){if(this.server)throw new Error("message control server already started");if(process.platform!=="win32"){Pa.mkdirSync(Roe.dirname(this.socketPath),{recursive:!0});try{if(!Pa.lstatSync(this.socketPath).isSocket())throw new Error(`refusing to replace non-socket control path: ${this.socketPath}`);Pa.unlinkSync(this.socketPath)}catch(r){if(r.code!=="ENOENT")throw r}}let t=Aoe.createServer((r,i)=>{this.handle(r,i)});this.server=t,await new Promise((r,i)=>{let n=s=>{t.off("listening",o),i(s)},o=()=>{t.off("error",n),r()};t.once("error",n),t.once("listening",o),t.listen(this.socketPath)}),process.platform!=="win32"&&Pa.chmodSync(this.socketPath,384)}async stop(){let t=this.server;if(this.server=void 0,t&&await new Promise(r=>t.close(()=>r())),process.platform!=="win32")try{Pa.lstatSync(this.socketPath).isSocket()&&Pa.unlinkSync(this.socketPath)}catch(r){if(r.code!=="ENOENT")throw r}}async handle(t,r){let i=t.method==="POST"&&t.url==="/v1/message",n=t.method==="GET"&&t.url==="/v1/status";if(!i&&!n){qa(r,404,{error:"not found"});return}if(!Doe(t.headers.authorization,this.token)){qa(r,401,{error:"unauthorized"});return}if(n){if(!this.statusProvider){qa(r,404,{error:"not found"});return}qa(r,200,this.statusProvider());return}let o=new AbortController,s=()=>o.abort(new Error("control client disconnected"));t.once("aborted",s);try{let a=await Noe(t),c=await this.handler(a,o.signal);qa(r,c.success?200:422,c)}catch(a){qa(r,400,{success:!1,sentMediaCount:0,queued:!1,error:a instanceof Error?a.message:String(a)})}finally{t.off("aborted",s)}}};import{createHash as Poe}from"node:crypto";var jo=class extends Error{status;constructor(t,r){super(t),this.status=r,this.name="DcgApiRequestError"}};function qoe(e){return e!==null&&typeof e=="object"?JSON.stringify(e):String(e)}function joe(e,t,r,i,n="1.0.0"){let o={timestamp:t,path:r,version:n,...e},s=Object.keys(o).sort().map(a=>o[a]===void 0?"":`${a}${qoe(o[a])}`).join("")+i;return Poe("md5").update(s).digest("hex").toUpperCase()}function Moe(e,t){try{let r=new URL(t,e);return`POST ${r.origin}${r.pathname}`}catch{return`POST ${t.split("?",1)[0]??""}`}}var Ch=class{config;logger;fetchImpl;timeoutMs;constructor(t,r,i=fetch,n=6e4){this.config=t,this.logger=r,this.fetchImpl=i,this.timeoutMs=n}async post(t,r,i={}){if(!t.startsWith("/")||t.startsWith("//"))throw new Error("mbh-chat API request path must be an origin-relative path");let n=new URL(this.config.apiBaseUrl),o=new URL(t,n);if(o.origin!==n.origin)throw new Error("mbh-chat API request path must stay on the configured origin");let s=typeof i.appId=="number"&&Number.isFinite(i.appId)?Math.trunc(i.appId):typeof i.appId=="string"&&i.appId.trim()?i.appId.trim():this.config.appId,a={...r,_appId:s},c=Date.now(),u=AbortSignal.timeout(this.timeoutMs),l=i.signal?AbortSignal.any([i.signal,u]):u,d=Moe(this.config.apiBaseUrl,t);try{let p=await this.fetchImpl(o,{method:"POST",signal:l,headers:{"content-type":"application/json",appKey:this.config.apiAppKey,sign:joe(a,c,t,this.config.apiSignKey,this.config.apiVersion),timestamp:String(c),version:this.config.apiVersion,...i.userToken?{authorization:i.userToken}:{}},body:JSON.stringify(a)});if(!p.ok)throw await p.body?.cancel(),new jo(`mbh-chat API request failed with HTTP ${p.status}`,p.status);let f=await p.json();if(!f||typeof f!="object"||Array.isArray(f))throw new jo("mbh-chat API returned a non-object JSON response",p.status);return f}catch(p){let f=p instanceof jo?p.status:void 0;throw this.logger.warn("mbh-chat API request failed",{request:d,...f!==void 0?{status:f}:{},error:p instanceof Error?p.message:String(p)}),p}}};var Ah=class{ttlMs;tokens=new Map;pending=new Map;constructor(t=3600*1e3){if(this.ttlMs=t,!Number.isFinite(t)||t<=0)throw new Error("user-token cache ttlMs must be positive")}key(t,r){return`${t}\0${r.userId}\0${r.appId}`}get(t,r){let i=this.key(t,r),n=this.tokens.get(i);if(n){if(Date.now()>=n.expiresAt){this.tokens.delete(i);return}return n.token}}set(t,r,i){this.tokens.set(this.key(t,r),{token:i,expiresAt:Date.now()+this.ttlMs})}delete(t,r){this.tokens.delete(this.key(t,r))}async getOrLoad(t,r,i){let n=this.get(t,r);if(n)return n;let o=this.key(t,r),s=this.pending.get(o);if(s)return s;let a=i().then(c=>{if(!c)throw new Error("mbh-chat user-token lookup returned an empty token");return this.set(t,r,c),c}).finally(()=>this.pending.delete(o));return this.pending.set(o,a),a}clear(){this.tokens.clear(),this.pending.clear()}};var Loe=1001;function Rh(e,t){let r=t.code===void 0?"unknown":String(t.code),i=typeof t.message=="string"?t.message.replace(/[\u0000-\u001f\u007f]+/g," ").slice(0,300):"";return new Error(`${e} failed (code=${r})${i?`: ${i}`:""}`)}function AE(e,t,r){let i=e==null||e===""?t:e,n=typeof i=="number"?i:Number(String(i).trim());if(!Number.isSafeInteger(n)||n<0)throw new Error(`${r} must be a non-negative safe integer`);return n}function Foe(e){let t=e.match(/^(.*?)-(\d+(?:-\d+)*)$/);return t?t[1]??"":""}function zoe(e){if(e==null||e==="")return;let t=typeof e=="number"?e:Number(String(e).trim());return Number.isSafeInteger(t)&&t>=0?t:void 0}var Dh=class{config;client;tokenCache;constructor(t,r,i){this.config=t,this.client=new Ch(t,r,i?.fetchImpl,i?.timeoutMs),this.tokenCache=i?.tokenCache??new Ah}context(t){return{appId:typeof t?.appId=="number"&&Number.isFinite(t.appId)?String(Math.trunc(t.appId)):typeof t?.appId=="string"&&t.appId.trim()?t.appId.trim():this.config.appId,userId:Number.isFinite(t?.userId)?t?.userId??0:Number(this.config.userId)||0}}async queryUserTokenByBotToken(t,r){let i=this.context(r),n=await this.client.post("/organization/queryUserTokenByBotTokenV2",{botToken:t,_userId:i.userId},{appId:i.appId,...r?.signal?{signal:r.signal}:{}});if(!n.data?.token)throw Rh("mbh-chat user-token lookup",n);return n.data.token}async getUserToken(t,r){let i=t.trim();if(!i)throw new Error("botToken is required for mbh-chat API authentication");let n=this.context(r);return this.tokenCache.getOrLoad(i,n,()=>this.queryUserTokenByBotToken(i,r))}async withUserToken(t,r,i){let n=t.trim(),o=this.context(r),s=await this.getUserToken(n,r);try{return await i(s)}catch(a){if(!(a instanceof jo)||a.status!==401)throw a;return this.tokenCache.delete(n,o),s=await this.getUserToken(n,r),i(s)}}async generateSignUrl(t,r,i){if(!t.trim())throw new Error("fileUrl is required for mbh-chat generateSignUrl");let n=this.context(i),o=await this.withUserToken(r,i,s=>this.client.post("/user/generateSignUrl",{loudPlatform:0,fileName:t},{appId:n.appId,userToken:s,...i?.signal?{signal:i.signal}:{}}));if(Number(o.code)!==0||!o.data?.filePath)throw Rh("mbh-chat generateSignUrl",o);return o.data.filePath}async getMyExpertDownloadUrl(t,r,i={}){let n=t.trim(),o=r.trim();if(!n)throw new Error("cloneCode is required for Agent package lookup");if(!o)throw new Error("botToken is required for mbh-chat Agent package lookup");let s=this.context(i),a=AE(i.userId,s.userId,"_userId"),c=zoe(i.businessUserId)??a,u=AE(i.domainId,this.config.domainId,"_domainId"),l=AE(i.appId,this.config.appId,"_appId"),d=await this.withUserToken(o,i,h=>this.client.post("/skill-market/v1/user_expert/get_my_expert_list",{_orgId:Loe,_domainId:u,user_id:c,bot_token:o,page_no:1,key_word:Foe(n),page_size:200,with_download:!0,_userId:a},{appId:l,userToken:h,...i.signal?{signal:i.signal}:{}}));if(Number(d.code)!==0)throw Rh("mbh-chat Agent package lookup",d);let p=ye(d.data)?.list;if(!Array.isArray(p))throw new Error("mbh-chat Agent package lookup returned an invalid list");let f=p.map(h=>ye(h)).map(h=>nt(h?Ae(h,"downloadUrl","download_url"):void 0)).find(Boolean);if(!f)throw new Error(`Agent ${n} has no downloadable package`);return f}async getStsToken(t,r,i,n){if(!t.trim())throw new Error("sourceFileName is required for mbh-chat STS credentials");let o=this.context(n),s=await this.withUserToken(r,n,a=>this.client.post("/user/getStsTokenByAsync",{sourceFileName:t,isPrivate:i},{appId:o.appId,userToken:a,...n?.signal?{signal:n.signal}:{}}));if(!s.data?.bucket)throw Rh("mbh-chat STS credential lookup",s);return s.data}};var vV=Br(yV(),1);import{extname as Fye}from"node:path";import{fileURLToPath as zye}from"node:url";var Uye=vV.default,Bye=1024*1024,Wye=900*1e3;function Vye(e){if(typeof e=="string"){let t=e.trim();if(t.startsWith("file:"))try{return zye(t)}catch{return e}return e}if(Buffer.isBuffer(e))return e;if(e&&typeof e=="object"){if(ArrayBuffer.isView(e)&&!(e instanceof DataView)&&!Buffer.isBuffer(e)){let i=e;return Buffer.from(i.buffer,i.byteOffset,i.byteLength)}let t=e,r=t.path??t.filePath;if(typeof r=="string"&&r.trim())return r.trim()}return e}var Zye={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".bmp":"image/bmp",".svg":"image/svg+xml",".ico":"image/x-icon",".avif":"image/avif",".heic":"image/heic",".heif":"image/heif",".pdf":"application/pdf",".epub":"application/epub+zip",".mp4":"video/mp4",".webm":"video/webm",".mov":"video/quicktime",".mp3":"audio/mpeg",".wav":"audio/wav",".ogg":"audio/ogg",".opus":"audio/opus",".m4a":"audio/mp4",".aac":"audio/aac",".flac":"audio/flac",".txt":"text/plain; charset=utf-8",".log":"text/plain; charset=utf-8",".csv":"text/csv; charset=utf-8",".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"text/javascript; charset=utf-8",".mjs":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".xml":"application/xml; charset=utf-8",".md":"text/markdown; charset=utf-8",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation"};function YT(e){let t=e.split(/[/\\]/).pop()??e,r=Fye(t).toLowerCase();return r?Zye[r]:void 0}function Hye(e,t){if(typeof e=="string")return YT(e)??"application/octet-stream";if(Buffer.isBuffer(e)){if(t){let n=YT(t);if(n)return n}return"application/octet-stream"}let r=e.type?.trim();if(r&&r!=="application/octet-stream")return r;let i=typeof e.name=="string"&&e.name?e.name:"";if(i){let n=YT(i);if(n)return n}return r||"application/octet-stream"}function Gye(e){let t=e.split(";",1)[0]?.trim().toLowerCase()??"";return t==="application/epub+zip"||t==="image/svg+xml"||t==="application/xml"||t==="text/javascript"||t==="application/javascript"?"attachment":"inline"}async function Kye(e){if(Buffer.isBuffer(e))return{content:e,fileName:"file"};if(typeof e=="string")return{content:e,fileName:e.split(/[/\\]/).pop()??"file"};let t=Buffer.from(await e.arrayBuffer()),r=e.name;return{content:t,fileName:typeof r=="string"&&r?r:"file"}}var QT=class{api;logger;constructor(t,r){this.api=t,this.logger=r}async upload(t,r,i=1,n,o){let s=Vye(t),{content:a,fileName:c}=await Kye(s),u=await this.api.getStsToken(c,r,i,o),l=Hye(s,c),d=n?.onProgress,p={accessKeyId:u.tempAccessKeyId,accessKeySecret:u.tempAccessKeySecret,stsToken:u.tempSecurityToken,bucket:u.bucket,endpoint:u.endPoint,region:u.region,secure:!0,cname:!0,authorizationV4:!0,timeout:n?.timeoutMs??Wye},f=new Uye(p),h=`${u.uploadDir}${u.ossFileKey}`;try{let m,_={progress:y=>{d?.(y)},parallel:4,partSize:Bye,mime:l,headers:{"Content-Disposition":Gye(l)}};if(m=await f.multipartUpload(h,a,_),m?.res?.status!==200)throw new Error(`OSS upload failed with status ${m?.res?.status??"unknown"}`);let x=(m?.res?.requestUrls||[])[0]||"",v=i===1&&m.name||x;if(!v)throw new Error("OSS upload succeeded but returned no object name or URL");let g=i===1?await this.api.generateSignUrl(v,r,o):v;if(!g)throw new Error("OSS upload succeeded but returned no signed URL");return this.logger.info("OSS upload succeeded",{private:i===1}),g}catch(m){throw this.logger.error("OSS upload failed",{error:m instanceof Error?m.message:String(m)}),m}}};function bV(e,t){let r=new QT(e,t);return r.upload.bind(r)}var Yg=class{tails=new Map;generations=new Map;enqueue(t,r){let i=this.tails.get(t)??Promise.resolve(),n=this.generations.get(t)??0,o=i.catch(()=>{}).then(async()=>{(this.generations.get(t)??0)===n&&await r()});return this.tails.set(t,o),o.finally(()=>{this.tails.get(t)===o&&(this.tails.delete(t),this.generations.delete(t))}).catch(()=>{}),o}cancelPending(t){this.tails.has(t)&&this.generations.set(t,(this.generations.get(t)??0)+1)}cancelAllPending(){for(let t of this.tails.keys())this.cancelPending(t)}};import{randomUUID as tI}from"node:crypto";import nve from"node:fs";import Tr from"node:fs/promises";import ive from"node:os";import li from"node:path";import{resolveDshHome as ove,dshHomePath as sve,dshHomeDisplay as ave}from"@deepseek-ai/dsh-home-paths";var xV=Br(Y0(),1);import Xye from"node:fs";import _V from"node:fs/promises";import Vl from"node:path";import{Transform as Jye}from"node:stream";import{pipeline as Yye}from"node:stream/promises";var SV=500*1024*1024,eI=1024*1024*1024,wV=2e4;function Qye(e){if((e.flags&2048)!==0)return new TextDecoder("utf-8").decode(e.pathBuffer);try{return new TextDecoder("utf-8",{fatal:!0}).decode(e.pathBuffer)}catch{return new TextDecoder("gbk").decode(e.pathBuffer)}}function eve(e){let t=e.replaceAll("\\","/"),r=t.split("/").filter(Boolean);if(t.startsWith("/")||/^[a-z]:\//i.test(t)||r.some(i=>i==="."||i===".."))throw new Error(`skill archive contains an unsafe path: ${e}`);return t}function tve(e){let t=e.map(n=>n.replaceAll("\\","/").replace(/\/+$/,"")).filter(Boolean);if(t.length===0)return;let r=new Set(t.map(n=>n.split("/").filter(Boolean)[0]).filter(Boolean));if(r.size!==1)return;let i=[...r][0];return i&&t.some(n=>n.startsWith(`${i}/`))&&t.every(n=>n===i||n.startsWith(`${i}/`))?i:void 0}function rve(e,t){let r=Vl.resolve(e,t),i=Vl.relative(Vl.resolve(e),r);if(!i||i.startsWith("..")||Vl.isAbsolute(i))throw new Error(`skill archive contains an unsafe path: ${t}`);return r}var Qg=class extends Jye{limitBytes;budget;constructor(t,r){super(),this.limitBytes=t,this.budget=r}_transform(t,r,i){if(this.budget.used+=t.length,this.budget.used>this.limitBytes){i(new Error(`skill archive expands beyond ${this.limitBytes} bytes`));return}i(null,t)}};async function EV(e,t){let r=await xV.default.Open.buffer(e);if(r.files.length>wV)throw new Error(`skill archive exceeds ${wV} entries`);let i=r.files.reduce((a,c)=>a+c.uncompressedSize,0);if(!Number.isSafeInteger(i)||i>eI)throw new Error(`skill archive expands beyond ${eI} bytes`);let n=r.files.map(a=>eve(Qye(a))),o=tve(n),s={used:0};for(let a=0;a<r.files.length;a+=1){let c=r.files[a],u=n[a];if(!c||!u)continue;let l=u.replaceAll("\\","/");if(o&&(l===o||l===`${o}/`)||(o&&l.startsWith(`${o}/`)&&(l=l.slice(o.length+1)),l=l.replace(/\/+$/,""),!l))continue;let d=rve(t,l);if(c.type==="Directory"){await _V.mkdir(d,{recursive:!0});continue}if(c.type!=="File")throw new Error(`skill archive contains an unsupported entry: ${u}`);await _V.mkdir(Vl.dirname(d),{recursive:!0}),await Yye(c.stream(),new Qg(eI,s),Xye.createWriteStream(d,{mode:384}))}}var cve=/^[a-z0-9]+(?:-[a-z0-9]+)*$/;function ty(e){let t=Array.isArray(e.skills_scope)?ye(e.skills_scope[0]):void 0,r=Array.isArray(e.intent_recognition)?e.intent_recognition.map(ye).filter(c=>!!c).find(c=>nt(Ae(c,"biz_type","bizType")).toLowerCase()==="skill"):void 0,i=t??r;if(!i)return;let n=nt(Ae(i,"skill_code","skillCode"))||(i===r?nt(i.name):"");if(!n)return;let o=nt(Ae(i,"short_name","shortName","name"))||n,s=nt(Ae(i,"url","download_url","downloadUrl","skill_url","skillUrl")),a=Ae(i,"skill_id","skillId","id");return{code:n,url:s,name:o,...typeof a=="string"||typeof a=="number"?{id:a}:{}}}var ey=class{logger;options;dshHome;skillsRoot;skillsDisplayRoot;operations=new Map;constructor(t,r={}){this.logger=t,this.options=r,this.dshHome=ove(),this.skillsRoot=sve("skills"),this.skillsDisplayRoot=li.join(ave(this.dshHome),"skills")}normalizeCode(t){let r=t.trim();if(!cve.test(r))throw new Error(`invalid mbh-chat skill code: ${r||"<empty>"}`);return r}skillPath(t){return li.join(this.skillsRoot,this.normalizeCode(t))}skillDisplayPath(t){return li.join(this.skillsDisplayRoot,this.normalizeCode(t))}exists(t){try{return nve.existsSync(li.join(this.skillPath(t),"SKILL.md"))}catch{return!1}}install(t,r){return this.serialized(r,async()=>{let i,n;try{if(i=this.normalizeCode(r),n=this.skillPath(i),!t.trim())throw new Error("skill url is empty")}catch(c){return{success:!1,status:"fail",error:ne(c)}}let o=li.dirname(n),s=li.join(o,`.${i}.${tI()}.tmp`),a=li.join(o,`.${i}.${tI()}.bak`);try{await Tr.mkdir(o,{recursive:!0,mode:448}),await Hu(async()=>{await Tr.rm(s,{recursive:!0,force:!0}),await Tr.mkdir(s,{recursive:!0,mode:448});let u=await this.download(t);await EV(u,s);let l=li.join(s,"SKILL.md");if(!(await Tr.stat(l).catch(()=>{}))?.isFile())throw new Error("skill archive does not contain a root SKILL.md")});let c=await Tr.stat(n).then(()=>!0,()=>!1);c&&await Tr.rename(n,a);try{await Tr.rename(s,n)}catch(u){throw c&&await Tr.rename(a,n).catch(()=>{}),u}return await Tr.rm(a,{recursive:!0,force:!0}).catch(u=>{this.logger.warn("could not remove the previous mbh-chat skill backup",{code:i,error:ne(u)})}),this.logger.info("installed mbh-chat skill",{code:i,path:this.skillDisplayPath(i)}),{success:!0,status:"ok"}}catch(c){return await Tr.rm(s,{recursive:!0,force:!0}).catch(()=>{}),this.logger.error("mbh-chat skill installation failed",{code:i,error:ne(c)}),{success:!1,status:"fail",error:ne(c)}}})}uninstall(t){return this.serialized(t,async()=>{try{let r=this.normalizeCode(t),i=this.skillPath(r);return await Tr.rm(i,{recursive:!0,force:!0}),this.logger.info("uninstalled mbh-chat skill",{code:r,path:this.skillDisplayPath(r)}),{success:!0,status:"ok"}}catch(r){return this.logger.error("mbh-chat skill removal failed",{code:t,error:ne(r)}),{success:!1,status:"fail",error:ne(r)}}})}eventContent(t,r){return{event_type:"skill",operation_type:"install",skill_url:t.url,skill_code:t.code,...t.id!==void 0?{skill_id:t.id}:{},...r?{bot_token:r}:{}}}serialized(t,r){let i=t.trim(),o=(this.operations.get(i)??Promise.resolve({success:!0,status:"ok"})).catch(()=>{}).then(r);return this.operations.set(i,o),o.finally(()=>{this.operations.get(i)===o&&this.operations.delete(i)}),o}async download(t){let r=await Tr.mkdtemp(li.join(ive.tmpdir(),"mbh-chat-skill-"));try{let i=await Vs([{url:t,name:"skill.zip"}],{storageRoot:r,requestId:tI(),maxBytes:SV,maxFiles:1,maxInlineImageBytes:1,fetchTimeoutMs:18e4,concurrency:1,allowPrivateNetwork:this.options.allowPrivateNetwork??!1,...this.options.fetchImpl?{fetchImpl:this.options.fetchImpl}:{}}),n=i.media[0];if(!n)throw new Error(i.failures[0]?.reason||"skill download failed");return await Tr.readFile(n.localPath)}finally{await Tr.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}};import{randomUUID as kV}from"node:crypto";var rI=class{baseUrl;logger;sessionCookie;socket;streams=new Map;opening;closed;constructor(t,r,i){this.baseUrl=t,this.logger=r,this.sessionCookie=i}async*open(t,r,i,n){let o=kV(),s=[],a,c=l=>{s.push(l),a?.(),a=void 0};this.streams.set(o,c);let u=()=>{this.send({type:"cancel",streamId:o}),c({kind:"end"})};i.addEventListener("abort",u,{once:!0});try{if(await this.ensureOpen(),this.closed)throw this.closed;for(this.send({type:"open",streamId:o,endpoint:t,payload:r}),n?.(),i.aborted&&u();;){for(;s.length>0;){let l=s.shift();if(!l||l.kind==="end")return;if(l.kind==="error")throw l.error;yield l.value}await new Promise(l=>{a=l})}}finally{i.removeEventListener("abort",u),this.streams.delete(o),i.aborted||this.send({type:"cancel",streamId:o})}}close(t){this.closed=t??new Error("mbh-chat Remote mux closed");for(let i of this.streams.values())i({kind:"end"});this.streams.clear();let r=this.socket;this.socket=void 0,this.opening=void 0,r&&(r.readyState===rr.CONNECTING?r.terminate():r.readyState===rr.OPEN&&r.close(1e3,"bridge stream stopped"))}async ensureOpen(){if(this.socket?.readyState===rr.OPEN)return;if(this.opening)return this.opening;let t=new URL("/api/remote.mux",this.baseUrl);t.protocol=t.protocol==="https:"?"wss:":"ws:";let r=new rr(t,{headers:vn(this.sessionCookie)});this.socket=r,this.opening=new Promise((i,n)=>{let o=s=>{this.close(s),n(s)};r.once("open",()=>{r.once("close",()=>this.close(new Error("mbh-chat Remote mux closed"))),i()}),r.once("error",s=>o(s instanceof Error?s:new Error(String(s))))}),r.on("message",(i,n)=>{if(n){this.logger.warn("dropping binary mbh-chat WebSocket frame",{path:"/api/remote.mux"});return}let o;try{o=JSON.parse(i.toString())}catch(a){this.logger.warn("dropping malformed mbh-chat Remote mux frame",{error:a instanceof Error?a.message:String(a)});return}let s=this.streams.get(o.streamId);s&&(o.type==="item"?s({kind:"frame",value:o.value}):o.type==="error"?s({kind:"error",error:new Error(`mbh-chat ${o.error.code}: ${o.error.message}`)}):s({kind:"end"}))}),await this.opening}send(t){this.socket?.readyState===rr.OPEN&&this.socket.send(JSON.stringify(t))}},ry=class{baseUrl;logger;timeoutMs;sessionCookie;mux;eventClientId;constructor(t,r,i=3e4,n=Ih()){this.baseUrl=t,this.logger=r,this.timeoutMs=i,this.sessionCookie=n}sessions={create:(t,r)=>this.invoke("session/create",{request:t},r),prompt:(t,r)=>this.invoke("session/prompt",{request:t},r),cancel:(t,r)=>this.invoke("session/cancel",{request:t},r),selectModel:(t,r)=>this.invoke("session/selectModel",{request:t},r),modelCatalog:t=>this.invoke("session/modelCatalog",{},t),follow:(t,r,i)=>this.openStream("session/follow",{request:t},r,i)};openEvents(t,r){return this.openStream("$events",{},t,r)}respondEvent(t,r){let i=t.clientId??this.eventClientId;if(!i)throw new Error("mbh-chat event stream is not ready");return this.invoke("$events/result",{clientId:i,eventId:t.eventId,outcome:t.outcome},r)}disconnect(){this.eventClientId=void 0,this.mux?.close(),this.mux=void 0}async invoke(t,r,i){let n=kV(),o=await fetch(new URL(`/api/${t}`,this.baseUrl),{method:"POST",headers:vn(this.sessionCookie,{"Content-Type":"application/json"}),body:JSON.stringify({type:"client-request",rpcId:n,method:t,payload:{args:r}}),signal:i?AbortSignal.any([i,AbortSignal.timeout(this.timeoutMs)]):AbortSignal.timeout(this.timeoutMs)});if(!o.ok)throw Object.assign(new Error(`mbh-chat ${t} returned HTTP ${o.status}`),{code:"http-error"});return await o.json()}openStream(t,r,i,n){return this.mux??=new rI(this.baseUrl,this.logger,this.sessionCookie),this.mux.open(t,{args:r},i,n)}};function An(e){if(e.result.ok)return e.result.value;let t=new Error(`mbh-chat ${e.result.error.code}: ${e.result.error.message}`);throw Object.assign(t,{code:e.result.error.code}),t}function uve(e){if(!(typeof e!="object"||e===null||!("code"in e)))return typeof e.code=="string"?e.code:void 0}var lve=new Set(["session/not-found","session-not-found"]);function nI(e){return e!==void 0&&lve.has(e)}function iI(e){return nI(uve(e))}function TV(){let e,t;return{promise:new Promise((i,n)=>{e=i,t=n}),resolve:e,reject:t}}var fve=3e3;function dve(e,t,r){let i=Math.min(r,t*2**Math.min(e,8));return i+Math.floor(Math.random()*Math.max(1,Math.min(1e3,i/5)))}function IV(e,t){return new Promise(r=>{if(t.aborted)return r();let i=setTimeout(n,e);function n(){clearTimeout(i),t.removeEventListener("abort",n),r()}t.addEventListener("abort",n,{once:!0})})}var ny=class{reconnectMinMs;reconnectMaxMs;logger;api;rootAbort;generationAbort;handlers;loopPromise;connected=!1;followedSessions=new Set;followAborts=new Map;followReadiness=new Map;liveFollows=new Set;connectionWaiters=new Set;constructor(t,r,i,n){this.reconnectMinMs=r,this.reconnectMaxMs=i,this.logger=n,this.api=new ry(t,n)}start(t){if(this.loopPromise)throw new Error("mbh-chat connection already started");this.handlers=t,this.rootAbort=new AbortController,this.loopPromise=this.run(t,this.rootAbort.signal)}async stop(){this.rootAbort?.abort();let t=new Error("mbh-chat connection stopped before becoming ready");for(let r of this.connectionWaiters)r.reject(t);this.connectionWaiters.clear();for(let r of this.followReadiness.values())r.reject(t);this.followReadiness.clear(),this.liveFollows.clear(),await this.loopPromise,this.loopPromise=void 0,this.rootAbort=void 0,this.handlers=void 0,this.api.disconnect()}isConnected(){return this.connected}followSession(t){if(this.followedSessions.add(t),this.liveFollows.has(t))return Promise.resolve();let r=this.followReadiness.get(t);r||(r=TV(),this.followReadiness.set(t,r)),this.connected&&this.generationAbort&&!this.followAborts.has(t)&&this.startFollow(t,this.generationAbort.signal);let i=r.promise;return i.catch(()=>{}),Promise.race([i,IV(fve,this.generationAbort?.signal??new AbortController().signal).then(()=>{this.liveFollows.has(t)||this.logger.warn("mbh-chat session follow was not ready before timeout",{sessionId:t})})])}unfollowSession(t){this.followedSessions.delete(t),this.liveFollows.delete(t),this.followAborts.get(t)?.abort(),this.followAborts.delete(t),this.followReadiness.get(t)?.reject(new Error(`mbh-chat stopped following session ${t}`)),this.followReadiness.delete(t)}whenConnected(t){return this.connected?Promise.resolve():new Promise((r,i)=>{let n=()=>{a(),r()},o=u=>{a(),i(u)},s=()=>o(t?.reason??new Error("waiting for mbh-chat connection was aborted")),a=()=>{this.connectionWaiters.delete(c),t?.removeEventListener("abort",s)},c={resolve:n,reject:o};this.connectionWaiters.add(c),t?.addEventListener("abort",s,{once:!0}),t?.aborted&&s()})}async setConnected(t,r){if(t||(this.connected=!1),await r.onConnection?.(t),t){this.connected=!0;for(let i of this.connectionWaiters)i.resolve();this.connectionWaiters.clear()}}async run(t,r){let i=0;for(;!r.aborted;){let n=new AbortController;this.generationAbort=n;let o=()=>n.abort();r.addEventListener("abort",o,{once:!0});let s=TV(),a=!1,c;try{c=this.pumpEvents(t,n.signal,s.resolve);let u=c.then(()=>{throw new Error("a mbh-chat event stream closed")});await Promise.race([s.promise,u]),a=!0,i=0,await this.setConnected(!0,t);for(let l of this.followedSessions)this.startFollow(l,n.signal);await u}catch(u){r.aborted||this.logger.warn("mbh-chat connection lost",{error:ne(u)})}finally{if(this.generationAbort=void 0,n.abort(),this.stopFollows(),this.api.disconnect(),await Promise.allSettled(c?[c]:[]),r.removeEventListener("abort",o),a)try{await this.setConnected(!1,t)}catch(u){this.logger.error("mbh-chat connection-state handler failed during disconnect",{error:ne(u)})}}if(!r.aborted){let u=dve(i++,this.reconnectMinMs,this.reconnectMaxMs);this.logger.info("reconnecting to mbh-chat Host",{delayMs:u,attempt:i}),await IV(u,r)}}}async pumpEvents(t,r,i){let n=!1;for await(let o of this.api.openEvents(r)){if(o.type==="ready"){this.api.eventClientId=o.clientId,n||(n=!0,i());continue}try{await t.onRemoteEvent(o)}catch(s){this.logger.error("mbh-chat event handler failed",{error:ne(s)})}}}markFollowReady(t){this.liveFollows.add(t),this.followReadiness.get(t)?.resolve()}async startFollow(t,r){if(this.followAborts.has(t))return;let i=new AbortController;this.followAborts.set(t,i);let n=AbortSignal.any([r,i.signal]),o=!1;try{for await(let s of this.api.sessions.follow({address:{kind:"session",sessionId:t}},n)){if(s.type==="snapshot"){o=!0,this.markFollowReady(t);continue}if(s.type==="event")try{this.handlers?.onSessionEvent(t,s.event)}catch(a){this.logger.error("mbh-chat session event handler failed",{sessionId:t,error:ne(a)})}}if(!n.aborted&&!o)throw new Error(`mbh-chat session follow ended before receiving a snapshot for ${t}`)}catch(s){!r.aborted&&!i.signal.aborted&&(this.followReadiness.get(t)?.reject(s),this.logger.warn("mbh-chat session follow ended",{sessionId:t,error:ne(s)}))}finally{this.followAborts.get(t)===i&&this.followAborts.delete(t),this.liveFollows.delete(t)}}stopFollows(){for(let t of this.followAborts.values())t.abort();this.followAborts.clear(),this.liveFollows.clear()}};async function OV(e,t,r,i){let n=new Map;for(let u of e.store.listActiveSubagentsForRoot(t))(!r||u.requestId===r)&&n.set(u.childSessionId,u.parentSessionId);for(let[u,l]of i??[])n.set(u,l);let o=!1,s=!1,a,c=u=>{e.store.settleSubagent(u,"cancelled"),n.delete(u)};for(let u=1;u<=e.config.task.maxAttempts;u+=1){let l=p=>{let f=0,h=p,m=new Set;for(;!m.has(h);){m.add(h);let _=n.get(h);if(!_)break;f+=1,h=_}return f},d=[...n].sort(([p],[f])=>l(f)-l(p));for(let[p,f]of d)try{An(await e.dsh.api.sessions.cancel({sessionId:p})),c(p)}catch(h){if(iI(h)){c(p);continue}a=h,e.logger.warn("subagent interrupt failed",{parentSessionId:f,childSessionId:p,attempt:u,error:ne(h)})}if(!o)try{An(await e.dsh.api.sessions.cancel({sessionId:t})),o=!0}catch(p){iI(p)?(o=!0,s=!0):(a=p,e.logger.warn("model/tool cancellation failed",{dshSessionId:t,attempt:u,error:ne(p)}))}if(o&&n.size===0)return s?"absent":"cancelled";if(u<e.config.task.maxAttempts){let p=Math.min(e.config.task.retryMaxMs,e.config.task.retryBaseMs*2**(u-1));await new Promise(f=>setTimeout(f,p))}}throw a instanceof Error?a:new Error("execution cancellation could not be confirmed")}var pve=/request id\s*:\s*([a-z0-9_-]{1,128})/iu,hve=new RegExp("\\p{Script=Han}","u");function mve(e){let t=pve.exec(e)?.[1];return t?`\uFF08\u8BF7\u6C42 ID\uFF1A${t}\uFF09`:""}function gve(e,t){let r=e?.trim();return r?r.slice(0,120):t}function yve(e){let t=ne(e).trim(),r=mve(t),i=/range of max_tokens should be \[\s*(\d+)\s*,\s*(\d+)\s*\]/iu.exec(t);if(i)return`\u6A21\u578B\u751F\u6210\u957F\u5EA6\u53C2\u6570\uFF08max_tokens\uFF09\u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF0C\u6709\u6548\u8303\u56F4\u4E3A ${i[1]}\u2013${i[2]}\u3002${r}`;let n=/no available channel for model\s+(.+?)\s+under group\b/iu.exec(t);return n?`\u6A21\u578B ${gve(n[1],"\u5F53\u524D\u6A21\u578B")} \u5F53\u524D\u6682\u65E0\u53EF\u7528\u670D\u52A1\u901A\u9053\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/no available channel/iu.test(t)?`\u5F53\u524D\u6A21\u578B\u6682\u65E0\u53EF\u7528\u670D\u52A1\u901A\u9053\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/tokenization failed/iu.test(t)?`\u6A21\u578B\u65E0\u6CD5\u5904\u7406\u5F53\u524D\u8F93\u5165\uFF0C\u8BF7\u7F29\u77ED\u5185\u5BB9\u6216\u5207\u6362\u6A21\u578B\u540E\u91CD\u8BD5\u3002${r}`:/completed response with no content|empty response|no content returned/iu.test(t)?`\u6A21\u578B\u672A\u8FD4\u56DE\u6709\u6548\u5185\u5BB9\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/context length|maximum context|context window|too many tokens/iu.test(t)?`\u5BF9\u8BDD\u5185\u5BB9\u8D85\u8FC7\u6A21\u578B\u53EF\u5904\u7406\u7684\u957F\u5EA6\uFF0C\u8BF7\u7F29\u77ED\u5185\u5BB9\u6216\u65B0\u5EFA\u4F1A\u8BDD\u3002${r}`:/\b(401|unauthorized|invalid api.?key|authentication)\b/iu.test(t)?`\u6A21\u578B\u670D\u52A1\u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u670D\u52A1\u914D\u7F6E\u3002${r}`:/\b(403|forbidden|permission denied)\b/iu.test(t)?`\u5F53\u524D\u8D26\u53F7\u65E0\u6743\u8BBF\u95EE\u8BE5\u6A21\u578B\uFF0C\u8BF7\u68C0\u67E5\u6A21\u578B\u6743\u9650\u6216\u5207\u6362\u6A21\u578B\u3002${r}`:/\b(429|rate.?limit|too many requests|overload|busy)\b/iu.test(t)?`\u6A21\u578B\u670D\u52A1\u5F53\u524D\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`:/timeout|timed out/iu.test(t)?`\u6A21\u578B\u670D\u52A1\u54CD\u5E94\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`:/\b5\d\d\b|bad gateway|service unavailable|upstream.*(?:error|failed)/iu.test(t)?`\u4E0A\u6E38\u6A21\u578B\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`:/invalidparameter|invalid parameter|\b400\b|bad request/iu.test(t)?`\u6A21\u578B\u8BF7\u6C42\u53C2\u6570\u4E0D\u6B63\u786E\uFF0C\u8BF7\u68C0\u67E5\u6A21\u578B\u914D\u7F6E\u3002${r}`:hve.test(t)?t.replace(/^\[错误\]\s*/u,""):`\u6A21\u578B\u670D\u52A1\u8C03\u7528\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002${r}`}function bc(e){return`[\u9519\u8BEF] ${yve(e)}`}var $V=2e3;function Qi(e){return e.time/1e3+e.seq/1e9}function iy(e,t){return Array.isArray(e)?e.map(r=>{let i=ye(r);return i?.type===t&&typeof i.text=="string"?i.text:""}).join(""):""}function oI(e,t){let r=e.trim()||t;return r.length<=$V?r:`${r.slice(0,$V)}\u2026\u2026\uFF08\u5185\u5BB9\u5DF2\u622A\u65AD\uFF09`}function sI(e){return Array.isArray(e)?e.map(t=>{let r=ye(t);if(!r)return"";if((r.type==="text"||r.type==="reasoning")&&typeof r.text=="string")return r.text;if(r.type==="image")return"[\u56FE\u7247]";try{return JSON.stringify(r)}catch{return"[\u65E0\u6CD5\u5C55\u793A\u7684\u5DE5\u5177\u7ED3\u679C]"}}).filter(Boolean).join(`
|
|
579
579
|
`):""}function CV(e){return/^started subagent\s+(\S+)\s*$/u.exec(sI(e))?.[1]}function oy(e){if(e.type!=="user/message")return;let t=ye(ye(e.data)?.source);return t?.kind==="subagent-settled"&&typeof t.senderSessionId=="string"?t.senderSessionId:void 0}function AV(e){let t=ye(e),r=typeof t?.kind=="string"?t.kind:"unknown";if(r==="completed")return{tag:"end",status:"succeeded"};if(r==="aborted")return{tag:"abort",status:"cancelled"};if(r==="interrupted")return{tag:"interrupted",status:"cancelled"};if(r==="max-tokens")return{tag:"max_tokens",status:"failed",response:"[\u9519\u8BEF] \u6A21\u578B\u8F93\u51FA\u8FBE\u5230\u957F\u5EA6\u4E0A\u9650"};if(r==="blocked")return{tag:"blocked",status:"failed",response:"[\u9519\u8BEF] \u672C\u8F6E\u88AB\u5BBF\u4E3B\u7B56\u7565\u963B\u6B62"};if(r==="error"){let i=ye(t?.error),n=typeof i?.message=="string"?i.message:"mbh-chat agent turn failed";return{tag:"error",status:"failed",response:bc(n)}}return{tag:"error",status:"failed",response:`[\u9519\u8BEF] \u672A\u8BC6\u522B\u7684 mbh-chat \u7ED3\u675F\u72B6\u6001\uFF1A${r}`}}function RV(e){if(e.type!=="turn/end")return;let t=ye(ye(e.data)?.reason);if(t?.kind!=="error")return;let r=ye(t.error);return typeof r?.message=="string"&&r.message.trim()?r.message:void 0}function DV(e){let t=ye(e.data);if(e.type==="assistant/message"){let n=ye(t?.message);return Array.isArray(n?.content)?n.content.some(o=>{let s=ye(o);return s?.type==="tool-call"&&(!_c(s.id)||!_c(s.name))}):!1}if(e.type==="tool/call")return!_c(t?.callId)||!_c(t?.name);if(e.type!=="tool/result")return!1;let r=ye(t?.message),i=ye(r?.source);return _c(i?.callId)?Array.isArray(r?.content)?r.content.some(n=>{let o=ye(n);return o?.type==="tool-result"&&!_c(o.toolCallId)}):!1:!0}function _c(e){return typeof e=="string"&&e.trim().length>0}function NV(e){return e.type==="user/message"?iy(ye(e.data)?.content,"text"):JSON.stringify(e.data??"")}function sy(e,t){let r=`${t}:`,i=NV(e).split(`
|
|
580
580
|
`).find(n=>n.startsWith(r));if(i)try{let n=JSON.parse(i.slice(r.length).trim());return typeof n=="string"&&n.trim()?n.trim():void 0}catch{return}}function ay(e){let t=NV(e);return t.includes("SCHEDULED TASK DUE")||t.includes("CRON AUTOMATION DUE")}function aI(e,t){return e==="allow-once"||t?"allowed-once":"rejected"}import PV from"node:path";function Zl(e){let t=e.toLowerCase();return/cannot read properties of undefined \(reading ['"]prepare['"]\)/u.test(t)||/session event ['"]turn\/end['"] carries non-json-serializable data/u.test(t)||/messages\[\d+\]/u.test(t)&&t.includes("missing field")&&t.includes("tool_call_id")||t.includes("stored session")&&t.includes("is corrupt")&&t.includes("failed validation")||t.includes("insufficient tool messages")||t.includes("tool_calls")&&t.includes("followed by tool")}var cy=class{config;store;getDsh;logger;getCronSync;activeBySession;finish;cancelExecution;quarantineUnconfirmedExecution;hostDefaultProvider;constructor(t,r,i,n,o,s,a,c,u){this.config=t,this.store=r,this.getDsh=i,this.logger=n,this.getCronSync=o,this.activeBySession=s,this.finish=a,this.cancelExecution=c,this.quarantineUnconfirmedExecution=u}clearHostDefaultProvider(){this.hostDefaultProvider=void 0}async ensureSession(t,r,i,n){let o=this.store.getSessionBinding(t);if(o){let s=!!o.workspaceDir&&!!i.workspaceDir&&PV.resolve(o.workspaceDir)!==PV.resolve(i.workspaceDir),a=i.managed&&!o.workspaceDir,c=!!o.agentPreset&&o.agentPreset!==i.agentPreset;if(s||a||c)this.store.removeSession(t),this.logger.info("discarded stale mbh-chat session route",{businessKey:t,dshSessionId:o.dshSessionId,workspaceMismatch:s||a,presetMismatch:c});else{this.store.bindSession(t,o.dshSessionId,n,{...i.workspaceDir?{workspaceDir:i.workspaceDir}:{},...i.agentPreset?{agentPreset:i.agentPreset}:{}});try{await this.getDsh().followSession?.(o.dshSessionId)}catch(u){let l=ne(u);if(!Zl(l))throw this.getDsh().unfollowSession?.(o.dshSessionId),u;return this.store.removeSession(t),this.getDsh().unfollowSession?.(o.dshSessionId),this.logger.info("discarded stored corrupt mbh-chat session before prompt",{businessKey:t,dshSessionId:o.dshSessionId,error:l}),this.createSession(t,r,i,n)}return r?.trim()&&await this.selectModel(o.dshSessionId,r.trim()),o.dshSessionId}}return this.createSession(t,r,i,n)}async createSession(t,r,i,n){let o={...i.workspaceDir?{cwd:i.workspaceDir}:{},...i.agentPreset?{agentPreset:i.agentPreset}:{}},a=An(await this.getDsh().api.sessions.create(o)).sessionId;this.store.bindSession(t,a,n,{...i.workspaceDir?{workspaceDir:i.workspaceDir}:{},...i.agentPreset?{agentPreset:i.agentPreset}:{}});try{await this.getDsh().followSession?.(a)}catch(u){throw this.store.removeSession(t),this.getDsh().unfollowSession?.(a),u}this.getCronSync()?.notifySessionAvailable(),this.getCronSync()?.bindDshSessionId(t,a).catch(u=>{this.logger.warn("failed to bind cron jobs to new mbh-chat session",{businessKey:t,dshSessionId:a,error:ne(u)})});let c=r?.trim()||this.config.dsh.model;return c&&await this.selectModel(a,c),this.logger.info("created mbh-chat session mapping",{businessKey:t,dshSessionId:a,workspaceDir:i.workspaceDir,agentPreset:i.agentPreset,managedAgent:i.agent?.cloneCode}),a}async invalidateAgentSessions(t,r){let i=new Set;for(let n of t)for(let o of this.store.listSessionBindingsForAgent(n)){let s=this.activeBySession.get(o.dshSessionId);try{s&&!s.finalized?await this.cancelExecution(s):An(await this.getDsh().api.sessions.cancel({sessionId:o.dshSessionId}))}catch(a){i.add(n),this.quarantineUnconfirmedExecution?.(o.businessKey,o.dshSessionId,`${r}_cancel_unconfirmed`,!1),this.logger.warn("could not cancel invalidated Agent session",{cloneCode:n,dshSessionId:o.dshSessionId,error:ne(a)})}s&&!s.finalized&&this.finish(s,r,"cancelled","[\u9519\u8BEF] \u4E13\u5BB6\u914D\u7F6E\u5DF2\u53D8\u66F4\uFF0C\u672C\u8F6E\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u91CD\u8BD5"),this.store.removeSession(o.businessKey),this.getDsh().unfollowSession?.(o.dshSessionId)}return[...i]}async selectModel(t,r){let i=r.indexOf("/"),n=i>0?r.slice(0,i):this.config.dsh.modelProvider,o=i>0?r.slice(i+1):r;if(!n){if(!this.hostDefaultProvider){let s=An(await this.getDsh().api.sessions.modelCatalog());this.hostDefaultProvider=s.default.provider}n=this.hostDefaultProvider}if(!n)throw new Error(`model ${r} has no provider and mbh-chat Host reports no default provider`);An(await this.getDsh().api.sessions.selectModel({sessionId:t,provider:n,model:o,...this.config.dsh.reasoningEffort?{reasoningEffort:this.config.dsh.reasoningEffort}:{}})),this.logger.info("selected mbh-chat model",{dshSessionId:t,provider:n,model:o})}};var cI=10,uI=100,lI=128,fI=256,Hl=4e3,uy=2e3;function vve(e,t){if(typeof e!="string"||!e.trim())throw new Error(`user question ${t} must be a non-empty string`);return e.trim()}function ly(e,t,r){let i=vve(e,t);if(i.length>r)throw new Error(`user question ${t} exceeds ${r} characters`);return i}function bve(e,t,r){return typeof e=="number"&&Number.isFinite(e)?String(Math.trunc(e)):ly(e,t,r)}function _ve(e){if(e.eventType!=="user_question")return;let t=bve(e.content.session_id,"session_id",fI),r=ly(e.content.tool_call_id,"tool_call_id",lI);if(e.operationType==="cancel")return{action:"cancel",sessionId:t,toolCallId:r};if(e.operationType!=="answer")throw new Error("user question operation_type must be answer or cancel");if(!Array.isArray(e.content.answers)||e.content.answers.length===0)throw new Error("user question answers must be a non-empty array");if(e.content.answers.length>cI)throw new Error(`user question answers must contain at most ${cI} items`);return{action:"answer",sessionId:t,toolCallId:r,answers:e.content.answers.map(i=>{if(!i||typeof i!="object"||Array.isArray(i))throw new Error("user question answer must be an object");let n=i;if(!Array.isArray(n.selected)||n.selected.length>uI||!n.selected.every(a=>typeof a=="string"))throw new Error(`user question answer selected must be a string array of at most ${uI} items`);let o=n.custom;if(o!==void 0&&typeof o!="string")throw new Error("user question answer.custom must be a string");let s=o?.trim();if(s&&s.length>Hl)throw new Error(`user question answer.custom exceeds ${Hl} characters`);return{id:ly(n.id,"answer.id",lI),selected:n.selected.map(a=>ly(a,"answer.selected",uy)),...s===void 0?{}:{custom:s}}})}}function wve(e,t){if(t.length!==e.length)throw new Error("user question answer count does not match the request");return t.map((r,i)=>{let n=e[i];if(r.id!==n.id)throw new Error(`user question answer id does not match ${n.id}`);let o=new Set((n.options??[]).map(l=>l.label)),s=r.selected.map(l=>l.trim());if(s.some(l=>!l))throw new Error(`user question ${n.id} contains an empty selection`);if(new Set(s).size!==s.length)throw new Error(`user question ${n.id} contains duplicate selections`);let a=s.filter(l=>o.has(l)),c=s.filter(l=>!o.has(l)),u=r.custom?.trim()||c.join(`
|
|
581
581
|
`);if(u.length>Hl)throw new Error(`user question ${n.id} custom answer exceeds ${Hl} characters`);if(n.multiSelect!==!0&&u)return{id:r.id,selected:[],custom:u};if(n.multiSelect!==!0&&a.length>1)throw new Error(`user question ${n.id} accepts only one selection`);return{id:r.id,selected:a,...u?{custom:u}:{}}})}function Gl(e,t,r){return{version:1,type:"ask_user_question",interaction_id:e.rpcId,session_id:e.context.sessionId,...e.toolCallId?{tool_call_id:e.toolCallId}:{},status:t,questions:e.frame.questions.map(i=>({id:i.id,question:i.question,...i.header===void 0?{}:{header:i.header},...i.options===void 0?{}:{options:i.options},...i.multiSelect===void 0?{}:{multi_select:i.multiSelect}})),...r===void 0?{}:{answers:r}}}async function jV(e,t){let r=_ve(t);if(!r)return!1;let i=[...e.pendingUserQuestions.values()].filter(l=>l.context.sessionId!==r.sessionId||l.context.userId!==t._userId?!1:l.toolCallId===void 0||l.toolCallId===r.toolCallId);if(i.length>1)return e.logger.warn("rejected ambiguous user question response",{toolCallId:r.toolCallId,sessionId:r.sessionId,matches:i.length}),!1;let n=i[0];if(!n)return e.logger.info("ignored stale user question response",{toolCallId:r.toolCallId,sessionId:r.sessionId}),!1;let o=r.action==="answer"?wve(n.frame.questions,r.answers):void 0,s=o?{ok:!0,value:{answers:o}}:{ok:!1,error:{code:"cancelled",message:"the user cancelled this question request",details:{}}},a=r.action==="answer"?"answered":"cancelled";n.submitted={status:a,...o?{answers:o}:{}};let c;try{c=await e.dsh.api.respondEvent({eventId:n.rpcId,outcome:s.ok?{kind:"result",value:s.value}:{kind:"rejected",error:{name:"Error",message:s.error.message,code:s.error.code,details:s.error.details}}})}catch(l){throw e.pendingUserQuestions.get(n.rpcId)===n&&delete n.submitted,l}if(!c.result.ok)return e.pendingUserQuestions.get(n.rpcId)===n&&delete n.submitted,e.logger.warn("DSH rejected user question response",{interactionId:n.rpcId}),!1;e.pendingUserQuestions.delete(n.rpcId);let u=dI(e,n.frame.sessionId);return u&&e.turns.resumeAfterUserInput(u),e.dcg.enqueue(n.context,{response:"",state:"chunk",is_finish:0,interaction:Gl(n,a,o)},`question:${n.rpcId}:${a}`),!0}function MV(e,t){for(let[r,i]of e.pendingUserQuestions)if(!(t&&i.frame.sessionId!==t)){e.pendingUserQuestions.delete(r);try{e.dcg.enqueue(i.context,{response:"",state:"chunk",is_finish:0,interaction:Gl(i,"cancelled")},`question:${r}:cancelled`)}catch(n){e.logger.warn("could not persist user-question cancellation",{interactionId:r,error:n instanceof Error?n.message:String(n)})}}}async function LV(e,t){let r=xve(t.request,t.agentId),i=r?dI(e,r.sessionId):void 0;if(!r||!i||i.followup){e.logger.warn("rejected user question without an interactive user",{eventId:t.eventId,agentId:t.agentId,sessionId:r?.sessionId,reason:r?i?"followup":"no_live_run":"invalid_request"});let s=e.pendingUserQuestions.get(t.eventId);if(s){e.pendingUserQuestions.delete(t.eventId);try{e.dcg.enqueue(s.context,{response:"",state:"chunk",is_finish:0,interaction:Gl(s,"cancelled")},`question:${t.eventId}:cancelled`)}catch(a){e.logger.warn("could not persist stale user-question cancellation",{eventId:t.eventId,error:a instanceof Error?a.message:String(a)})}}await qV(e,t.eventId,"\u5F53\u524D\u8FD0\u884C\u6CA1\u6709\u53EF\u4EA4\u4E92\u7684\u7528\u6237","cancelled");return}let n=[...i.toolCalls].reverse().find(([,s])=>s.name==="ask_user_question"&&!s.settled)?.[0],o={rpcId:t.eventId,frame:r,context:i.context,...n?{toolCallId:n}:{}};e.pendingUserQuestions.set(t.eventId,o);try{e.store.markRequestToolWaiting(i.context.requestId),e.turns.pauseForUserInput(i),e.dcg.enqueue(i.context,{response:"",state:"waiting_input",is_finish:0,interaction:Gl(o,"pending")},`question:${t.eventId}:requested`)}catch(s){e.pendingUserQuestions.delete(t.eventId),e.logger.warn("could not persist user question for MBHChat",{eventId:t.eventId,error:s instanceof Error?s.message:String(s)});try{e.store.markRequestRunningAfterTool(i.context.requestId)}catch(a){e.logger.warn("could not restore task state after user-question delivery failure",{eventId:t.eventId,error:a instanceof Error?a.message:String(a)})}try{e.turns.resumeAfterUserInput(i)}catch(a){e.logger.warn("could not resume turn timeout after user-question delivery failure",{eventId:t.eventId,error:a instanceof Error?a.message:String(a)})}await qV(e,t.eventId,"\u65E0\u6CD5\u5C06\u95EE\u9898\u53D1\u9001\u7ED9\u5F53\u524D\u7528\u6237","delivery_failed");return}e.logger.info("forwarded user question to MBHChat",{sessionId:r.sessionId,rpcId:t.eventId})}function FV(e,t){let r=e.pendingUserQuestions.get(t);if(!r)return;e.pendingUserQuestions.delete(t);let i=dI(e,r.frame.sessionId);i&&e.turns.resumeAfterUserInput(i),e.dcg.enqueue(r.context,{response:"",state:"chunk",is_finish:0,interaction:Gl(r,"cancelled",r.submitted?.answers)},`question:${t}:cancelled`)}function dI(e,t){let r=e.turns.liveRun(t);return r||e.turns.liveRuns().find(i=>!i.finalized&&i.dshSessionId===t)}function xve(e,t){let r=cs(e.sessionId,fI)??cs(t,fI),i=e.questions;if(!r||!Array.isArray(i)||i.length===0||i.length>cI)return;let n=[];for(let o of i){let s=ye(o);if(!s)return;let a=cs(s.id,lI),c=cs(s.question,Hl);if(!a||!c)return;let u;if(s.options!==void 0){if(!Array.isArray(s.options)||s.options.length>uI)return;u=[];for(let d of s.options){let p=ye(d),f=cs(p?.label,uy);if(!f)return;let h=cs(p?.description,uy);if(p?.description!==void 0&&!h)return;u.push({label:f,...h?{description:h}:{}})}}let l=cs(s.header,uy);if(s.header!==void 0&&!l||s.multiSelect!==void 0&&typeof s.multiSelect!="boolean")return;n.push({id:a,question:c,...l?{header:l}:{},...u?{options:u}:{},...typeof s.multiSelect=="boolean"?{multiSelect:s.multiSelect}:{}})}return{sessionId:r,questions:n}}function cs(e,t){if(typeof e!="string")return;let r=e.trim();return r&&r.length<=t?r:void 0}async function qV(e,t,r,i){try{(await e.dsh.api.respondEvent({eventId:t,outcome:{kind:"rejected",error:{name:"Error",message:r,code:i}}})).result.ok||e.logger.warn("DSH rejected user-question rejection",{eventId:t,code:i})}catch(n){e.logger.warn("could not reject user question through DSH",{eventId:t,code:i,error:n instanceof Error?n.message:String(n)})}}async function zV(e,t){if(t.type==="waterfall"&&t.event==="approval/request"){let r=pI(t.request,"sessionId"),i=pI(t.request,"approvalId"),n=pI(t.request,"toolName"),o=r?e.turns.liveRun(r):void 0,s=aI(e.config.dsh.approvalPolicy,o?.followup===!0);await e.dsh.api.respondEvent({eventId:t.eventId,outcome:{kind:"result",value:{sessionId:r,approvalId:i,outcome:s}}}),e.logger.info("answered headless approval",{sessionId:r,toolName:n,outcome:s});return}if(t.type==="waterfall"&&t.event==="user-questions/request"){await LV(e,t);return}if(t.type==="cancel"){FV(e,t.eventId);return}if(t.type==="emit"){if(t.event==="api-session/removed"){let r=String(t.args[0]??"");if(!r)return;e.unfollowSession?.(r),e.store.removeSessionByDshId(r);for(let i of e.turns.liveRuns())i.dshSessionId===r&&e.turns.finish(i,"session_removed","failed","[\u9519\u8BEF] mbh-chat \u4F1A\u8BDD\u5DF2\u88AB\u79FB\u9664");return}t.event==="api-session/error"&&Sve(e,String(t.args[0]??""),String(t.args[1]??""))}}function pI(e,t){let r=e[t];return typeof r=="string"&&r?r:void 0}function Sve(e,t,r){if(t){if(!Zl(r)){e.logger.error("mbh-chat agent error",{sessionId:t,message:r});return}hI(e,t,r)}}function hI(e,t,r){if(e.handledCorruptSessions.has(t))return;e.handledCorruptSessions.add(t);let i=e.stopRequestedSessions.delete(t);if(i?e.logger.info("ignored late mbh-chat agent error after stop",{dshSessionId:t,error:r}):e.logger.error("mbh-chat agent error",{sessionId:t,message:r}),e.unfollowSession?.(t),e.store.removeSessionByDshId(t),e.logger.info("discarded mbh-chat session with corrupt history",{dshSessionId:t,error:r,followsStop:i}),i){for(let o of e.turns.liveRuns())o.dshSessionId===t&&e.turns.finish(o,"stop","cancelled","");return}let n=e.corruptSessionRecoveries.get(t);n&&!n.active.finalized&&n.recover(r);for(let o of e.turns.liveRuns())o.dshSessionId===t&&o!==n?.active&&e.turns.finish(o,"session_invalidated","cancelled","")}var UV=["\u5982\u679C\u4EFB\u52A1\u751F\u6210\u4E86\u4E00\u4E2A\u6216\u591A\u4E2A\u6587\u4EF6\uFF0C\u5FC5\u987B\u5728\u6700\u7EC8\u56DE\u590D\u524D\u8C03\u7528 mbhchat_message \u5DE5\u5177\uFF0C\u5E76\u5728\u540C\u4E00\u4E2A media \u6570\u7EC4\u4E2D\u5217\u51FA\u6240\u6709\u6587\u4EF6\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002","\u4E0D\u8981\u5728\u6B63\u6587\u4E2D\u66B4\u9732\u672C\u5730\u6587\u4EF6\u8DEF\u5F84\uFF1B\u7B49\u5F85\u5DE5\u5177\u8FD4\u56DE success=true \u540E\u518D\u544A\u77E5\u7528\u6237\u6587\u4EF6\u5DF2\u53D1\u9001\u3002","\u666E\u901A\u6B63\u6587\u76F4\u63A5\u4F5C\u4E3A\u52A9\u624B\u56DE\u590D\uFF1Bmbhchat_message \u5DE5\u5177\u4E3B\u8981\u7528\u4E8E\u9644\u4EF6\u4EA4\u4ED8\uFF0C\u907F\u514D\u6B63\u6587\u53CC\u5199\u3002","\u5B9A\u65F6\u4EFB\u52A1\u81EA\u52A8\u6267\u884C\u65F6\uFF0C\u9644\u4EF6\u53CA\u5176\u4EA4\u4ED8\u8BF4\u660E\u4F1A\u4E0E\u6700\u7EC8\u6B63\u6587\u5408\u5E76\u4E3A\u540C\u4E00\u6761\u63A8\u9001\uFF1B\u4ECD\u5E94\u5148\u8C03\u7528\u5DE5\u5177\uFF0C\u5E76\u5728\u6210\u529F\u540E\u518D\u5B8C\u6210\u6B63\u6587\u3002"],BV=`[\u7CFB\u7EDF: ${UV.join("")}]`,wAe=["\u5411\u5F53\u524D\u4E66\u7075\u58A8\u5B9D\u7528\u6237\u53D1\u9001\u6587\u672C\u6216\u9644\u4EF6\u3002",...UV].join(`
|
|
@@ -590,7 +590,7 @@ ${o}${s}${i.text}
|
|
|
590
590
|
|
|
591
591
|
${s}`.trim():s;if(!c&&a.length===0)return[];let u=m=>typeof m=="string"?m.trim():typeof m=="number"&&Number.isFinite(m)?String(Math.trunc(m)):"",l=YV(c,py(t.content)),d=[this.config.messageControl?BV:"",o??"",l].filter(Boolean).join(`
|
|
592
592
|
|
|
593
|
-
`).trim();if(a.length===0)return d?[{type:"text",text:d}]:[];let p=await Vs(a,{storageRoot:n,requestId:r,maxBytes:this.config.media.maxBytes,maxTotalBytes:this.config.media.maxTotalBytes,maxInlineImageBytes:this.config.media.maxInlineImageBytes,fetchTimeoutMs:this.config.media.fetchTimeoutMs,concurrency:this.config.media.concurrency,retentionMs:this.config.media.retentionMs,allowPrivateNetwork:this.config.media.allowPrivateNetwork,resolveReference:m=>this.requestApi.generateSignUrl(m.url,t.content.bot_token?.trim()||this.config.account.botToken,{...t.content.app_id?{appId:t.content.app_id}:{},userId:t._userId})});for(let m of p.failures)this.logger.warn("inbound attachment could not be resolved",{requestId:r,fileName:m.fileName,error:m.reason});let f=MC(d,p),h=f?[{type:"text",text:f}]:[];for(let m of p.media)m.inlineImage&&h.push({type:"image",mediaType:m.inlineImage.mediaType,data:m.inlineImage.data,name:m.fileName});return h}};async function QV(e,t){let r=t.content,i=r.operation_type;try{let n=i==="install"||i==="enable"||i==="update"?await e.skillManager.install(r.skill_url??"",r.skill_code??""):await e.skillManager.uninstall(r.skill_code??"");await e.dcg.sendEvent({...r,status:n.status,...n.success?{}:{error:n.error}})}catch(n){await e.dcg.sendEvent({...r,status:"fail",error:ne(n)})}}async function eZ(e,t){if(t.eventType==="user_question"){try{await jV(e,t)}catch(r){e.logger.warn("user question response invalid",{error:ne(r)})}return}if(t.eventType==="agent"){await Lve(e,t);return}await Fve(e,t)}async function Lve(e,t){try{let r=await e.agentManager.handleEvent(t),i=r.success&&(t.operationType==="create"||t.operationType==="remove")?await e.sessions.invalidateAgentSessions(r.affectedCloneCodes,`agent_${t.operationType}`):[];await e.dcg.sendEvent({...t.content,status:r.status,...r.updatedCodes?{updated_codes:r.updatedCodes}:{},...r.skippedCodes?{skipped_codes:r.skippedCodes}:{},...r.failedCodes?{failed_codes:r.failedCodes}:{},...r.failedReasons?{failed_reasons:r.failedReasons}:{},...r.cacheOnly!==void 0?{cache_only:r.cacheOnly}:{},...i.length>0?{session_cleanup_pending:!0,session_cleanup_clone_codes:i}:{},...r.success?{}:{error:r.message}}),e.logger.info("applied mbh-chat Agent operation",{operationType:t.operationType,success:r.success,affectedCloneCodes:r.affectedCloneCodes})}catch(r){await e.dcg.sendEvent({...t.content,status:"fail",error:ne(r)}),e.logger.warn("mbh-chat Agent operation failed",{operationType:t.operationType,error:ne(r)})}}async function Fve(e,t){let r=nM(t);if(!r){if(t.eventType==="cron"){await e.dcg.sendEvent({...t.content,status:"fail",error:`unsupported cron operation or missing job_id: ${t.operationType}`});return}e.logger.info("ignored mbh-chat event",{eventType:t.eventType,operationType:t.operationType});return}if(!e.cronSync){e.logger.warn("Mobook cron catalog control arrived before catalog sync started",{operation:r.operation,cronId:r.cronId}),await e.dcg.sendEvent({...t.content,status:"fail",error:"cron catalog sync is not ready"});return}r.operation==="run"&&r.messageId&&e.pendingCronMessageIds.set(r.cronId,r.messageId);let i;try{i=await e.cronSync.applyControl(r.operation,r.cronId)}catch(n){r.messageId&&e.pendingCronMessageIds.get(r.cronId)===r.messageId&&e.pendingCronMessageIds.delete(r.cronId),await e.dcg.sendEvent({...t.content,status:"fail",error:ne(n)}),e.logger.warn("Mobook cron catalog control failed",{operation:r.operation,cronId:r.cronId,error:ne(n)});return}i.runStatus!=="dispatched"&&r.messageId&&e.pendingCronMessageIds.get(r.cronId)===r.messageId&&e.pendingCronMessageIds.delete(r.cronId),e.logger.info("applied Mobook cron catalog control",{operation:r.operation,cronId:r.cronId,ok:i.applied,...i.runStatus?{runStatus:i.runStatus}:{},...i.reconciled?{reconciled:!0}:{}}),i.applied||e.logger.warn("Mobook cron catalog control did not apply",{operation:r.operation,cronId:r.cronId,...i.runStatus?{runStatus:i.runStatus}:{}}),await e.dcg.sendEvent({...t.content,status:i.applied?"ok":"fail",...i.runStatus?{run_status:i.runStatus}:{},...i.reconciled!==void 0?{reconciled:i.reconciled}:{}})}import iZ from"node:path";import mI from"node:fs";import wc from"node:path";var tZ=new Set([".webp",".gif",".bmp",".png",".jpg",".jpeg",".svg",".ico",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".pdf",".txt",".rtf",".odt",".json",".xml",".csv",".yaml",".yml",".html",".htm",".md",".markdown",".css",".js",".mjs",".ts",".py",".pyi",".ipynb",".zip",".rar",".7z",".tar",".gz",".bz2",".xz",".log",".dat",".bin",".mp3",".wav",".ogg",".aac",".m4a",".flac",".mp4",".avi",".mov",".wmv",".flv",".mkv",".webm"]),Xl={bash:{package:"dsh-tool-bash / dsh-tool-bash-persistent",name:"\u6267\u884C\u547D\u4EE4"},pwsh:{package:"dsh-tool-pwsh / dsh-tool-pwsh-persistent",name:"\u6267\u884C\u547D\u4EE4"},read:{package:"dsh-tool-fs",name:"\u8BFB\u53D6\u6587\u4EF6"},write:{package:"dsh-tool-fs",name:"\u5199\u5165\u6587\u4EF6"},edit:{package:"dsh-tool-fs",name:"\u7F16\u8F91\u6587\u4EF6"},read_image:{package:"dsh-tool-fs",name:"\u8BFB\u53D6\u56FE\u7247"},glob:{package:"dsh-tool-fs-search",name:"\u6309\u6A21\u5F0F\u627E\u6587\u4EF6"},grep:{package:"dsh-tool-fs-search",name:"\u641C\u7D22\u6587\u4EF6\u5185\u5BB9"},web_search:{package:"dsh-tool-web",name:"\u8054\u7F51\u641C\u7D22"},web_fetch:{package:"dsh-tool-web",name:"\u6293\u53D6\u7F51\u9875"},todo_write:{package:"dsh-tool-todo",name:"\u66F4\u65B0\u4EFB\u52A1\u6E05\u5355"},skill:{package:"dsh-tool-skill",name:"\u52A0\u8F7D\u6280\u80FD"},ask_user_question:{package:"dsh-tool-ask-user",name:"\u5411\u7528\u6237\u63D0\u95EE"},create_goal:{package:"dsh-tool-goal",name:"\u521B\u5EFA\u76EE\u6807"},get_goal:{package:"dsh-tool-goal",name:"\u8BFB\u53D6\u76EE\u6807"},update_goal:{package:"dsh-tool-goal",name:"\u66F4\u65B0\u76EE\u6807"},job_list:{package:"dsh-tool-jobs",name:"\u5217\u51FA\u540E\u53F0\u4EFB\u52A1"},job_output:{package:"dsh-tool-jobs",name:"\u8BFB\u53D6\u4EFB\u52A1\u8F93\u51FA"},job_kill:{package:"dsh-tool-jobs",name:"\u7EC8\u6B62\u540E\u53F0\u4EFB\u52A1"},subagent:{package:"dsh-tool-subagent",name:"\u59D4\u6D3E\u5B50\u4EE3\u7406"},send_message:{package:"dsh-tool-subagent-control",name:"\u7ED9\u5B50\u4EE3\u7406\u53D1\u6D88\u606F"},list_agents:{package:"dsh-tool-subagent-control",name:"\u5217\u51FA\u5B50\u4EE3\u7406"},interrupt_agent:{package:"dsh-tool-subagent-control",name:"\u4E2D\u65AD\u5B50\u4EE3\u7406"},report:{package:"dsh-tool-subagent-report",name:"\u5B50\u4EE3\u7406\u5185\u90E8\u6C47\u62A5"},workflow:{package:"dsh-tool-workflow",name:"\u591A\u4EE3\u7406\u7F16\u6392"},ralph:{package:"dsh-tool-ralph",name:"\u5168\u65B0\u4EE3\u7406\u8FED\u4EE3\u5FAA\u73AF"},str_replace_editor:{package:"dsh-tool-str-replace-editor",name:"\u5B57\u7B26\u4E32\u66FF\u6362\u7F16\u8F91\u5668"}};var zve=new Set([".exe",".dmg",".pkg",".apk",".ipa"]),Uve=new Set([...tZ,...zve]);function rZ(e){if(!e||typeof e!="object")return"\u8BF7\u6C42\u5FC5\u987B\u662F\u5BF9\u8C61";if(typeof e.sessionId!="string"||!e.sessionId.trim())return"\u7F3A\u5C11 mbh-chat sessionId";if(typeof e.callId!="string"||!e.callId.trim())return"\u7F3A\u5C11\u5DE5\u5177 callId";if(!e.args||typeof e.args!="object")return"\u7F3A\u5C11\u5DE5\u5177\u53C2\u6570";if(e.args.target!==void 0&&typeof e.args.target!="string")return"target \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";if(e.args.content!==void 0&&typeof e.args.content!="string")return"content \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";if(e.workspaceDir!==void 0&&typeof e.workspaceDir!="string")return"workspaceDir \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";if(e.args.media!==void 0&&!Array.isArray(e.args.media))return"media \u5FC5\u987B\u662F\u6570\u7EC4";if((e.args.media??[]).some(t=>!t||typeof t.file!="string"||!t.file.trim()))return"media \u4E2D\u6BCF\u9879\u90FD\u5FC5\u987B\u5305\u542B\u975E\u7A7A file";if(!e.args.content?.trim()&&(e.args.media?.length??0)===0)return"content \u548C media \u81F3\u5C11\u63D0\u4F9B\u4E00\u9879"}function nZ(e,t,r){if(!wc.isAbsolute(e))throw new Error(`\u9644\u4EF6\u5FC5\u987B\u4F7F\u7528\u7EDD\u5BF9\u8DEF\u5F84\uFF1A${e}`);let i,n;try{i=mI.realpathSync(e),n=mI.statSync(i)}catch{throw new Error(`\u9644\u4EF6\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BFB\uFF1A${e}`)}if(!n.isFile()||n.size===0)throw new Error(`\u9644\u4EF6\u5FC5\u987B\u662F\u975E\u7A7A\u666E\u901A\u6587\u4EF6\uFF1A${e}`);if(n.size>r)throw new Error(`\u9644\u4EF6\u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650 ${r} bytes\uFF1A${wc.basename(e)}`);let o=wc.extname(i).toLowerCase();if(!Uve.has(o))throw new Error(`\u4E0D\u5141\u8BB8\u53D1\u9001\u6B64\u6587\u4EF6\u7C7B\u578B\uFF1A${o||"\u65E0\u6269\u5C55\u540D"}`);if(!t.some(a=>{try{let c=mI.realpathSync(a),u=wc.relative(c,i);return u===""||!u.startsWith(`..${wc.sep}`)&&u!==".."&&!wc.isAbsolute(u)}catch{return!1}}))throw new Error(`\u9644\u4EF6\u8DEF\u5F84\u4E0D\u5728\u5F53\u524D mbh-chat \u5DE5\u4F5C\u533A\u5185\uFF1A${e}`);return i}async function oZ(e){let{request:t,signal:r,config:i,activeBySession:n,ossUpload:o,dcg:s,logger:a}=e,c=rZ(t);if(c)return{success:!1,sentMediaCount:0,queued:!1,error:c};let u=n.get(t.sessionId);if(!u||u.finalized)return{success:!1,sentMediaCount:0,queued:!1,error:"\u5F53\u524D\u4F1A\u8BDD\u6CA1\u6709\u6D3B\u8DC3\u8BF7\u6C42\uFF0C\u5DF2\u62D2\u7EDD\u8FC7\u671F\u53D1\u9001"};let l=t.args.target?.trim();if(l&&l.toLowerCase()!==u.businessKey.toLowerCase())return{success:!1,sentMediaCount:0,queued:!1,error:"target \u4E0E\u5F53\u524D mbh-chat SessionKey \u4E0D\u4E00\u81F4"};let d=t.args.media??[];if(d.length>20)return{success:!1,sentMediaCount:0,queued:!1,error:"\u5355\u6B21\u6700\u591A\u53D1\u9001 20 \u4E2A\u9644\u4EF6"};let p=[t.workspaceDir,i.dsh.workspaceCwd,i.dsh.outputRoot,"/workspace","/mobook",...i.outboundExtraRoots].filter(_=>!!_?.trim()),f=[],h=new Set;try{for(let _ of d){let k=nZ(_.file,p,i.media.maxBytes);h.has(k)||(h.add(k),f.push(k))}}catch(_){return{success:!1,sentMediaCount:0,queued:!1,error:ne(_)}}let m=[];try{for(let x of f){if(r.aborted)throw r.reason??new Error("mbhchat_message aborted");let v=await o(x,u.botToken,1,void 0,{...u.context.appId?{appId:u.context.appId}:{},userId:u.context.userId,signal:r});if(!v)throw new Error(`\u9644\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF1A${iZ.basename(x)}`);m.push({url:v,name:iZ.basename(x)})}let _=t.args.content?.trim()??"",k=[...new Set(d.map(x=>x.file))].sort((x,v)=>v.length-x.length);for(let x of k)_=_.split(x).join("");if(_=_.trim(),u.followup)_&&(u.cronText+=u.cronText?`
|
|
593
|
+
`).trim();if(a.length===0)return d?[{type:"text",text:d}]:[];let p=await Vs(a,{storageRoot:n,requestId:r,maxBytes:this.config.media.maxBytes,maxTotalBytes:this.config.media.maxTotalBytes,maxInlineImageBytes:this.config.media.maxInlineImageBytes,fetchTimeoutMs:this.config.media.fetchTimeoutMs,concurrency:this.config.media.concurrency,retentionMs:this.config.media.retentionMs,allowPrivateNetwork:this.config.media.allowPrivateNetwork,resolveReference:m=>this.requestApi.generateSignUrl(m.url,t.content.bot_token?.trim()||this.config.account.botToken,{...t.content.app_id?{appId:t.content.app_id}:{},userId:t._userId})});for(let m of p.failures)this.logger.warn("inbound attachment could not be resolved",{requestId:r,fileName:m.fileName,error:m.reason});let f=MC(d,p),h=f?[{type:"text",text:f}]:[];for(let m of p.media)m.inlineImage&&h.push({type:"image",mediaType:m.inlineImage.mediaType,data:m.inlineImage.data,name:m.fileName});return h}};async function QV(e,t){let r=t.content,i=r.operation_type;try{let n=i==="install"||i==="enable"||i==="update"?await e.skillManager.install(r.skill_url??"",r.skill_code??""):await e.skillManager.uninstall(r.skill_code??"");await e.dcg.sendEvent({...r,status:n.status,...n.success?{}:{error:n.error}})}catch(n){await e.dcg.sendEvent({...r,status:"fail",error:ne(n)})}}async function eZ(e,t){if(t.eventType==="user_question"){try{await jV(e,t)}catch(r){e.logger.warn("user question response invalid",{error:ne(r)})}return}if(t.eventType==="agent"){await Lve(e,t);return}await Fve(e,t)}async function Lve(e,t){try{let r=await e.agentManager.handleEvent(t),i=r.success&&(t.operationType==="create"||t.operationType==="remove")?await e.sessions.invalidateAgentSessions(r.affectedCloneCodes,`agent_${t.operationType}`):[];await e.dcg.sendEvent({...t.content,status:r.status,...r.updatedCodes?{updated_codes:r.updatedCodes}:{},...r.skippedCodes?{skipped_codes:r.skippedCodes}:{},...r.failedCodes?{failed_codes:r.failedCodes}:{},...r.failedReasons?{failed_reasons:r.failedReasons}:{},...r.cacheOnly!==void 0?{cache_only:r.cacheOnly}:{},...i.length>0?{session_cleanup_pending:!0,session_cleanup_clone_codes:i}:{},...r.success?{}:{error:r.message}}),e.logger.info("applied mbh-chat Agent operation",{operationType:t.operationType,success:r.success,affectedCloneCodes:r.affectedCloneCodes})}catch(r){await e.dcg.sendEvent({...t.content,status:"fail",error:ne(r)}),e.logger.warn("mbh-chat Agent operation failed",{operationType:t.operationType,error:ne(r)})}}async function Fve(e,t){let r=nM(t);if(!r){if(t.eventType==="cron"){await e.dcg.sendEvent({...t.content,status:"fail",error:`unsupported cron operation or missing job_id: ${t.operationType}`});return}e.logger.info("ignored mbh-chat event",{eventType:t.eventType,operationType:t.operationType});return}if(!e.cronSync){e.logger.warn("Mobook cron catalog control arrived before catalog sync started",{operation:r.operation,cronId:r.cronId}),await e.dcg.sendEvent({...t.content,status:"fail",error:"cron catalog sync is not ready"});return}r.operation==="run"&&r.messageId&&e.pendingCronMessageIds.set(r.cronId,r.messageId);let i;try{i=await e.cronSync.applyControl(r.operation,r.cronId)}catch(n){r.messageId&&e.pendingCronMessageIds.get(r.cronId)===r.messageId&&e.pendingCronMessageIds.delete(r.cronId),await e.dcg.sendEvent({...t.content,status:"fail",error:ne(n)}),e.logger.warn("Mobook cron catalog control failed",{operation:r.operation,cronId:r.cronId,error:ne(n)});return}i.runStatus!=="dispatched"&&r.messageId&&e.pendingCronMessageIds.get(r.cronId)===r.messageId&&e.pendingCronMessageIds.delete(r.cronId),e.logger.info("applied Mobook cron catalog control",{operation:r.operation,cronId:r.cronId,ok:i.applied,...i.runStatus?{runStatus:i.runStatus}:{},...i.reconciled?{reconciled:!0}:{}}),i.applied||e.logger.warn("Mobook cron catalog control did not apply",{operation:r.operation,cronId:r.cronId,...i.runStatus?{runStatus:i.runStatus}:{}}),await e.dcg.sendEvent({...t.content,status:i.applied?"ok":"fail",...i.runStatus?{run_status:i.runStatus}:{},...i.reconciled!==void 0?{reconciled:i.reconciled}:{}})}import iZ from"node:path";import mI from"node:fs";import wc from"node:path";var tZ=new Set([".webp",".gif",".bmp",".png",".jpg",".jpeg",".svg",".ico",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".pdf",".epub",".txt",".rtf",".odt",".json",".xml",".csv",".yaml",".yml",".html",".htm",".md",".markdown",".css",".js",".mjs",".ts",".py",".pyi",".ipynb",".zip",".rar",".7z",".tar",".gz",".bz2",".xz",".log",".dat",".bin",".mp3",".wav",".ogg",".aac",".m4a",".flac",".mp4",".avi",".mov",".wmv",".flv",".mkv",".webm"]),Xl={bash:{package:"dsh-tool-bash / dsh-tool-bash-persistent",name:"\u6267\u884C\u547D\u4EE4"},pwsh:{package:"dsh-tool-pwsh / dsh-tool-pwsh-persistent",name:"\u6267\u884C\u547D\u4EE4"},read:{package:"dsh-tool-fs",name:"\u8BFB\u53D6\u6587\u4EF6"},write:{package:"dsh-tool-fs",name:"\u5199\u5165\u6587\u4EF6"},edit:{package:"dsh-tool-fs",name:"\u7F16\u8F91\u6587\u4EF6"},read_image:{package:"dsh-tool-fs",name:"\u8BFB\u53D6\u56FE\u7247"},glob:{package:"dsh-tool-fs-search",name:"\u6309\u6A21\u5F0F\u627E\u6587\u4EF6"},grep:{package:"dsh-tool-fs-search",name:"\u641C\u7D22\u6587\u4EF6\u5185\u5BB9"},web_search:{package:"dsh-tool-web",name:"\u8054\u7F51\u641C\u7D22"},web_fetch:{package:"dsh-tool-web",name:"\u6293\u53D6\u7F51\u9875"},todo_write:{package:"dsh-tool-todo",name:"\u66F4\u65B0\u4EFB\u52A1\u6E05\u5355"},skill:{package:"dsh-tool-skill",name:"\u52A0\u8F7D\u6280\u80FD"},ask_user_question:{package:"dsh-tool-ask-user",name:"\u5411\u7528\u6237\u63D0\u95EE"},create_goal:{package:"dsh-tool-goal",name:"\u521B\u5EFA\u76EE\u6807"},get_goal:{package:"dsh-tool-goal",name:"\u8BFB\u53D6\u76EE\u6807"},update_goal:{package:"dsh-tool-goal",name:"\u66F4\u65B0\u76EE\u6807"},job_list:{package:"dsh-tool-jobs",name:"\u5217\u51FA\u540E\u53F0\u4EFB\u52A1"},job_output:{package:"dsh-tool-jobs",name:"\u8BFB\u53D6\u4EFB\u52A1\u8F93\u51FA"},job_kill:{package:"dsh-tool-jobs",name:"\u7EC8\u6B62\u540E\u53F0\u4EFB\u52A1"},subagent:{package:"dsh-tool-subagent",name:"\u59D4\u6D3E\u5B50\u4EE3\u7406"},send_message:{package:"dsh-tool-subagent-control",name:"\u7ED9\u5B50\u4EE3\u7406\u53D1\u6D88\u606F"},list_agents:{package:"dsh-tool-subagent-control",name:"\u5217\u51FA\u5B50\u4EE3\u7406"},interrupt_agent:{package:"dsh-tool-subagent-control",name:"\u4E2D\u65AD\u5B50\u4EE3\u7406"},report:{package:"dsh-tool-subagent-report",name:"\u5B50\u4EE3\u7406\u5185\u90E8\u6C47\u62A5"},workflow:{package:"dsh-tool-workflow",name:"\u591A\u4EE3\u7406\u7F16\u6392"},ralph:{package:"dsh-tool-ralph",name:"\u5168\u65B0\u4EE3\u7406\u8FED\u4EE3\u5FAA\u73AF"},str_replace_editor:{package:"dsh-tool-str-replace-editor",name:"\u5B57\u7B26\u4E32\u66FF\u6362\u7F16\u8F91\u5668"}};var zve=new Set([".exe",".dmg",".pkg",".apk",".ipa"]),Uve=new Set([...tZ,...zve]);function rZ(e){if(!e||typeof e!="object")return"\u8BF7\u6C42\u5FC5\u987B\u662F\u5BF9\u8C61";if(typeof e.sessionId!="string"||!e.sessionId.trim())return"\u7F3A\u5C11 mbh-chat sessionId";if(typeof e.callId!="string"||!e.callId.trim())return"\u7F3A\u5C11\u5DE5\u5177 callId";if(!e.args||typeof e.args!="object")return"\u7F3A\u5C11\u5DE5\u5177\u53C2\u6570";if(e.args.target!==void 0&&typeof e.args.target!="string")return"target \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";if(e.args.content!==void 0&&typeof e.args.content!="string")return"content \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";if(e.workspaceDir!==void 0&&typeof e.workspaceDir!="string")return"workspaceDir \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";if(e.args.media!==void 0&&!Array.isArray(e.args.media))return"media \u5FC5\u987B\u662F\u6570\u7EC4";if((e.args.media??[]).some(t=>!t||typeof t.file!="string"||!t.file.trim()))return"media \u4E2D\u6BCF\u9879\u90FD\u5FC5\u987B\u5305\u542B\u975E\u7A7A file";if(!e.args.content?.trim()&&(e.args.media?.length??0)===0)return"content \u548C media \u81F3\u5C11\u63D0\u4F9B\u4E00\u9879"}function nZ(e,t,r){if(!wc.isAbsolute(e))throw new Error(`\u9644\u4EF6\u5FC5\u987B\u4F7F\u7528\u7EDD\u5BF9\u8DEF\u5F84\uFF1A${e}`);let i,n;try{i=mI.realpathSync(e),n=mI.statSync(i)}catch{throw new Error(`\u9644\u4EF6\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BFB\uFF1A${e}`)}if(!n.isFile()||n.size===0)throw new Error(`\u9644\u4EF6\u5FC5\u987B\u662F\u975E\u7A7A\u666E\u901A\u6587\u4EF6\uFF1A${e}`);if(n.size>r)throw new Error(`\u9644\u4EF6\u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650 ${r} bytes\uFF1A${wc.basename(e)}`);let o=wc.extname(i).toLowerCase();if(!Uve.has(o))throw new Error(`\u4E0D\u5141\u8BB8\u53D1\u9001\u6B64\u6587\u4EF6\u7C7B\u578B\uFF1A${o||"\u65E0\u6269\u5C55\u540D"}`);if(!t.some(a=>{try{let c=mI.realpathSync(a),u=wc.relative(c,i);return u===""||!u.startsWith(`..${wc.sep}`)&&u!==".."&&!wc.isAbsolute(u)}catch{return!1}}))throw new Error(`\u9644\u4EF6\u8DEF\u5F84\u4E0D\u5728\u5F53\u524D mbh-chat \u5DE5\u4F5C\u533A\u5185\uFF1A${e}`);return i}async function oZ(e){let{request:t,signal:r,config:i,activeBySession:n,ossUpload:o,dcg:s,logger:a}=e,c=rZ(t);if(c)return{success:!1,sentMediaCount:0,queued:!1,error:c};let u=n.get(t.sessionId);if(!u||u.finalized)return{success:!1,sentMediaCount:0,queued:!1,error:"\u5F53\u524D\u4F1A\u8BDD\u6CA1\u6709\u6D3B\u8DC3\u8BF7\u6C42\uFF0C\u5DF2\u62D2\u7EDD\u8FC7\u671F\u53D1\u9001"};let l=t.args.target?.trim();if(l&&l.toLowerCase()!==u.businessKey.toLowerCase())return{success:!1,sentMediaCount:0,queued:!1,error:"target \u4E0E\u5F53\u524D mbh-chat SessionKey \u4E0D\u4E00\u81F4"};let d=t.args.media??[];if(d.length>20)return{success:!1,sentMediaCount:0,queued:!1,error:"\u5355\u6B21\u6700\u591A\u53D1\u9001 20 \u4E2A\u9644\u4EF6"};let p=[t.workspaceDir,i.dsh.workspaceCwd,i.dsh.outputRoot,"/workspace","/mobook",...i.outboundExtraRoots].filter(_=>!!_?.trim()),f=[],h=new Set;try{for(let _ of d){let k=nZ(_.file,p,i.media.maxBytes);h.has(k)||(h.add(k),f.push(k))}}catch(_){return{success:!1,sentMediaCount:0,queued:!1,error:ne(_)}}let m=[];try{for(let x of f){if(r.aborted)throw r.reason??new Error("mbhchat_message aborted");let v=await o(x,u.botToken,1,void 0,{...u.context.appId?{appId:u.context.appId}:{},userId:u.context.userId,signal:r});if(!v)throw new Error(`\u9644\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF1A${iZ.basename(x)}`);m.push({url:v,name:iZ.basename(x)})}let _=t.args.content?.trim()??"",k=[...new Set(d.map(x=>x.file))].sort((x,v)=>v.length-x.length);for(let x of k)_=_.split(x).join("");if(_=_.trim(),u.followup)_&&(u.cronText+=u.cronText?`
|
|
594
594
|
${_}`:_),u.cronAttachments.push(...m);else{let x={response:_,state:"chunk",chunk_idx:u.chunkIndex++,is_finish:0,...m.length>0?{files:m}:{}};s.enqueue(u.context,x,`message-tool:${t.callId}`),await s.flush()}return a.info("mbhchat_message queued",{dshSessionId:t.sessionId,callId:t.callId,sentMediaCount:m.length}),{success:!0,sentMediaCount:m.length,queued:!0}}catch(_){return a.warn("mbhchat_message failed",{dshSessionId:t.sessionId,callId:t.callId,error:ne(_)}),{success:!1,sentMediaCount:0,queued:!1,error:ne(_)}}}import{randomUUID as lZ}from"node:crypto";import Zve from"node:path";var Jl=0;function gI(e=Date.now()){return Jl=Math.max(e,Jl+1),String(Jl)}function sZ(e,t=Date.now()){if(e){let i=Number(e);return Number.isSafeInteger(i)&&(Jl=Math.max(Jl,i)),{notification:e,chat:gI(t)}}return{notification:gI(t),chat:gI(t)}}function my(e){let t,r=new Promise(s=>{t=s}),i=e.deadlineAt??Date.now()+e.taskTimeoutMs,n=Math.max(1,Math.min(e.turnTimeoutMs,i-Date.now())),o={context:e.context,botToken:e.botToken,businessKey:e.businessKey,dshSessionId:e.dshSessionId,...e.turn!==void 0?{turn:e.turn}:{},chunkIndex:e.chunkIndex??0,pendingText:"",cronText:"",cronAttachments:[],stepText:new Map,pendingReasoning:"",stepReasoning:new Map,reasoningLineIndex:0,reasoningStarted:!1,reasoningMessageKey:void 0,reasoningSort:void 0,toolCalls:new Map,pendingSubagents:new Set,subagentParents:new Map,settledSubagents:new Set,finalized:!1,followup:e.followup,deadlineAt:i,completion:r,resolveCompletion:t,timeout:setTimeout(()=>e.onTimeout(o),n)};return o}import{createHash as Bve}from"node:crypto";import Wve from"node:fs/promises";import Rn from"node:path";function Vve(e){return Bve("sha256").update(e).digest("hex").slice(0,24)}function aZ(e,t){let r=Rn.resolve(e);if(!t)return r;let i=Rn.resolve(t);if(i===r)return r;let n=Rn.dirname(r),o=Rn.dirname(n);return i===o||i===n?r:Rn.join(i,"output")}async function cZ(e,t){let r=Rn.join(e,Vve(t)),i={root:r,files:Rn.join(r,"files"),tmp:Rn.join(r,"tmp"),previews:Rn.join(r,"previews"),downloads:Rn.join(r,"downloads")};return await Promise.all(Object.values(i).map(n=>Wve.mkdir(n,{recursive:!0}))),i}function uZ(e){return["[MOBOOK OUTPUT DIRECTORY]",`This session's output directory is: ${e.root}`,`Final deliverables: ${e.files}`,`Temporary scripts and intermediate files: ${e.tmp}`,`Rendered previews and validation images: ${e.previews}`,`Downloaded task inputs: ${e.downloads}`,"Write every newly created task artifact into one of these directories. Reuse these directories throughout this session instead of creating a directory for each turn. Do not write task artifacts directly into DSH_HOME, the shared workspace root, or another session. Existing project files may be edited in place only when the user explicitly requested that edit."].join(`
|
|
595
595
|
`)}async function fZ(e,t,r,i){if(!e.started)return;let n=XV(t.content);n?.source==="intent"&&e.intentFeedback.matched(r,"\u4E13\u5BB6",n.value.name);let s=(n?!await e.agentManager.hasWorkspace(n.value.cloneCode):!1)?e.intentFeedback.beginInstall(r,"\u4E13\u5BB6",n?.value.name??"\u4E13\u5BB6"):void 0,a=await e.inboundPrompt.prepareAgentRoute(t);s&&e.intentFeedback.finishInstall(r,s,!("error"in a));let c=0;if("error"in a){if(!n){e.turns.sendImmediateFinal(r,"agent_not_installed","failed",a.error);return}e.dcg.enqueue(r,{response:`${n.value.name}\u5B89\u88C5\u5931\u8D25\uFF0C\u7531\u4E66\u7075\u58A8\u5B9D\u4E3A\u60A8\u89E3\u7B54\u3002`,state:"chunk",chunk_idx:c++,message_tags:{source:"agent_install_failed"},is_finish:-1},"agent:install-failed"),a={...e.config.dsh.workspaceCwd?{workspaceDir:e.config.dsh.workspaceCwd}:{},agentPreset:e.config.dsh.agentPreset,managed:!1}}let u=JV(t.content);u?.source==="intent"&&e.intentFeedback.matched(r,"\u6280\u80FD",u.value.name);let d=(u?!e.skillManager.exists(u.value.code):!1)?e.intentFeedback.beginInstall(r,"\u6280\u80FD",u?.value.name??"\u6280\u80FD"):void 0,p=await e.inboundPrompt.prepareSelectedSkill(t);d&&e.intentFeedback.finishInstall(r,d,!p.error);let f=p.error;f&&e.dcg.enqueue(r,{response:f,state:"chunk",chunk_idx:c++,message_tags:{source:"skill_install_failed"},is_finish:-1},"skill:install-failed"),e.intentFeedback.knowledgeSearch(r,py(t.content));let h=a.managed&&a.workspaceDir?aZ(e.config.dsh.outputRoot,a.workspaceDir):e.config.dsh.outputRoot,m=await cZ(h,r.businessKey),_=await e.inboundPrompt.promptContent(t,r.requestId,p.promptPrefix,a.workspaceDir?Zve.join(a.workspaceDir,"inbound"):e.config.media.storageRoot,uZ(m));if(_.length===0){e.turns.sendImmediateFinal(r,"not_text","succeeded","\u4F60\u9700\u8981\u6211\u5E2E\u4F60\u505A\u4EC0\u4E48\u5462\uFF1F");return}if(await e.dsh.whenConnected(e.connectionWaitSignal()),!e.started)return;if(i!==void 0&&i<=Date.now())throw new Error("task preparation timed out");let k=await e.sessions.ensureSession(r.businessKey,t.content.model,a,r);if(e.stopRequestedSessions.delete(k),!e.started)return;if(!e.store.markRequestRunning(r.requestId,k)){e.logger.warn("mbh-chat request was no longer waiting before execution",{requestId:r.requestId});return}let x=my({context:r,botToken:t.content.bot_token?.trim()||e.config.account.botToken,businessKey:r.businessKey,dshSessionId:k,chunkIndex:c,followup:!1,turnTimeoutMs:e.config.turnTimeoutMs,taskTimeoutMs:e.config.task.timeoutMs,...i===void 0?{}:{deadlineAt:i},onTimeout:$=>{e.turns.onTurnTimeout($)}});e.activeBySession.set(k,x);let v=_,g=0,y=!1,T=new Set,D=async $=>{let B=await e.dsh.api.sessions.prompt({requestId:lZ(),sessionId:$,mode:"queue",content:v,clientTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone});return!B.result.ok&&B.result.error.code==="attachment-error"&&v.some(C=>C.type==="image")&&(e.logger.warn("mbh-chat rejected inline image input; retrying with readable local attachment paths",{requestId:r.requestId,reason:B.result.error.message}),v=v.filter(C=>C.type==="text"),B=await e.dsh.api.sessions.prompt({requestId:lZ(),sessionId:$,mode:"queue",content:v,clientTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone})),B},I=$=>{An($)},b=$=>{T.delete($),e.corruptSessionRecoveries.get($)?.active===x&&e.corruptSessionRecoveries.delete($)},O=async($,B)=>{e.cancelPendingUserQuestions($),e.turns.detachForSessionRetry(x,$),e.store.removeSession(r.businessKey);let C=await e.sessions.ensureSession(r.businessKey,t.content.model,a,r);if(!e.started||x.finalized){e.store.removeSession(r.businessKey),b($);return}if(x.deadlineAt<=Date.now())throw new Error("task timed out while recovering the session");return k=C,e.store.updateRequestExecutionSession(r.requestId,C),b($),e.turns.attachAfterSessionRetry(x,C),R(C),e.logger.info("recreated mbh-chat session and resubmitting the current request",{requestId:r.requestId,oldDshSessionId:$,dshSessionId:C,reason:B}),C},R=$=>{T.add($),e.corruptSessionRecoveries.set($,{active:x,recover:B=>{x.finalized||y||x.dshSessionId!==$||(y=!0,P($,B))}})};async function P($,B){try{if(g+=1,g>1)throw new Error("session history recovery was already attempted");let C=await O($,B);if(!C)return;I(await D(C))}catch(C){e.logger.error("could not recover corrupt mbh-chat session",{requestId:r.requestId,dshSessionId:$,error:ne(C)}),x.finalized||e.turns.finish(x,"session_recovery_failed","failed","[\u9519\u8BEF] \u4F1A\u8BDD\u81EA\u52A8\u6062\u590D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")}finally{y=!1}}try{R(k);try{let $=await D(k);if(!$.result.ok&&nI($.result.error.code)){let B=await O(k,$.result.error.code);if(!B)return;$=await D(B)}I($)}catch($){e.logger.error("mbh-chat prompt submission failed",{requestId:r.requestId,dshSessionId:k,error:ne($)}),e.turns.finish(x,"error","failed",bc($))}await x.completion}finally{for(let $ of T)b($)}}var Hve="\uFEFF",Gve="cron_running";function gy(e,t,r,i=!0){let n=e.store.getBusinessKeyByDshSessionId(t);if(!n&&ay(r)){let h=sy(r,"cron_id");h&&(n=e.resolveCronBusinessKey?.(h))}if(!n){e.logger.warn("unsolicited mbh-chat session event has no mapped mbh-chat session",{dshSessionId:t,type:r.type});return}let o=e.store.getLatestContextForBusinessKey(n);if(!o){e.logger.warn("unsolicited mbh-chat session event has no prior outbound context",{dshSessionId:t,businessKey:n});return}let s=sy(r,"cron_id"),a=s?e.pendingCronMessageIds.get(s):void 0;s&&a&&e.pendingCronMessageIds.delete(s);let c=sZ(a),u={...o,messageId:c.notification,requestId:Yn(o.accountId,c.notification)},l={...o,messageId:c.chat,requestId:Yn(o.accountId,c.chat)},d=ye(r.data),p=my({context:l,botToken:e.config.botToken,businessKey:n,dshSessionId:t,...typeof d?.turn=="number"?{turn:d.turn}:{},followup:!0,turnTimeoutMs:e.config.turnTimeoutMs,taskTimeoutMs:e.config.taskTimeoutMs,onTimeout:h=>{e.onTurnTimeout(h)}});e.trackRun(p),i&&e.activeBySession.set(t,p);let f=sy(r,"name")??"\u5B9A\u65F6\u4EFB\u52A1";try{e.dcg.enqueue(l,{response:Hve,state:"chunk",message_tags:{source:Gve,uid:l.messageId},is_finish:0},"cron:loading")}catch(h){e.logger.warn("could not persist cron loading message",{cronId:s,requestId:l.requestId,error:ne(h)})}return e.dcg.enqueueEvent(u,{event_type:"notify",operation_type:"cron",title:f,message_id:u.messageId,desc:""}),e.logger.info("started mbh-chat followup run for unsolicited mbh-chat turn",{dshSessionId:t,requestId:l.requestId,sessionId:l.sessionId,type:r.type}),p}var Kve=["i'll start by loading the skill instructions","i'll start by loading the skill instruction","i will start by loading the skill instructions","i will start by loading the skill instruction","let me start by loading the skill instructions","let me start by loading the skill instruction","let me load the skill instructions","let me load the skill instruction","i'm going to start by loading the skill instructions","i'm going to load the skill instructions","i am going to start by loading the skill instructions","i am going to load the skill instructions","loading the skill instructions","loading the skill instruction","\u6211\u5148\u52A0\u8F7D\u6280\u80FD\u8BF4\u660E","\u6211\u5148\u52A0\u8F7D\u6280\u80FD\u6307\u4EE4","\u6211\u5148\u52A0\u8F7D\u6280\u80FD\u5185\u5BB9","\u6211\u5F00\u59CB\u52A0\u8F7D\u6280\u80FD\u8BF4\u660E","\u6211\u5F00\u59CB\u52A0\u8F7D\u6280\u80FD\u6307\u4EE4","\u6211\u5F00\u59CB\u52A0\u8F7D\u6280\u80FD\u5185\u5BB9","\u5148\u52A0\u8F7D\u6280\u80FD\u8BF4\u660E","\u5148\u52A0\u8F7D\u6280\u80FD\u6307\u4EE4","\u6B63\u5728\u52A0\u8F7D\u6280\u80FD\u8BF4\u660E","\u6B63\u5728\u52A0\u8F7D\u6280\u80FD\u6307\u4EE4"],Xve=[String.raw`I(?:'ll| will) start by loading the skill instructions?`,String.raw`Let me start by loading the skill instructions?`,String.raw`Let me load the skill instructions?`,String.raw`I(?:'m| am) going to (?:start by )?load(?:ing)? the skill instructions?`,String.raw`Loading the skill instructions?`],Jve=[String.raw`我先加载技能(?:说明|指令|内容)`,String.raw`我开始加载技能(?:说明|指令|内容)`,String.raw`先加载技能(?:说明|指令)`,String.raw`正在加载技能(?:说明|指令)`],dZ=new RegExp(String.raw`(?:\b(?:${Xve.join("|")})|(?:${Jve.join("|")}))[.!?。!…]*`,"gi");function Yve(e){return e.trim().replace(/[.!?。!…]+$/u,"").replace(/\s+/g," ").toLowerCase()}function Qve(e){return e&&(dZ.lastIndex=0,e.replace(dZ,"").replace(/[^\S\n]{2,}/g," ").replace(/^\s+/,""))}function ebe(e){let t=Yve(e);return t?Kve.some(r=>r.startsWith(t)&&t!==r):!1}function Yl(e){let t=Qve(e);return{buffer:t,hold:ebe(t)}}var tbe=/(?:\r?\n+|[。!?!?;;]+[”’"'))】》」』]*\s*)/gu,rbe=/(?:[,,、::]|\s+)/gu;function pZ(e,t){let r=[];t.lastIndex=0;for(let i=t.exec(e);i;i=t.exec(e))r.push(i.index+i[0].length);return r}function nbe(e,t){let r=Math.min(t,e.length);if(r>0&&r<e.length){let i=e.charCodeAt(r-1),n=e.charCodeAt(r);i>=55296&&i<=56319&&n>=56320&&n<=57343&&(r-=1)}return r}function yI(e,t){if(!e)return 0;let r=pZ(e,tbe),i=r.filter(s=>s>=t.minChars);if(e.length<=t.maxChars)return t.keepLastComplete&&i.length>=2?i[i.length-2]??0:!t.keepLastComplete&&i.length>=1?i[i.length-1]??0:0;let n=r.filter(s=>s<=t.maxChars).at(-1);if(n&&n>=Math.floor(t.maxChars/3))return n;let o=pZ(e.slice(0,t.maxChars),rbe).filter(s=>s>=Math.floor(t.maxChars/2)).at(-1);return o||nbe(e,t.maxChars)}function Dn(e,t){return e.followup?{...t,state:"chunk",is_finish:t.thought_chain?t.is_finish??1:0,message_tags:{source:"cron_running",uid:e.context.messageId}}:t}var ibe=24,obe=512,sbe=32,abe=480;function xc(e,t,r){e.finalized||!r||(e.pendingText+=r,cbe(e,t))}function yy(e,t){if(!e.pendingText||e.finalized){e.pendingText="";return}let r=Yl(e.pendingText);e.pendingText="",!(r.hold||!r.buffer)&&hZ(e,t,r.buffer)}function cbe(e,t){for(;!e.finalized;){let r=Yl(e.pendingText);if(e.pendingText=r.buffer,r.hold||!e.pendingText)return;let i=yI(e.pendingText,{minChars:ibe,maxChars:obe});if(i===0)return;hZ(e,t,e.pendingText.slice(0,i)),e.pendingText=e.pendingText.slice(i)}}function hZ(e,t,r){if(!r)return;if(e.followup){e.cronText+=r;return}let i=e.chunkIndex++;t.enqueue(e.context,{response:r,state:"chunk",chunk_idx:i},`chunk:${i}`)}function vy(e,t,r,i,n){if(!(e.finalized||!r))for(e.reasoningMessageKey&&e.reasoningMessageKey!==i&&us(e,t,"complete"),e.reasoningMessageKey=i,e.reasoningSort??=n,e.pendingReasoning+=r;!e.finalized;){let o=Yl(e.pendingReasoning);if(e.pendingReasoning=o.buffer,o.hold||!e.pendingReasoning)return;let s=yI(e.pendingReasoning,{minChars:sbe,maxChars:abe,keepLastComplete:!0});if(s===0)return;let a=e.pendingReasoning.slice(0,s);e.pendingReasoning=e.pendingReasoning.slice(s),mZ(e,t,a,!1,"start_stream")}}function us(e,t,r){e.reasoningMessageKey&&(ube(e,t,!0,r),e.reasoningMessageKey=void 0,e.reasoningSort=void 0,e.reasoningStarted=!1)}function ube(e,t,r,i){let n=Yl(e.pendingReasoning),o=n.hold?"":n.buffer;e.pendingReasoning="",!(e.finalized||!o&&(!r||!e.reasoningStarted))&&mZ(e,t,o,r,i)}function mZ(e,t,r,i,n){if(!r&&!i)return;r&&(e.reasoningStarted=!0);let o=e.reasoningLineIndex++,s=e.reasoningMessageKey??`reasoning:${e.turn??0}:0`,a=(e.reasoningSort??Date.now()/1e3)+o/1e9;t.enqueue(e.context,Dn(e,ZV({context:e.context,content:r,sort:a,finished:i,status:n,messageKey:s})),`thought:${o}`)}function vI(e,t,r){for(let[i,n]of e.toolCalls){if(n.settled)continue;n.settled=!0;let o=r==="cancelled";t.enqueue(e.context,Dn(e,Ur({context:e.context,title:n.name,name:Xl[n.name]?.name||"\u5DE5\u5177\u6267\u884C",toolCallId:i,content:o?"\u5DE5\u5177\u6267\u884C\u5DF2\u4E2D\u65AD":"\u5DE5\u5177\u6267\u884C\u672A\u8FD4\u56DE\u7ED3\u679C",sort:n.sort,finished:!0,status:o?"cancel":"fail",isError:!0})),`tool:${i}:result`)}}function gZ(e){e.pendingText="",e.stepText.clear(),e.pendingReasoning="",e.stepReasoning.clear(),e.reasoningMessageKey=void 0,e.reasoningSort=void 0,e.reasoningStarted=!1,e.toolCalls.clear(),delete e.turn}function bI(e,t){for(let r of e)if(!r.finalized&&r.pendingSubagents.has(t))return r}function yZ(e,t,r,i){let n=oy(i);if(n)return e.find(o=>o.dshSessionId===r&&o.pendingSubagents.has(n))??t??bI(e,r)}function vZ(e,t,r,i,n,o){if(o(e),oy(t)){wI(e,t,r,i,n,o);return}t.type==="tool/result"&&_I(e,t.data.message.content[0].content,r,i,n,o)}function _I(e,t,r,i,n,o){let s=CV(t);s&&(e.settledSubagents.delete(s)||(e.pendingSubagents.add(s),e.subagentParents.set(s,r),e.followup||(i.trackSubagent(e.context.requestId,r,s),i.markRequestToolWaiting(e.context.requestId)),bZ(e,n,s,Date.now()/1e3),o(e)))}function wI(e,t,r,i,n,o){let s=oy(t);if(!s)return;e.pendingSubagents.delete(s)||(e.settledSubagents.add(s),bZ(e,n,s,Qi(t))),e.subagentParents.delete(s);let a=ye(ye(t.data)?.source),c=typeof a?.summary=="string"?a.summary.trim():"completed",u=c.toLowerCase(),l=/(aborted|cancelled|canceled|interrupted)/.test(u)?"cancel":/(failed|failure|error)/.test(u)?"fail":"complete";e.followup||(i.trackSubagent(e.context.requestId,r,s),i.settleSubagent(s,l==="complete"?"completed":l==="cancel"?"cancelled":"failed")),n.enqueue(e.context,Dn(e,Ur({context:e.context,title:"subagent",name:"\u5B50 Agent",toolCallId:s,content:`\u5B50 Agent ${s} \u5DF2\u7ED3\u675F\uFF1A${c}`,sort:Qi(t),finished:!0,status:l,isError:l==="fail"})),`subagent:${s}:result`),SI(e,i),o(e)}function bZ(e,t,r,i){t.enqueue(e.context,Dn(e,Ur({context:e.context,title:"subagent",name:"\u5B50 Agent",toolCallId:r,content:`\u5B50 Agent ${r} \u5DF2\u542F\u52A8`,sort:i,finished:!1,status:"start_stream",isError:!1})),`subagent:${r}:start`)}function xI(e,t,r,i){let n=i==="cancelled";for(let o of e.pendingSubagents)e.followup||t.settleSubagent(o,n?"cancelled":"failed"),r.enqueue(e.context,Dn(e,Ur({context:e.context,title:"subagent",name:"\u5B50 Agent",toolCallId:o,content:n?"\u5B50 Agent \u6267\u884C\u5DF2\u4E2D\u65AD":"\u5B50 Agent \u672A\u8FD4\u56DE\u5B8C\u6574\u7ED3\u679C",sort:Date.now()/1e3,finished:!0,status:n?"cancel":"fail",isError:!0})),`subagent:${o}:result`);e.pendingSubagents.clear(),e.subagentParents.clear(),e.settledSubagents.clear()}function SI(e,t){e.followup||e.pendingSubagents.size>0||[...e.toolCalls.values()].some(r=>!r.settled)||t.markRequestRunningAfterTool(e.context.requestId)}function _Z(e,t,r){if(r.type==="user/message"){if(ay(r)){let c=e.hasLiveRun(t),u=gy(e,t,r,!c);c&&u&&e.queuePendingTurn(t,{kind:"resume",active:u});return}let a=yZ(e.liveRuns(),e.liveRun(t),t,r);a&&(wI(a,r,t,e.store,e.dcg,c=>e.armTurnTimeout(c)),a.dshSessionId===t&&e.queuePendingTurn(t,{kind:"resume",active:a}));return}let i=bI(e.liveRuns(),t);if(i){vZ(i,r,t,e.store,e.dcg,a=>e.armTurnTimeout(a));return}let n=ye(r.data),o=typeof n?.turn=="number"?n.turn:void 0,s=o===void 0?e.liveRun(t):e.turnOwner(t,o);if(r.type==="turn/start"){if(o===void 0||(s=e.ownerForTurnStart(t,o),!s))return;e.armTurnTimeout(s);return}if(s??=e.liveRun(t),!!s&&!(o!==void 0&&s.turn!==void 0&&o!==s.turn)){if(e.armTurnTimeout(s),r.type==="assistant/chunk"){lbe(s,r,e.dcg);return}if(r.type==="assistant/message"){fbe(s,r,e.dcg);return}if(r.type==="tool/call"){dbe(s,r,e.store,e.dcg);return}if(r.type==="tool/result"){pbe(s,r,t,e.store,e.dcg,a=>e.armTurnTimeout(a));return}r.type==="turn/end"&&hbe(e,s,o,n?.reason)}}function lbe(e,t,r){let i=ye(t.data),n=ye(i?.chunk),o=typeof i?.step=="number"?i.step:0,s=`${i?.turn??e.turn??0}:${o}`;n?.type==="text-delta"&&typeof n.text=="string"?(e.stepText.set(s,(e.stepText.get(s)??"")+n.text),xc(e,r,n.text)):n?.type==="reasoning-delta"&&typeof n.text=="string"&&(e.stepReasoning.set(s,(e.stepReasoning.get(s)??"")+n.text),vy(e,r,n.text,`reasoning:${s}`,Qi(t)))}function fbe(e,t,r){let i=ye(t.data),n=ye(i?.message),o=iy(n?.content,"text"),s=iy(n?.content,"reasoning"),a=typeof i?.step=="number"?i.step:0,c=`${i?.turn??e.turn??0}:${a}`,u=e.stepText.get(c)??"";!u&&o?xc(e,r,o):o.startsWith(u)&&o.length>u.length&&xc(e,r,o.slice(u.length));let l=e.stepReasoning.get(c)??"",d=`reasoning:${c}`,p=Qi(t);!l&&s?vy(e,r,s,d,p):s.startsWith(l)&&s.length>l.length&&vy(e,r,s.slice(l.length),d,p),yy(e,r),e.reasoningMessageKey===d&&us(e,r,"complete")}function dbe(e,t,r,i){us(e,i,"complete");let n=String(t.data.callId);if(e.toolCalls.has(n))return;let o=Qi(t);e.toolCalls.set(n,{name:t.data.name,sort:o,settled:!1}),e.followup||r.markRequestToolWaiting(e.context.requestId),i.enqueue(e.context,Dn(e,Ur({context:e.context,title:t.data.name,name:Xl[t.data.name]?.name||"\u5DE5\u5177\u6267\u884C",toolCallId:n,content:oI(t.data.arguments,"\u6B63\u5728\u6267\u884C"),sort:o,finished:!1,status:"start_stream",isError:!1})),`tool:${n}:start`)}function pbe(e,t,r,i,n,o){let s=String(t.data.message.source.callId),a=e.toolCalls.get(s);if(a?.settled)return;let c=t.data.message.content[0];_I(e,c.content,r,i,n,o);let u=t.data.error?.code==="interrupted",l=c.isError===!0||t.data.error!==void 0,d=a?.name||"\u5DE5\u5177\u6267\u884C",p=a?.sort??Qi(t);e.toolCalls.set(s,{name:d,sort:p,settled:!0}),SI(e,i),n.enqueue(e.context,Dn(e,Ur({context:e.context,title:d,name:Xl[d]?.name||"\u5DE5\u5177\u6267\u884C",toolCallId:s,content:oI(sI(c.content),l?"\u6267\u884C\u5931\u8D25":"\u6267\u884C\u5B8C\u6210"),sort:p,finished:!0,status:u?"cancel":l?"fail":"complete",isError:l})),`tool:${s}:result`)}function hbe(e,t,r,i){let n=AV(i);if(r!==void 0&&e.releaseTurnOwner(t.dshSessionId,r),n.status==="succeeded"&&t.pendingSubagents.size>0){e.logger.info("keeping MBHChat message open for background subagents",{dshSessionId:t.dshSessionId,requestId:t.context.requestId,pendingSubagents:[...t.pendingSubagents]}),e.armTurnTimeout(t);return}if(n.status!=="succeeded"&&t.pendingSubagents.size>0){e.finishAfterCascade(t,n.tag,n.status,n.response??"");return}e.finish(t,n.tag,n.status,n.response)}var by=class{config;store;getDcg;logger;activeBySession;pendingCronMessageIds;cancelExecution;resolveCronBusinessKey;quarantineUnconfirmedExecution;runsBySession=new Map;turnOwners=new Map;pendingTurns=new Map;terminatingRuns=new WeakSet;constructor(t,r,i,n,o,s,a,c,u){this.config=t,this.store=r,this.getDcg=i,this.logger=n,this.activeBySession=o,this.pendingCronMessageIds=s,this.cancelExecution=a,this.resolveCronBusinessKey=c,this.quarantineUnconfirmedExecution=u}get dcg(){return this.getDcg()}liveRun(t){let r=this.activeBySession.get(t);if(!(!r||r.finalized))return this.trackRun(r),r}liveRuns(){let t=new Set;for(let r of this.activeBySession.values())r.finalized||t.add(r);for(let r of this.runsBySession.values())for(let i of r)i.finalized||t.add(i);return[...t]}handleSessionEvent(t,r){_Z(this,t,r)}queueText(t,r){xc(t,this.dcg,r)}detachForSessionRetry(t,r){t.finalized||t.dshSessionId!==r||(clearTimeout(t.timeout),vI(t,this.dcg,"cancelled"),xI(t,this.store,this.dcg,"cancelled"),us(t,this.dcg,"cancel"),gZ(t),this.forgetRun(t,r,{keepReplacement:!1}))}attachAfterSessionRetry(t,r){t.finalized||(t.dshSessionId=r,this.activeBySession.set(r,t),this.armTurnTimeout(t))}finish(t,r,i,n=""){if(!t.finalized){clearTimeout(t.timeout);try{vI(t,this.dcg,i),xI(t,this.store,this.dcg,i),us(t,this.dcg,VV(i)),yy(t,this.dcg);let o={response:t.followup?"":n,state:"final",final_tag:r,is_finish:1,message_tags:{isFinal:1},...t.context.model?{model:t.context.model}:{}};if(t.followup){let s=t.cronText&&n?`${t.cronText}
|
|
596
596
|
${n}`:t.cronText||n;(s||t.cronAttachments.length>0)&&this.dcg.enqueue(t.context,{response:s,message_tags:{source:"cron_running",uid:t.context.messageId,...t.cronAttachments.length>0?{mark:"empty_text_file"}:{}},state:"chunk",is_finish:0,...t.cronAttachments.length>0?{files:t.cronAttachments}:{}},"cron:content"),this.dcg.enqueue(t.context,{...o,message_tags:{source:"cron_running",uid:t.context.messageId,isFinal:1}},"final")}else this.dcg.enqueueTerminal(t.context,o,"final",i,r)}catch(o){this.logger.error("could not persist terminal request and delivery",{requestId:t.context.requestId,tag:r,error:ne(o)})}finally{t.finalized=!0,this.forgetRun(t,t.dshSessionId,{keepReplacement:!0}),t.resolveCompletion()}}}sendImmediateFinal(t,r,i,n){try{this.dcg.enqueueTerminal(t,{response:n,state:"final",final_tag:r,is_finish:1,message_tags:{isFinal:1}},"final",i,r)}catch(o){this.logger.error("could not persist immediate terminal request and delivery",{requestId:t.requestId,tag:r,error:ne(o)})}}async onTurnTimeout(t){if(t.finalized)return;let r=Date.now()>=t.deadlineAt,i=r?"task_timeout":"timeout",n=r?"[\u9519\u8BEF] \u4EFB\u52A1\u5DF2\u8D85\u8FC7\u6267\u884C\u65F6\u9650\uFF0C\u5DF2\u8BF7\u6C42\u505C\u6B62":"[\u9519\u8BEF] mbh-chat \u672C\u8F6E\u957F\u65F6\u95F4\u65E0\u6D3B\u52A8\uFF0C\u5DF2\u8BF7\u6C42\u505C\u6B62";this.logger.error(r?"mbh-chat task timed out":"mbh-chat turn timed out",{dshSessionId:t.dshSessionId,requestId:t.context.requestId});try{await this.cancelExecution(t),t.finalized||this.finish(t,i,"failed",n)}catch(o){this.quarantineUnconfirmedExecution?.(t,"timeout_cancel_unconfirmed"),this.logger.error("mbh-chat timeout cancel failed",{dshSessionId:t.dshSessionId,error:ne(o)}),t.finalized||this.finish(t,"timeout_cancel_unconfirmed","failed","[\u9519\u8BEF] mbh-chat \u672C\u8F6E\u957F\u65F6\u95F4\u65E0\u6D3B\u52A8\uFF0C\u4F46\u672A\u80FD\u786E\u8BA4\u505C\u6B62\uFF0C\u8BF7\u68C0\u67E5 Agent Host \u72B6\u6001")}}pauseForUserInput(t){t.finalized||(clearTimeout(t.timeout),t.timeout=setTimeout(()=>{this.onTurnTimeout(t)},Math.max(1,t.deadlineAt-Date.now())))}resumeAfterUserInput(t){this.armTurnTimeout(t)}async finishAfterCascade(t,r,i,n){if(!(t.finalized||this.terminatingRuns.has(t))){this.terminatingRuns.add(t),clearTimeout(t.timeout);try{await this.cancelExecution(t),this.finish(t,r,i,n)}catch(o){this.quarantineUnconfirmedExecution?.(t,`${r}_cancel_unconfirmed`),this.logger.error("mbh-chat terminal cascade cancellation failed",{dshSessionId:t.dshSessionId,requestId:t.context.requestId,error:ne(o)}),this.finish(t,`${r}_cancel_unconfirmed`,"failed",n||"[\u9519\u8BEF] \u4EFB\u52A1\u5DF2\u7EC8\u6B62\uFF0C\u4F46\u672A\u80FD\u786E\u8BA4\u6A21\u578B\u3001\u5DE5\u5177\u4E0E\u5B50 Agent \u5747\u5DF2\u505C\u6B62")}}}trackRun(t){let r=this.runsBySession.get(t.dshSessionId);r||(r=new Set,this.runsBySession.set(t.dshSessionId,r)),r.add(t)}hasLiveRun(t){return this.liveRuns().some(r=>r.dshSessionId===t)}queuePendingTurn(t,r){let i=this.pendingTurns.get(t)??[];i.push(r),this.pendingTurns.set(t,i)}ownerForTurnStart(t,r){let i=this.turnOwners.get(t)?.get(r);if(i&&!i.finalized)return i;let n=this.liveRun(t);if(n&&n.turn===void 0)n.turn=r;else{let s=this.pendingTurns.get(t),a=s?.shift();s?.length===0&&this.pendingTurns.delete(t),a?.kind==="resume"?n=a.active.finalized?void 0:a.active:a?.kind==="cron"?n=gy(this,t,a.event,!1):(!n||n.finalized)&&(n=void 0),n&&(n.turn=r)}if(!n)return;this.trackRun(n);let o=this.turnOwners.get(t);return o||(o=new Map,this.turnOwners.set(t,o)),o.set(r,n),this.activeBySession.set(t,n),n}turnOwner(t,r){return this.turnOwners.get(t)?.get(r)}releaseTurnOwner(t,r){this.turnOwners.get(t)?.delete(r)}armTurnTimeout(t){if(t.finalized)return;clearTimeout(t.timeout);let r=Math.max(1,Math.min(this.config.turnTimeoutMs,t.deadlineAt-Date.now()));t.timeout=setTimeout(()=>{this.onTurnTimeout(t)},r)}forgetRun(t,r,i){let n=this.runsBySession.get(r);n?.delete(t),n?.size===0&&this.runsBySession.delete(r);let o=this.pendingTurns.get(r);if(o){let a=o.filter(c=>c.kind!=="resume"||c.active!==t);a.length>0?this.pendingTurns.set(r,a):this.pendingTurns.delete(r)}let s=this.turnOwners.get(r);if(s){for(let[a,c]of s)c===t&&s.delete(a);s.size===0&&this.turnOwners.delete(r)}if(this.activeBySession.get(r)===t){if(i.keepReplacement){let a=n?[...n].find(c=>!c.finalized):void 0;a?this.activeBySession.set(r,a):this.activeBySession.delete(r);return}this.activeBySession.delete(r)}}};function wZ(e){let t=ne(e).toLowerCase();return/(429|rate.?limit|too many requests|overload|busy)/.test(t)?"throttled":/(timeout|timed out|temporar|unavailable|econn|enet|eai_again|socket|network|fetch failed|connection|host.*ready)/.test(t)?"transient":"permanent"}function xZ(e,t,r){if(t==="permanent")return 0;let i=t==="throttled"?4:1;return Math.min(r.maxDelayMs,r.baseDelayMs*i*2**Math.max(0,e-1))}function SZ(e,t){if(!e.started)return;let r=Date.now(),i=Math.min(t.nextRetryAt??r,t.deadlineAt??Number.MAX_SAFE_INTEGER),n=Math.max(0,i-r),o=e.retryTimers.get(t.requestId);if(o&&clearTimeout(o),n>0){let s=setTimeout(()=>{e.retryTimers.delete(t.requestId),e.enqueueWaitingRequest(t)},n);s.unref(),e.retryTimers.set(t.requestId,s);return}e.enqueueWaitingRequest(t)}function EZ(e,t){e.queue.enqueue(t.context.businessKey,()=>e.executeWaitingRequest(t.requestId)).catch(r=>{e.logger.error("task queue orchestration failed",{requestId:t.requestId,error:ne(r)})})}async function kZ(e,t){if(!e.started)return;let r=e.store.getWaitingRequest(t);if(!r)return;let i=Date.now();if(r.deadlineAt!==void 0&&r.deadlineAt<=i){e.turns.sendImmediateFinal(r.context,"task_timeout","failed","[\u9519\u8BEF] \u4EFB\u52A1\u5DF2\u8D85\u8FC7\u6267\u884C\u65F6\u9650");return}if(r.attemptCount>=e.config.task.maxAttempts){e.turns.sendImmediateFinal(r.context,"retry_exhausted","failed","[\u9519\u8BEF] \u4EFB\u52A1\u91CD\u8BD5\u6B21\u6570\u5DF2\u8017\u5C3D");return}let n=e.store.beginRequestAttempt(t);if(n!==void 0)try{await e.runPrompt(r.message,r.context,r.deadlineAt)}catch(o){if(!e.started)return;let s=e.store.getWaitingRequest(t);if(!s)return;let a=wZ(o),c=xZ(n,a,{baseDelayMs:e.config.task.retryBaseMs,maxDelayMs:e.config.task.retryMaxMs}),u=Date.now()+c;if(a!=="permanent"&&n<e.config.task.maxAttempts&&(s.deadlineAt===void 0||u<s.deadlineAt)&&e.store.scheduleRequestRetry(t,ne(o),u)){e.logger.warn("scheduled task retry",{requestId:t,attempt:n,failureClass:a,delayMs:c}),e.scheduleWaitingRequest({...s,attemptCount:n,nextRetryAt:u});return}let d=a==="permanent"?"task_error":"retry_exhausted";e.logger.error("mbh-chat task failed after retry handling",{requestId:t,attempt:n,failureClass:a,error:ne(o)}),e.turns.sendImmediateFinal(r.context,d,"failed",bc(o))}}var _y=class{config;logger;store;dsh;dcg;requestApi;ossUpload;messageControl;skillManager;agentManager;inboundPrompt;intentFeedback;sessions;turns;bridgeStatus=new sh;cronSync;queue=new Yg;activeBySession=new Map;corruptSessionRecoveries=new Map;pendingCronMessageIds=new Map;pendingUserQuestions=new Map;sessionsToCancelOnReconnect=new Set;stopRequestedSessions=new Set;handledCorruptSessions=new Set;invalidToolHistorySessions=new Set;cancelQuarantinedChain=Promise.resolve();quarantinedRetryTimer;retryTimers=new Map;runAbort;started=!1;constructor(t){this.config=t,this.logger=new Us(t.logLevel),this.store=new uh(t.stateDb,t.task.timeoutMs),this.dsh=new ny(t.dsh.baseUrl,t.dsh.reconnectMinMs,t.dsh.reconnectMaxMs,this.logger),this.requestApi=new Dh(t.api,this.logger),this.skillManager=new ey(this.logger,{allowPrivateNetwork:t.media.allowPrivateNetwork}),this.agentManager=new oh(this.logger,{storageRoot:t.agent.storageRoot,allowPrivateNetwork:t.media.allowPrivateNetwork,resolveDownloadUrl:(r,i)=>this.requestApi.getMyExpertDownloadUrl(r,i.botToken,i)}),this.dcg=new Th(t.account,this.store,this.logger,r=>this.handleInbound(r),r=>this.handleSkillEvent(r),r=>this.bridgeStatus.setDcgState(r),r=>this.handleInboundEvent(r)),this.ossUpload=bV(this.requestApi,this.logger),this.turns=new by({turnTimeoutMs:t.turnTimeoutMs,taskTimeoutMs:t.task.timeoutMs,botToken:t.account.botToken},this.store,()=>this.dcg,this.logger,this.activeBySession,this.pendingCronMessageIds,r=>this.cancelActiveExecution(r),r=>this.cronSync?.businessKeyForCronId(r),(r,i)=>this.quarantineUnconfirmedExecution(r.businessKey,r.dshSessionId,i)),this.inboundPrompt=new hy(t,this.agentManager,this.skillManager,this.requestApi,()=>this.dcg,this.logger),this.intentFeedback=new dy((r,i,n)=>{this.dcg.enqueue(r,i,n)}),this.sessions=new cy(t,this.store,()=>this.dsh,this.logger,()=>this.cronSync,this.activeBySession,(r,i,n,o)=>this.turns.finish(r,i,n,o),r=>this.cancelActiveExecution(r),(r,i,n,o)=>this.quarantineUnconfirmedExecution(r,i,n,o)),this.messageControl=t.messageControl?new $h(t.messageControl.socketPath,t.messageControl.token,(r,i)=>this.handleMbhchatMessage(r,i),()=>this.bridgeStatus.snapshot()):void 0}async start(){if(this.started)throw new Error("bridge already started");this.started=!0,this.runAbort=new AbortController,this.bridgeStatus.start(),await this.messageControl?.start();for(let n of this.store.listQuarantinedSessions())this.sessionsToCancelOnReconnect.add(n);this.dsh.start({onRemoteEvent:n=>this.handleRemoteEvent(n),onSessionEvent:(n,o)=>this.handleSessionEvent(n,o),onConnection:async n=>{this.bridgeStatus.setDshConnected(n);try{await this.handleDshConnectionChange(n)}catch(o){this.logger.error("mbh-chat connection transition handling failed",{connected:n,error:ne(o)})}}}),await this.dsh.whenConnected(this.connectionWaitSignal());let t=this.store.listWaitingRequests(),r=this.store.listActiveRequests(),i=this.store.pruneDeliveredDeliveries(this.config.outboxRetentionMs===0?0:Date.now()-this.config.outboxRetentionMs,this.config.outboxMaxDelivered);this.config.outboxRetentionMs>0&&this.store.pruneManagementEvents(Date.now()-this.config.outboxRetentionMs),i>0&&this.logger.info("pruned delivered Outbox history",{count:i}),await this.recoverActiveRequests(r,{waitForCancel:!1}),this.cronSync=new Oh({dshBaseUrl:this.config.dsh.baseUrl,store:this.store,dcg:this.dcg,logger:this.logger,followSession:n=>this.dsh.followSession(n),provisionSession:n=>this.provisionMigratedCronSession(n)}),this.dcg.start(),this.cronSync.start(),this.cronSync.bindAllKnownDshSessions().catch(n=>{this.logger.warn("failed to bind cron jobs to pre-existing mbh-chat sessions",{error:ne(n)})});for(let n of t)n.context.requestId=n.requestId,this.scheduleWaitingRequest(n);t.length>0&&this.logger.warn("recovered waiting requests",{count:t.length}),this.logger.info("mbh-chat bridge started",{stateDb:this.config.stateDb})}async provisionMigratedCronSession(t){let r=t.sessionKey;if(!r)return;let i=zi(r);if(!i.agentId||!i.sessionId)return;let o=this.store.getLatestContextForBusinessKey(r)??{accountId:this.config.account.accountId,requestId:`cron-provision:${t.id}`,businessKey:r,userId:Number(this.config.account.userId)||0,sessionId:i.sessionId,messageId:this.pendingCronMessageIds.get(t.id)??String(Date.now()),domainId:this.config.account.domainId,appId:this.config.account.appId,agentId:i.agentId},s=await this.sessions.ensureSession(r,void 0,{...this.config.dsh.workspaceCwd?{workspaceDir:this.config.dsh.workspaceCwd}:{},agentPreset:this.config.dsh.agentPreset,managed:!1},o);return this.logger.info("provisioned DSH session for migrated cron",{cronId:t.id,businessKey:r,dshSessionId:s}),s}async stop(){if(!this.started)return;this.started=!1;let t=[],r=async(n,o)=>{try{await o()}catch(s){t.push({step:n,error:s}),this.logger.warn("Bridge shutdown step failed",{step:n,error:ne(s)})}};await r("cancel queued requests",()=>this.queue.cancelAllPending()),await r("clear retry timers",()=>{for(let n of this.retryTimers.values())clearTimeout(n);this.retryTimers.clear(),this.quarantinedRetryTimer&&clearTimeout(this.quarantinedRetryTimer),this.quarantinedRetryTimer=void 0}),await r("abort runtime waits",()=>this.runAbort?.abort(new Error("Bridge is stopping"))),await r("stop status tracker",()=>this.bridgeStatus.stop()),await r("cancel pending user questions",()=>this.cancelPendingUserQuestions());let i=[];await r("collect active runs",()=>{i=[...new Set([...this.turns.liveRuns(),...[...this.corruptSessionRecoveries.values()].map(n=>n.active)])]}),await r("cancel active runs",async()=>{await Promise.allSettled(i.map(async n=>{try{await this.cancelActiveExecution(n)}catch(o){t.push({step:`cancel active run ${n.dshSessionId}`,error:o}),this.quarantineUnconfirmedExecution(n.businessKey,n.dshSessionId,"bridge_shutdown_cancel_unconfirmed"),this.logger.warn("mbh-chat cancel during shutdown failed",{dshSessionId:n.dshSessionId,error:ne(o)})}}))}),await r("finish active runs",()=>{for(let n of i)try{this.turns.finish(n,"bridge_shutdown","cancelled","[\u9519\u8BEF] Bridge \u6B63\u5728\u505C\u6B62\uFF0C\u672C\u8F6E\u5DF2\u53D6\u6D88")}catch(o){t.push({step:`finish active run ${n.dshSessionId}`,error:o}),this.logger.warn("Bridge shutdown step failed",{step:`finish active run ${n.dshSessionId}`,error:ne(o)})}this.corruptSessionRecoveries.clear()}),await r("stop cron synchronization",()=>this.cronSync?.stop()),await r("flush outbound queue",()=>this.dcg.flush()),await r("stop outbound socket",()=>this.dcg.stop()),await r("stop DSH connection",()=>this.dsh.stop()),await r("stop message control",()=>this.messageControl?.stop()),await r("finish quarantined cancellation queue",()=>this.cancelQuarantinedChain),await r("clear runtime state",()=>{this.pendingCronMessageIds.clear(),this.sessionsToCancelOnReconnect.clear(),this.stopRequestedSessions.clear(),this.handledCorruptSessions.clear(),this.invalidToolHistorySessions.clear()}),await r("close state store",()=>this.store.close()),this.runAbort=void 0,t.length>0?this.logger.error("mbh-chat bridge stopped with cleanup failures",{failures:t.map(({step:n,error:o})=>({step:n,error:ne(o)}))}):this.logger.info("mbh-chat bridge stopped")}async recoverActiveRequests(t,r){for(let n of t)n.dshSessionId&&(this.store.quarantineSession(n.context.businessKey,n.dshSessionId,"bridge_restarted"),this.sessionsToCancelOnReconnect.add(n.dshSessionId));let i=this.cancelQuarantinedSessions();r?.waitForCancel===!1?i.catch(n=>{this.logger.warn("could not cancel mbh-chat session left behind by stream loss",{error:ne(n)})}):await i;for(let n of t)this.dcg.enqueueTerminal(n.context,{response:"[\u9519\u8BEF] Bridge \u4E0A\u6B21\u8FD0\u884C\u5F02\u5E38\u4E2D\u65AD\u4E86\u8BE5\u8BF7\u6C42\uFF0C\u8BF7\u91CD\u8BD5",state:"final",final_tag:"bridge_restarted",is_finish:1},"final","failed","bridge_restarted");t.length>0&&this.logger.warn("terminated unsafe recovered tasks",{count:t.length})}async handleDshConnectionChange(t){if(this.started){if(!t){this.sessions.clearHostDefaultProvider();for(let r of this.turns.liveRuns())this.cancelPendingUserQuestions(r.dshSessionId),this.sessionsToCancelOnReconnect.add(r.dshSessionId),this.store.quarantineSession(r.businessKey,r.dshSessionId,"dsh_stream_lost"),this.turns.finish(r,"dsh_stream_lost","failed","[\u9519\u8BEF] mbh-chat \u4E8B\u4EF6\u6D41\u5DF2\u65AD\u5F00\uFF0C\u672C\u8F6E\u72B6\u6001\u65E0\u6CD5\u5B89\u5168\u7EED\u63A5\uFF1B\u4F1A\u8BDD\u5DF2\u9694\u79BB\uFF0C\u8BF7\u91CD\u8BD5");return}this.cancelQuarantinedSessions().catch(r=>{this.logger.warn("could not cancel mbh-chat session left behind by stream loss",{error:ne(r)})})}}cancelQuarantinedSessions(){let t=this.cancelQuarantinedChain.then(()=>this.runCancelQuarantinedSessions());return this.cancelQuarantinedChain=t.then(()=>{},()=>{}),t}async runCancelQuarantinedSessions(){for(let t of[...this.sessionsToCancelOnReconnect])try{let r=await this.cancelExecutionTree(t);if(this.sessionsToCancelOnReconnect.delete(t),r==="absent"){this.store.removeQuarantinedSession(t),this.logger.info("dropped quarantined mbh-chat session that is no longer attached",{dshSessionId:t});continue}let i=this.store.resolveQuarantinedSession(t);this.logger.info("cancelled quarantined mbh-chat session",{dshSessionId:t,resolution:i})}catch(r){this.logger.warn("could not cancel mbh-chat session left behind by stream loss",{dshSessionId:t,error:ne(r)})}this.sessionsToCancelOnReconnect.size>0&&this.scheduleQuarantinedCancellationRetry()}quarantineUnconfirmedExecution(t,r,i,n=!0){this.sessionsToCancelOnReconnect.add(r);try{this.store.quarantineSession(t,r,i,n)}catch(o){this.logger.error("could not persist quarantined mbh-chat session",{businessKey:t,dshSessionId:r,reason:i,error:ne(o)})}this.scheduleQuarantinedCancellationRetry()}scheduleQuarantinedCancellationRetry(){if(!this.started||this.quarantinedRetryTimer||this.sessionsToCancelOnReconnect.size===0)return;let t=Math.max(1e3,this.config.task.retryMaxMs);this.quarantinedRetryTimer=setTimeout(()=>{this.quarantinedRetryTimer=void 0,this.cancelQuarantinedSessions().catch(r=>{this.logger.warn("background quarantined-session cancellation failed",{error:ne(r)}),this.scheduleQuarantinedCancellationRetry()})},t),this.quarantinedRetryTimer.unref()}async handleInbound(t){let r=Yn(this.config.account.accountId,t.content.message_id.trim()),i=ah(t,this.config.account.accountId,r),n=this.store.claimInbound(t,i);if(n.kind==="duplicate"){this.logger.info("duplicate inbound suppressed",{messageId:t.content.message_id,requestId:n.requestId,status:n.status}),this.dcg.flush().catch(a=>{this.logger.error("duplicate-triggered Outbox flush failed",{error:ne(a)})});return}if(n.kind==="conflict"){this.logger.error("inbound idempotency conflict",{messageId:t.content.message_id,requestId:n.requestId});return}if(i.requestId=n.requestId,this.logger.info("accepted inbound chat",{messageId:t.content.message_id,sessionId:i.sessionId,businessKey:i.businessKey}),this.cronSync?.notifySessionAvailable(),t.content.text.trim()==="/stop"){await this.handleStop(i);return}this.intentFeedback.messageReceived(i,t.content.text);let s=this.store.getWaitingRequest(i.requestId);if(!s)throw new Error(`claimed task ${i.requestId} is not in waiting state`);this.scheduleWaitingRequest({...s,message:t,context:i})}scheduleWaitingRequest(t){SZ(this,t)}enqueueWaitingRequest(t){EZ(this,t)}async executeWaitingRequest(t){await kZ(this,t)}async handleSkillEvent(t){await this.claimManagementEvent(t.content)&&await QV(this,t)}async handleInboundEvent(t){(t.eventType==="agent"||t.eventType==="cron")&&!await this.claimManagementEvent(t.content)||await eZ(this,t)}async claimManagementEvent(t){let r=typeof t.websocket_trace_id=="string"?t.websocket_trace_id.trim():"";if(!r)return!0;try{let i=this.store.claimManagementEvent(r,t);return i==="claimed"?!0:i==="duplicate"?(this.logger.info("duplicate management event suppressed",{traceId:r}),this.dcg.flush().catch(n=>{this.logger.warn("duplicate management event Outbox flush failed",{error:ne(n)})}),!1):(await this.dcg.sendEvent({...t,status:"fail",error:"management event idempotency conflict"}),this.logger.error("management event idempotency conflict",{traceId:r}),!1)}catch(i){return await this.dcg.sendEvent({...t,status:"fail",error:ne(i)}),this.logger.error("management event could not be claimed",{traceId:r,error:ne(i)}),!1}}async handleStop(t){this.queue.cancelPending(t.businessKey);let r=this.store.listWaitingRequestsForBusinessKey(t.businessKey,t.requestId);for(let o of r){let s=this.retryTimers.get(o.requestId);s&&clearTimeout(s),this.retryTimers.delete(o.requestId),this.turns.sendImmediateFinal(o.context,"stop","cancelled","")}r.length>0&&this.logger.info("cancelled waiting mbh-chat tasks",{businessKey:t.businessKey,count:r.length});let i=this.store.getSession(t.businessKey);if(!i){this.turns.sendImmediateFinal(t,"stop","cancelled","");return}this.cancelPendingUserQuestions(i);let n=this.turns.liveRun(i);this.stopRequestedSessions.add(i);try{n?await this.cancelActiveExecution(n):await this.cancelExecutionTree(i),n&&!n.finalized&&this.turns.finish(n,"stop","cancelled",""),this.turns.sendImmediateFinal(t,"stop","cancelled",""),this.logger.info("cancelled active mbh-chat turn",{dshSessionId:i,businessKey:t.businessKey})}catch(o){this.stopRequestedSessions.delete(i),this.quarantineUnconfirmedExecution(t.businessKey,i,"stop_cancel_unconfirmed"),this.logger.warn("mbh-chat cancel failed",{dshSessionId:i,error:ne(o)}),n&&!n.finalized&&this.turns.finish(n,"stop_cancel_unconfirmed","failed","[\u9519\u8BEF] \u672A\u80FD\u786E\u8BA4\u6A21\u578B\u3001\u5DE5\u5177\u4E0E\u5B50 Agent \u5747\u5DF2\u505C\u6B62"),this.turns.sendImmediateFinal(t,"stop_cancel_unconfirmed","failed","[\u9519\u8BEF] \u672A\u80FD\u786E\u8BA4\u6A21\u578B\u3001\u5DE5\u5177\u4E0E\u5B50 Agent \u5747\u5DF2\u505C\u6B62")}}cancelPendingUserQuestions(t){MV(this,t)}async cancelActiveExecution(t){await this.cancelExecutionTree(t.dshSessionId,t.context.requestId,t.subagentParents)}async cancelExecutionTree(t,r,i){return OV(this,t,r,i)}async runPrompt(t,r,i){await fZ(this,t,r,i)}connectionWaitSignal(){let t=this.runAbort?.signal,r=AbortSignal.timeout(this.config.supervisor.startTimeoutMs);return t?AbortSignal.any([t,r]):r}handleMbhchatMessage(t,r){return oZ({request:t,signal:r,config:this.config,activeBySession:this.activeBySession,ossUpload:this.ossUpload,dcg:this.dcg,logger:this.logger})}prepareSelectedSkill(t){return this.inboundPrompt.prepareSelectedSkill(t)}promptContent(t,r,i,n){return this.inboundPrompt.promptContent(t,r,i,n)}ensureSession(t,r,i,n){return this.sessions.ensureSession(t,r,i,n)}async handleRemoteEvent(t){await zV(this,t)}handleSessionEvent(t,r){if(DV(r)&&!this.invalidToolHistorySessions.has(t)&&(this.invalidToolHistorySessions.add(t),this.logger.warn("detected mbh-chat session with invalid tool identity",{dshSessionId:t,eventType:r.type})),r.type!=="turn/end"){this.turns.handleSessionEvent(t,r);return}let i=RV(r);if(i&&Zl(i)){this.invalidToolHistorySessions.delete(t),hI(this,t,i);return}let n=this.invalidToolHistorySessions.delete(t);this.stopRequestedSessions.delete(t),this.turns.handleSessionEvent(t,r),n&&(this.store.removeSessionByDshId(t),this.unfollowSession(t),this.logger.warn("discarded mbh-chat session with invalid tool identity after turn end",{dshSessionId:t}))}onTurnTimeout(t){return this.turns.onTurnTimeout(t)}unfollowSession(t){this.dsh.unfollowSession?.(t)}};async function mbe(){let e=DC(),t=NC(`${e.stateDb}.lock`),r=new _y(e),i=!1,n=async o=>{if(!i){i=!0,console.log(`${new Date().toISOString()} INFO received ${o}, stopping bridge`);try{await r.stop()}finally{t.release()}}};process.once("SIGINT",()=>{n("SIGINT")}),process.once("SIGTERM",()=>{n("SIGTERM")});try{await r.start()}catch(o){try{await r.stop()}finally{t.release()}throw o}}mbe().catch(e=>{console.error(`${new Date().toISOString()} ERROR bridge startup failed: ${ne(e)}`),process.exitCode=1});
|