shennian 0.4.28 → 0.4.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/publish-build-manifest.json +38 -38
- package/dist/src/agent-env.d.ts +6 -0
- package/dist/src/agent-env.js +2 -2
- package/dist/src/agents/claude.js +5 -5
- package/dist/src/agents/codex-managed-permissions.js +1 -1
- package/dist/src/agents/codex.js +11 -11
- package/dist/src/agents/cursor.js +1 -1
- package/dist/src/agents/custom.d.ts +1 -1
- package/dist/src/agents/custom.js +2 -2
- package/dist/src/agents/model-registry/service.js +1 -1
- package/dist/src/agents/opencode.js +1 -1
- package/dist/src/agents/pi-coding-agent.d.ts +1 -1
- package/dist/src/agents/pi-coding-agent.js +4 -4
- package/dist/src/agents/workbuddy.js +2 -2
- package/dist/src/native-fusion/service.d.ts +7 -0
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/room/activation-service.d.ts +2 -0
- package/dist/src/room/activation-service.js +4 -4
- package/dist/src/room/managed-prompt-composer.d.ts +2 -0
- package/dist/src/room/managed-prompt-composer.js +20 -14
- package/dist/src/room/room-action-client.d.ts +4 -0
- package/dist/src/room/room-action-client.js +1 -1
- package/dist/src/security/managed-agent-policy.d.ts +3 -0
- package/dist/src/security/managed-agent-policy.js +1 -1
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/room-managed.js +1 -1
- package/dist/src/session/run-recovery/journal.d.ts +1 -1
- package/dist/src/session/run-recovery/journal.js +2 -2
- package/dist/src/session/run-recovery/schema.d.ts +3 -0
- package/dist/src/session/run-recovery/schema.js +1 -1
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts +12 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.js +33 -1
- package/node_modules/@shennian/wire/dist/session.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isAvailableAgentType as j,parseManagedAgentPermissionPolicy as _}from"@shennian/wire";import M from"node:path";class c extends Error{code;constructor(e,o){super(o),this.code=e,this.name="RoomActionHttpError"}}class O{fetchImpl;baseUrl;constructor(e,o=fetch){this.fetchImpl=o,this.baseUrl=e.replace(/\/+$/,"")}async createOperatorRoom(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/operator/create`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({name:e.name}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(o);if(!o.ok)throw l(o.status,t);return $(t,e,this.baseUrl)}async resolveNativeSession(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/resolve-session`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({runtimeAdapter:e.runtimeAdapter,sourceSessionKey:e.sourceSessionKey}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(o);if(!o.ok)throw l(o.status,t);(!t||typeof t!="object")&&r();const n=t;return(typeof n.nianSessionId!="string"||!/^[A-Za-z0-9_.:@/-]{1,512}$/.test(n.nianSessionId)||typeof n.created!="boolean")&&r(),n}async createRoom(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/create`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,name:e.name,agentAlias:e.agentAlias,agentDescription:e.agentDescription,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(o);if(!o.ok)throw l(o.status,t);return R(t,e,this.baseUrl)}async joinRoom(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/join`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,inviteToken:e.inviteToken,message:e.message,agentAlias:e.agentAlias,agentDescription:e.agentDescription,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(o);if(!o.ok)throw l(o.status,t);return P(t,e,this.baseUrl)}async status(e){const o=await this.request(e,"status");return T(o,e)}async getAttachmentCapability(e){const o=await this.request(e,`attachments/${encodeURIComponent(e.attachmentId)}/download-capability`);(!o||typeof o!="object")&&r();const t=o;return(t.attachmentId!==e.attachmentId||t.roomId!==e.roomId||typeof t.safeName!="string"||!I(t.safeName)||typeof t.mimeType!="string"||t.mimeType.length<1||t.mimeType.length>191||typeof t.byteSize!="string"||!d(t.byteSize)||typeof t.sha256!="string"||!/^[a-f0-9]{64}$/.test(t.sha256)||!v(t.downloadUrl)||typeof t.expiresAt!="string"||!Number.isFinite(Date.parse(t.expiresAt)))&&r(),t}async initializeAttachment(e){const o=await this.request(e,"attachments/init",{method:"POST",body:JSON.stringify({clientUploadId:e.clientUploadId,name:e.name,mediaKind:e.mediaKind,mimeType:e.mimeType,byteSize:e.byteSize,sha256:e.sha256})});(!o||typeof o!="object")&&r();const t=o,n=t.attachment,s=t.upload;return(!n||typeof n.id!="string"||n.roomId!==e.roomId||typeof n.name!="string"||!I(n.name)||n.mimeType!==e.mimeType||n.byteSize!==String(e.byteSize)||n.sha256!==e.sha256||n.status!=="pending"&&n.status!=="uploaded"||!s||s.method!=="PUT"||!v(s.url)||!s.headers||typeof s.headers!="object"||s.headers["content-type"]!==e.mimeType||s.headers["x-oss-meta-sha256"]!==e.sha256||typeof s.expiresAt!="string"||!Number.isFinite(Date.parse(s.expiresAt))||Date.parse(s.expiresAt)<=Date.now()||typeof t.idempotent!="boolean")&&r(),t}async completeAttachment(e){const o=await this.request(e,`attachments/${encodeURIComponent(e.attachmentId)}/complete`,{method:"POST"});(!o||typeof o!="object")&&r();const t=o;typeof t.idempotent!="boolean"&&r();const n=t.attachment;return(!n||n.attachmentId!==e.attachmentId||n.mediaKind!=="image"&&n.mediaKind!=="audio"&&n.mediaKind!=="file"||typeof n.name!="string"||typeof n.mimeType!="string"||typeof n.byteSize!="string"||!d(n.byteSize)||typeof n.sha256!="string"||!/^[a-f0-9]{64}$/.test(n.sha256)||n.status!=="ready")&&r(),{attachment:n,idempotent:t.idempotent}}async read(e){if(e.beforeSequence&&e.afterSequence)throw new c("ambiguous_sequence_cursor","beforeSequence and afterSequence are mutually exclusive.");const o=new URLSearchParams({limit:String(e.limit)});e.beforeSequence&&o.set("before",e.beforeSequence),e.afterSequence&&o.set("after",e.afterSequence);const t=await this.request(e,`messages?${o}`);(!t||typeof t!="object")&&r();const n=t;return(!Array.isArray(n.messages)||typeof n.nextSequence!="string"||!d(n.nextSequence)||typeof n.hasMore!="boolean"||typeof n.historyFromSequence!="string"||!d(n.historyFromSequence)||typeof n.roomName!="string")&&r(),{messages:n.messages.map(a=>h(a,e.roomId)),nextSequence:n.nextSequence,hasMore:n.hasMore,historyFromSequence:n.historyFromSequence,roomName:n.roomName}}async send(e){const o=await this.request(e,"messages",{method:"POST",body:JSON.stringify({clientMessageId:e.clientMessageId,text:e.text,mentionMembershipIds:e.mentionMembershipIds,replyToMessageId:e.replyToMessageId,activationCauseMessageId:e.activationCauseMessageId,attachmentIds:e.attachmentIds})});(!o||typeof o!="object")&&r();const t=o;return typeof t.idempotent!="boolean"&&r(),{message:h(t.message,e.roomId),idempotent:t.idempotent}}async mode(e){const o=await this.request(e,"mode",{method:"PATCH",body:JSON.stringify({activationMode:e.activationMode})});(!o||typeof o!="object")&&r();const t=o;return(t.bindingId!==e.bindingId||t.roomId!==e.roomId||t.status!=="active"&&t.status!=="paused"||!S(t.activationMode)||t.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&r(),t}async pause(e){const o=await this.request(e,"pause",{method:"POST",body:JSON.stringify({reason:e.reason})});(!o||typeof o!="object")&&r();const t=o;return(t.bindingId!==e.bindingId||t.roomId!==e.roomId||t.status!=="paused"||t.activationMode!=="paused"||typeof t.idempotent!="boolean")&&r(),{...t,message:h(t.message,e.roomId)}}async request(e,o,t={}){let n;const s=q(e.signal,1e4);try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings/${encodeURIComponent(e.bindingId)}/${o}`,{...t,headers:{authorization:`Bearer ${e.machineToken}`,...t.body?{"content-type":"application/json"}:{}},signal:s.signal})}catch{throw e.signal?.aborted?new c("managed_room_context_revoked","Managed Room context was revoked."):new c("room_action_server_unavailable","Shennian Room service is unavailable.")}finally{s.dispose()}if(!n.ok){let a=`room_action_http_${n.status}`;try{const m=await n.json();typeof m.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(m.error)&&(a=m.error)}catch{}throw new c(a,"Shennian Room action failed.")}try{return await n.json()}catch{r()}}}function q(i,e){const o=new AbortController,t=()=>o.abort();i?.aborted?o.abort():i?.addEventListener("abort",t,{once:!0});const n=setTimeout(()=>o.abort(),e);return n.unref?.(),{signal:o.signal,dispose:()=>{clearTimeout(n),i?.removeEventListener("abort",t)}}}function T(i,e){(!i||typeof i!="object")&&r();const o=i,t=o.room,n=o.agent;(o.bindingId!==e.bindingId||o.roomId!==e.roomId||typeof o.agentIdentityId!="string"||o.agentMembershipId!==null&&typeof o.agentMembershipId!="string"||o.status!=="pending_approval"&&o.status!=="active"&&o.status!=="paused"&&o.status!=="detached"||!S(o.activationMode)||o.activationCapability!==void 0&&o.activationCapability!=="managed"&&o.activationCapability!=="idle_resume"&&o.activationCapability!=="notify_only"||o.managedWorkspacePath!==void 0&&o.managedWorkspacePath!==null&&(typeof o.managedWorkspacePath!="string"||o.managedWorkspacePath.length>4096||!M.isAbsolute(o.managedWorkspacePath))||typeof o.lastDeliveredSequence!="string"||!d(o.lastDeliveredSequence)||typeof o.lastActivatedSequence!="string"||!d(o.lastActivatedSequence)||!t||typeof t!="object"||n!==void 0&&(!n||typeof n!="object"))&&r(),(o.status==="pending_approval"&&o.agentMembershipId!==null||(o.status==="active"||o.status==="paused")&&typeof o.agentMembershipId!="string")&&r();const s=t,a=n,m=a?_(a.permissionPolicy):null,g=a?C(a.permissionConfirmation):null,w=a?Object.prototype.hasOwnProperty.call(a,"permissionConfirmation"):!1,f=s.members;return(a!==void 0&&(typeof a.displayName!="string"||!a.displayName.trim()||typeof a.description!="string"||a.sessionMode!=="standard"&&a.sessionMode!=="manager"||!m||!w||a.permissionConfirmation!==null&&!g)||typeof s.name!="string"||typeof s.status!="string"||s.memberCount!==void 0&&(typeof s.memberCount!="number"||!Number.isInteger(s.memberCount)||s.memberCount<0)||typeof s.lastSequence!="string"||!d(s.lastSequence)||f!==void 0&&(!Array.isArray(f)||f.some(y=>{if(!y||typeof y!="object")return!0;const u=y;return typeof u.displayName!="string"||u.principalType!=="human"&&u.principalType!=="agent"})))&&r(),{...o,...a&&m?{agent:{...a,permissionPolicy:m,permissionConfirmation:g}}:{}}}function C(i){if(!i||typeof i!="object"||Array.isArray(i))return null;const e=i;return!Number.isSafeInteger(e.policyVersion)||Number(e.policyVersion)<1||typeof e.runtimeAdapter!="string"||!j(e.runtimeAdapter)||typeof e.runtimeVersion!="string"||!e.runtimeVersion.trim()||typeof e.platform!="string"||!e.platform.trim()||typeof e.executableFingerprint!="string"||!/^sha256:[a-f0-9]{64}$/.test(e.executableFingerprint)||typeof e.hostFullAccess!="boolean"||typeof e.limitedProtection!="boolean"||typeof e.confirmedAt!="string"||!Number.isFinite(Date.parse(e.confirmedAt))?null:{policyVersion:Number(e.policyVersion),runtimeAdapter:e.runtimeAdapter,runtimeVersion:e.runtimeVersion,platform:e.platform,executableFingerprint:e.executableFingerprint,hostFullAccess:e.hostFullAccess,limitedProtection:e.limitedProtection,confirmedAt:e.confirmedAt}}function h(i,e){(!i||typeof i!="object")&&r();const o=i;if((typeof o.id!="string"||o.roomId!==e||typeof o.sequence!="string"||!d(o.sequence)||!o.author||typeof o.author.membershipId!="string"||!Array.isArray(o.attachments)||typeof o.createdAt!="string")&&r(),o.activationCause!=null){const t=o.activationCause;(typeof t.causeMessageId!="string"||typeof t.rootCauseMessageId!="string"||!Number.isInteger(t.hopCount)||t.hopCount<1||t.hopCount>32)&&r()}return o}function R(i,e,o){(!i||typeof i!="object")&&r();const t=i,n=t.room,s=t.agentIdentity,a=t.binding;return(t.outcome!=="created"||!n||typeof n.id!="string"||n.name!==e.name||n.visibility!=="private"||n.joinPolicy!=="open"||!b(n.canonicalUrl,o,`/spaces/${n.id}`)||!U(n.inviteUrl,o,n.id)||!s||typeof s.id!="string"||s.displayName!==e.agentAlias||!a||typeof a.id!="string"||a.roomId!==n.id||a.agentIdentityId!==s.id||typeof a.agentMembershipId!="string"||a.status!=="active"&&a.status!=="paused"||a.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&r(),t}function $(i,e,o){(!i||typeof i!="object")&&r();const t=i,n=t.room;return(t.outcome!=="created"||!n||typeof n.id!="string"||n.name!==e.name||n.visibility!=="private"||n.joinPolicy!=="open"||!b(n.canonicalUrl,o,`/spaces/${n.id}`))&&r(),t}function P(i,e,o){(!i||typeof i!="object")&&r();const t=i,n=t.room,s=t.agentIdentity,a=t.binding;return(t.outcome!=="joined"&&t.outcome!=="pending_approval"||!n||typeof n.id!="string"||typeof n.name!="string"||!b(n.canonicalUrl,o,`/spaces/${n.id}`)||!s||typeof s.id!="string"||s.displayName!==e.agentAlias||!a||typeof a.id!="string"||a.roomId!==n.id||a.agentIdentityId!==s.id||a.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&r(),(t.outcome==="pending_approval"&&(a.status!=="pending_approval"||a.agentMembershipId!==null||typeof t.joinRequestId!="string")||t.outcome==="joined"&&(a.status!=="active"&&a.status!=="paused"||typeof a.agentMembershipId!="string"||t.joinRequestId!==void 0))&&r(),t}function d(i){return/^(0|[1-9]\d{0,19})$/.test(i)}function I(i){return i.length<=255&&i===i.trim()&&i!=="."&&i!==".."&&!/[\\/\0-\x1f\x7f]/.test(i)}function v(i){if(typeof i!="string")return!1;try{const e=new URL(i);return e.protocol==="https:"&&!e.username&&!e.password&&!e.hash}catch{return!1}}function S(i){return i==="auto_follow"||i==="mention_only"||i==="paused"}function r(){throw new c("invalid_room_action_response","Invalid Room action response.")}async function p(i){try{return await i.json()}catch{r()}}function l(i,e){let o=`room_action_http_${i}`;if(e&&typeof e=="object"){const t=e.error;typeof t=="string"&&/^[a-z0-9_-]{1,80}$/.test(t)&&(o=t)}return new c(o,"Shennian Room action failed.")}function b(i,e,o){return A(i,e,t=>t.pathname===o)}function U(i,e,o){if(typeof i!="string")return!1;try{const t=new URL(i);return A(`${t.origin}${t.pathname}`,e,n=>n.pathname===`/spaces/${o}`)?t.searchParams.size===1&&/^[A-Za-z0-9_-]{32,256}$/.test(t.searchParams.get("invite")??"")&&!t.hash&&!t.username&&!t.password:!1}catch{return!1}}function A(i,e,o){if(typeof i!="string")return!1;try{const t=new URL(i),n=new URL(e),s=t.origin===n.origin,a=n.protocol==="http:"&&t.protocol==="http:"&&t.hostname===n.hostname,m=t.protocol==="https:"&&t.port===""&&t.hostname==="app.shennian.net";return(s||a||m)&&!t.username&&!t.password&&!t.search&&!t.hash&&o(t)}catch{return!1}}export{O as HttpRoomActionClient,c as RoomActionHttpError};
|
|
1
|
+
import{isAvailableAgentType as j,parseManagedAgentPermissionPolicy as _}from"@shennian/wire";import M from"node:path";class c extends Error{code;constructor(e,n){super(n),this.code=e,this.name="RoomActionHttpError"}}class O{fetchImpl;baseUrl;constructor(e,n=fetch){this.fetchImpl=n,this.baseUrl=e.replace(/\/+$/,"")}async createOperatorRoom(e){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/operator/create`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({name:e.name}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(n);if(!n.ok)throw f(n.status,t);return N(t,e,this.baseUrl)}async resolveNativeSession(e){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/resolve-session`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({runtimeAdapter:e.runtimeAdapter,sourceSessionKey:e.sourceSessionKey}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(n);if(!n.ok)throw f(n.status,t);(!t||typeof t!="object")&&r();const o=t;return(typeof o.nianSessionId!="string"||!/^[A-Za-z0-9_.:@/-]{1,512}$/.test(o.nianSessionId)||typeof o.created!="boolean")&&r(),o}async createRoom(e){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/create`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,name:e.name,agentAlias:e.agentAlias,agentDescription:e.agentDescription,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(n);if(!n.ok)throw f(n.status,t);return R(t,e,this.baseUrl)}async joinRoom(e){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/join`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,inviteToken:e.inviteToken,message:e.message,agentAlias:e.agentAlias,agentDescription:e.agentDescription,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await p(n);if(!n.ok)throw f(n.status,t);return $(t,e,this.baseUrl)}async status(e){const n=await this.request(e,"status");return q(n,e)}async getAttachmentCapability(e){const n=await this.request(e,`attachments/${encodeURIComponent(e.attachmentId)}/download-capability`);(!n||typeof n!="object")&&r();const t=n;return(t.attachmentId!==e.attachmentId||t.roomId!==e.roomId||typeof t.safeName!="string"||!I(t.safeName)||typeof t.mimeType!="string"||t.mimeType.length<1||t.mimeType.length>191||typeof t.byteSize!="string"||!m(t.byteSize)||typeof t.sha256!="string"||!/^[a-f0-9]{64}$/.test(t.sha256)||!S(t.downloadUrl)||typeof t.expiresAt!="string"||!Number.isFinite(Date.parse(t.expiresAt)))&&r(),t}async initializeAttachment(e){const n=await this.request(e,"attachments/init",{method:"POST",body:JSON.stringify({clientUploadId:e.clientUploadId,name:e.name,mediaKind:e.mediaKind,mimeType:e.mimeType,byteSize:e.byteSize,sha256:e.sha256})});(!n||typeof n!="object")&&r();const t=n,o=t.attachment,s=t.upload;return(!o||typeof o.id!="string"||o.roomId!==e.roomId||typeof o.name!="string"||!I(o.name)||o.mimeType!==e.mimeType||o.byteSize!==String(e.byteSize)||o.sha256!==e.sha256||o.status!=="pending"&&o.status!=="uploaded"||!s||s.method!=="PUT"||!S(s.url)||!s.headers||typeof s.headers!="object"||s.headers["content-type"]!==e.mimeType||s.headers["x-oss-meta-sha256"]!==e.sha256||typeof s.expiresAt!="string"||!Number.isFinite(Date.parse(s.expiresAt))||Date.parse(s.expiresAt)<=Date.now()||typeof t.idempotent!="boolean")&&r(),t}async completeAttachment(e){const n=await this.request(e,`attachments/${encodeURIComponent(e.attachmentId)}/complete`,{method:"POST"});(!n||typeof n!="object")&&r();const t=n;typeof t.idempotent!="boolean"&&r();const o=t.attachment;return(!o||o.attachmentId!==e.attachmentId||o.mediaKind!=="image"&&o.mediaKind!=="audio"&&o.mediaKind!=="file"||typeof o.name!="string"||typeof o.mimeType!="string"||typeof o.byteSize!="string"||!m(o.byteSize)||typeof o.sha256!="string"||!/^[a-f0-9]{64}$/.test(o.sha256)||o.status!=="ready")&&r(),{attachment:o,idempotent:t.idempotent}}async read(e){if(e.beforeSequence&&e.afterSequence)throw new c("ambiguous_sequence_cursor","beforeSequence and afterSequence are mutually exclusive.");const n=new URLSearchParams({limit:String(e.limit)});e.beforeSequence&&n.set("before",e.beforeSequence),e.afterSequence&&n.set("after",e.afterSequence);const t=await this.request(e,`messages?${n}`);(!t||typeof t!="object")&&r();const o=t;return(!Array.isArray(o.messages)||typeof o.nextSequence!="string"||!m(o.nextSequence)||typeof o.hasMore!="boolean"||typeof o.historyFromSequence!="string"||!m(o.historyFromSequence)||typeof o.roomName!="string")&&r(),{messages:o.messages.map(a=>h(a,e.roomId)),nextSequence:o.nextSequence,hasMore:o.hasMore,historyFromSequence:o.historyFromSequence,roomName:o.roomName}}async send(e){const n=await this.request(e,"messages",{method:"POST",body:JSON.stringify({clientMessageId:e.clientMessageId,text:e.text,mentionMembershipIds:e.mentionMembershipIds,replyToMessageId:e.replyToMessageId,activationCauseMessageId:e.activationCauseMessageId,attachmentIds:e.attachmentIds})});(!n||typeof n!="object")&&r();const t=n;return typeof t.idempotent!="boolean"&&r(),{message:h(t.message,e.roomId),idempotent:t.idempotent}}async mode(e){const n=await this.request(e,"mode",{method:"PATCH",body:JSON.stringify({activationMode:e.activationMode})});(!n||typeof n!="object")&&r();const t=n;return(t.bindingId!==e.bindingId||t.roomId!==e.roomId||t.status!=="active"&&t.status!=="paused"||!v(t.activationMode)||t.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&r(),t}async pause(e){const n=await this.request(e,"pause",{method:"POST",body:JSON.stringify({reason:e.reason})});(!n||typeof n!="object")&&r();const t=n;return(t.bindingId!==e.bindingId||t.roomId!==e.roomId||t.status!=="paused"||t.activationMode!=="paused"||typeof t.idempotent!="boolean")&&r(),{...t,message:h(t.message,e.roomId)}}async request(e,n,t={}){let o;const s=C(e.signal,1e4);try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings/${encodeURIComponent(e.bindingId)}/${n}`,{...t,headers:{authorization:`Bearer ${e.machineToken}`,...t.body?{"content-type":"application/json"}:{}},signal:s.signal})}catch{throw e.signal?.aborted?new c("managed_room_context_revoked","Managed Room context was revoked."):new c("room_action_server_unavailable","Shennian Room service is unavailable.")}finally{s.dispose()}if(!o.ok){let a=`room_action_http_${o.status}`;try{const d=await o.json();typeof d.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(d.error)&&(a=d.error)}catch{}throw new c(a,"Shennian Room action failed.")}try{return await o.json()}catch{r()}}}function C(i,e){const n=new AbortController,t=()=>n.abort();i?.aborted?n.abort():i?.addEventListener("abort",t,{once:!0});const o=setTimeout(()=>n.abort(),e);return o.unref?.(),{signal:n.signal,dispose:()=>{clearTimeout(o),i?.removeEventListener("abort",t)}}}function q(i,e){(!i||typeof i!="object")&&r();const n=i,t=n.room,o=n.agent;(n.bindingId!==e.bindingId||n.roomId!==e.roomId||typeof n.agentIdentityId!="string"||n.agentMembershipId!==null&&typeof n.agentMembershipId!="string"||n.status!=="pending_approval"&&n.status!=="active"&&n.status!=="paused"&&n.status!=="detached"||!v(n.activationMode)||n.activationCapability!==void 0&&n.activationCapability!=="managed"&&n.activationCapability!=="idle_resume"&&n.activationCapability!=="notify_only"||n.managedWorkspacePath!==void 0&&n.managedWorkspacePath!==null&&(typeof n.managedWorkspacePath!="string"||n.managedWorkspacePath.length>4096||!M.isAbsolute(n.managedWorkspacePath))||typeof n.lastDeliveredSequence!="string"||!m(n.lastDeliveredSequence)||typeof n.lastActivatedSequence!="string"||!m(n.lastActivatedSequence)||n.appliedConfigurationVersion!==void 0&&(!Number.isSafeInteger(n.appliedConfigurationVersion)||Number(n.appliedConfigurationVersion)<1)||n.pendingConfigurationVersion!==void 0&&n.pendingConfigurationVersion!==null&&(!Number.isSafeInteger(n.pendingConfigurationVersion)||Number(n.pendingConfigurationVersion)<1)||!t||typeof t!="object"||o!==void 0&&(!o||typeof o!="object"))&&r(),(n.status==="pending_approval"&&n.agentMembershipId!==null||(n.status==="active"||n.status==="paused")&&typeof n.agentMembershipId!="string")&&r();const s=t,a=o,d=a?_(a.permissionPolicy):null,g=a?T(a.permissionConfirmation):null,w=a?Object.prototype.hasOwnProperty.call(a,"permissionConfirmation"):!1,l=s.members;return(a!==void 0&&(typeof a.displayName!="string"||!a.displayName.trim()||typeof a.description!="string"||a.sessionMode!=="standard"&&a.sessionMode!=="manager"||a.configurationVersion!==void 0&&(!Number.isSafeInteger(a.configurationVersion)||Number(a.configurationVersion)<1)||a.configurationPending!==void 0&&typeof a.configurationPending!="boolean"||!d||!w||a.permissionConfirmation!==null&&!g)||typeof s.name!="string"||typeof s.status!="string"||s.memberCount!==void 0&&(typeof s.memberCount!="number"||!Number.isInteger(s.memberCount)||s.memberCount<0)||typeof s.lastSequence!="string"||!m(s.lastSequence)||l!==void 0&&(!Array.isArray(l)||l.some(u=>{if(!u||typeof u!="object")return!0;const y=u;return typeof y.displayName!="string"||y.principalType!=="human"&&y.principalType!=="agent"})))&&r(),{...n,...a&&d?{agent:{...a,permissionPolicy:d,permissionConfirmation:g}}:{}}}function T(i){if(!i||typeof i!="object"||Array.isArray(i))return null;const e=i;return!Number.isSafeInteger(e.policyVersion)||Number(e.policyVersion)<1||typeof e.runtimeAdapter!="string"||!j(e.runtimeAdapter)||typeof e.runtimeVersion!="string"||!e.runtimeVersion.trim()||typeof e.platform!="string"||!e.platform.trim()||typeof e.executableFingerprint!="string"||!/^sha256:[a-f0-9]{64}$/.test(e.executableFingerprint)||typeof e.hostFullAccess!="boolean"||typeof e.limitedProtection!="boolean"||typeof e.confirmedAt!="string"||!Number.isFinite(Date.parse(e.confirmedAt))?null:{policyVersion:Number(e.policyVersion),runtimeAdapter:e.runtimeAdapter,runtimeVersion:e.runtimeVersion,platform:e.platform,executableFingerprint:e.executableFingerprint,executionMode:e.executionMode==="native-full"?"native-full":"restricted",hostFullAccess:e.hostFullAccess,limitedProtection:e.limitedProtection,confirmedAt:e.confirmedAt}}function h(i,e){(!i||typeof i!="object")&&r();const n=i;if((typeof n.id!="string"||n.roomId!==e||typeof n.sequence!="string"||!m(n.sequence)||!n.author||typeof n.author.membershipId!="string"||!Array.isArray(n.attachments)||typeof n.createdAt!="string")&&r(),n.activationCause!=null){const t=n.activationCause;(typeof t.causeMessageId!="string"||typeof t.rootCauseMessageId!="string"||!Number.isInteger(t.hopCount)||t.hopCount<1||t.hopCount>32)&&r()}return n}function R(i,e,n){(!i||typeof i!="object")&&r();const t=i,o=t.room,s=t.agentIdentity,a=t.binding;return(t.outcome!=="created"||!o||typeof o.id!="string"||o.name!==e.name||o.visibility!=="private"||o.joinPolicy!=="open"||!b(o.canonicalUrl,n,`/spaces/${o.id}`)||!P(o.inviteUrl,n,o.id)||!s||typeof s.id!="string"||s.displayName!==e.agentAlias||!a||typeof a.id!="string"||a.roomId!==o.id||a.agentIdentityId!==s.id||typeof a.agentMembershipId!="string"||a.status!=="active"&&a.status!=="paused"||a.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&r(),t}function N(i,e,n){(!i||typeof i!="object")&&r();const t=i,o=t.room;return(t.outcome!=="created"||!o||typeof o.id!="string"||o.name!==e.name||o.visibility!=="private"||o.joinPolicy!=="open"||!b(o.canonicalUrl,n,`/spaces/${o.id}`))&&r(),t}function $(i,e,n){(!i||typeof i!="object")&&r();const t=i,o=t.room,s=t.agentIdentity,a=t.binding;return(t.outcome!=="joined"&&t.outcome!=="pending_approval"||!o||typeof o.id!="string"||typeof o.name!="string"||!b(o.canonicalUrl,n,`/spaces/${o.id}`)||!s||typeof s.id!="string"||s.displayName!==e.agentAlias||!a||typeof a.id!="string"||a.roomId!==o.id||a.agentIdentityId!==s.id||a.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&r(),(t.outcome==="pending_approval"&&(a.status!=="pending_approval"||a.agentMembershipId!==null||typeof t.joinRequestId!="string")||t.outcome==="joined"&&(a.status!=="active"&&a.status!=="paused"||typeof a.agentMembershipId!="string"||t.joinRequestId!==void 0))&&r(),t}function m(i){return/^(0|[1-9]\d{0,19})$/.test(i)}function I(i){return i.length<=255&&i===i.trim()&&i!=="."&&i!==".."&&!/[\\/\0-\x1f\x7f]/.test(i)}function S(i){if(typeof i!="string")return!1;try{const e=new URL(i);return e.protocol==="https:"&&!e.username&&!e.password&&!e.hash}catch{return!1}}function v(i){return i==="auto_follow"||i==="mention_only"||i==="paused"}function r(){throw new c("invalid_room_action_response","Invalid Room action response.")}async function p(i){try{return await i.json()}catch{r()}}function f(i,e){let n=`room_action_http_${i}`;if(e&&typeof e=="object"){const t=e.error;typeof t=="string"&&/^[a-z0-9_-]{1,80}$/.test(t)&&(n=t)}return new c(n,"Shennian Room action failed.")}function b(i,e,n){return A(i,e,t=>t.pathname===n)}function P(i,e,n){if(typeof i!="string")return!1;try{const t=new URL(i);return A(`${t.origin}${t.pathname}`,e,o=>o.pathname===`/spaces/${n}`)?t.searchParams.size===1&&/^[A-Za-z0-9_-]{32,256}$/.test(t.searchParams.get("invite")??"")&&!t.hash&&!t.username&&!t.password:!1}catch{return!1}}function A(i,e,n){if(typeof i!="string")return!1;try{const t=new URL(i),o=new URL(e),s=t.origin===o.origin,a=o.protocol==="http:"&&t.protocol==="http:"&&t.hostname===o.hostname,d=t.protocol==="https:"&&t.port===""&&t.hostname==="app.shennian.net";return(s||a||d)&&!t.username&&!t.password&&!t.search&&!t.hash&&n(t)}catch{return!1}}export{O as HttpRoomActionClient,c as RoomActionHttpError};
|
|
@@ -9,6 +9,8 @@ export type ManagedAgentAdapterPolicy = {
|
|
|
9
9
|
failClosed: true;
|
|
10
10
|
};
|
|
11
11
|
export type CompiledManagedAgentPolicy = {
|
|
12
|
+
/** Missing only on persisted/test snapshots created before execution modes. */
|
|
13
|
+
executionMode?: 'native-full' | 'restricted';
|
|
12
14
|
requestedPolicy: ManagedAgentPermissionPolicy;
|
|
13
15
|
enforcement: ManagedAgentEnforcement;
|
|
14
16
|
adapterPolicy: ManagedAgentAdapterPolicy;
|
|
@@ -24,6 +26,7 @@ export type CompiledManagedAgentPolicy = {
|
|
|
24
26
|
};
|
|
25
27
|
};
|
|
26
28
|
};
|
|
29
|
+
export declare function isManagedAgentNativeFull(policy: CompiledManagedAgentPolicy | null | undefined): boolean;
|
|
27
30
|
/**
|
|
28
31
|
* Native adapters must always attempt the user's requested restriction. The
|
|
29
32
|
* effective policy is an honest projection for display and confirmation; it
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import c from"node:fs/promises";import
|
|
1
|
+
import c from"node:fs/promises";import o from"node:path";import{managedAgentExecutionMode as y,parseManagedAgentPermissionPolicy as b,resolveManagedAgentEffectivePermissionPolicy as k}from"@shennian/wire";import{getManagedAgentBaseEnvKeys as _,getManagedAgentProviderEnvKeys as u,getManagedAgentSessionEnvKeys as d}from"../agent-env.js";import{collectPolicyEnforcementGaps as w,resolveManagedAgentRuntimeProtection as P,resolveManagedAgentSecurityProfile as x}from"./managed-agent-runtime.js";import{resolveProtectedShennianDirectories as C}from"./managed-agent-credential-paths.js";function V(e){return!!(e&&(e.executionMode==="native-full"||e.requestedPolicy.executionMode==="native-full"))}function I(e){return{...e.enforcement,effectivePolicy:{version:e.adapterPolicy.version,executionMode:e.executionMode??"restricted",fileAccess:e.adapterPolicy.fileAccess,externalCapabilities:{...e.adapterPolicy.externalCapabilities}}}}async function z(e){const r=b(e.policy);if(!r)return{ok:!1,errorCode:"managed_agent_policy_invalid"};const t=y(r);if((t==="native-full"||r.fileAccess==="host-full")&&!e.hostFullAccessConfirmed)return{ok:!1,errorCode:"managed_agent_host_full_confirmation_required"};const n=await h(e.workDir,e.resolveWorkDir);if(!n.ok)return n;if(await D(n.workDir))return{ok:!1,errorCode:"managed_agent_workdir_invalid"};const a=A(e),i=P(a),l=x(a),s=t==="restricted"?w(r,l):{unavailableCapabilities:[],overgrantedCapabilities:[]},v=g([...t==="restricted"&&i.level!=="hard"?["runtime.hardIsolation"]:[],...t==="restricted"?i.unsupportedCapabilities:[],...s.unavailableCapabilities,...s.overgrantedCapabilities]),p=k(r,i),m={level:i.level,effectivePolicy:p,unsupportedCapabilities:v,runtimeVersion:i.runtimeVersion,platform:i.platform,...i.executableFingerprint?{executableFingerprint:i.executableFingerprint}:{}};return{ok:!0,value:{requestedPolicy:F(r),executionMode:t,enforcement:m,adapterPolicy:{version:r.version,workDir:n.workDir,fileAccess:r.fileAccess,externalCapabilities:{...r.externalCapabilities},denySensitiveFiles:!0,failClosed:!0},environmentPolicy:{inheritDaemonEnv:!1,loadLoginShell:!1,providerEnvKeys:[...u(e.agentType)],sessionEnvKeys:[...d(e.agentType)],shellSubprocess:{inherit:"none",allowedEnvKeys:g([..._(e.platform),...d(e.agentType)]),deniedEnvKeys:[...u(e.agentType)]}}}}}function A(e){return{agentType:e.agentType,runtimeVersion:e.runtimeVersion,platform:e.platform,isWsl:e.isWsl,executableFingerprint:e.executableFingerprint,requireExecutableFingerprint:e.requireExecutableFingerprint,securityDeclaration:e.securityDeclaration}}async function h(e,r){const t=e.trim();if(!t||!o.isAbsolute(t))return{ok:!1,errorCode:"managed_agent_workdir_invalid"};try{const n=await(r??M)(t);return!n||!o.isAbsolute(n)?{ok:!1,errorCode:"managed_agent_workdir_invalid"}:{ok:!0,workDir:o.normalize(n)}}catch{return{ok:!1,errorCode:"managed_agent_workdir_unavailable"}}}async function M(e){const r=await c.realpath(e);if(!(await c.stat(r)).isDirectory())throw new Error("managed_agent_workdir_not_directory");return r}async function D(e){return C().some(t=>E(e,t,process.platform))}function E(e,r,t){const n=l=>{const s=o.resolve(l);return t==="win32"?s.toLowerCase():s},a=n(e),i=n(r);return f(a,i)||f(i,a)}function f(e,r){const t=o.relative(e,r);return t===""||!t.startsWith("..")&&!o.isAbsolute(t)}function F(e){return{...e,externalCapabilities:{...e.externalCapabilities}}}function g(e){return[...new Set(e)]}export{z as compileManagedAgentPolicy,V as isManagedAgentNativeFull,I as resolveManagedAgentAdapterEnforcement};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`),a=n>0?Math.min(n,80):Math.min(e.length,80);return e.slice(0,a)}function Ie(e,n,a){return`${e}:${q("sha256").update(`${n}\0${a??""}`).digest("hex")}`}function Le(e,n,a={}){if(e.state==="tool-call"||e.state==="tool-result"){const s={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:n,detailRef:s,status:e.state==="tool-call"?"running":"completed",detailAvailable:!0,...e.durationMs!==void 0?{durationMs:e.durationMs}:{},...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...a}}return{...e,sessionId:n,...a}}const Ke=3e4;function Qe(e){return e.state==="heartbeat"?e.runPhase??null:e.state==="tool-call"||e.state==="tool-result"?"tool_running":e.state==="approval-pending"?"waiting_approval":e.state==="delta"?e.thinking?"thinking":"streaming_text":e.state==="init"||e.state==="start"?"thinking":null}function Re(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function Se(e,n){return e!=="manager"?e:n==="claude"?"claude":"codex"}function Ge(e,n){U({sessionId:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,workDir:n.workDir,status:"active",externalChannel:null}}})}function ke(e){return We(e)}function we(e,n,a){return{}}function L(e,n,a,s,r,u,c,m){const l=a==="codex";e.configure?.({sessionId:n,externalChannel:s??null,env:{...ke(a),...we(n,s,r),...u&&!l?{SHENNIAN_MANAGED_ROOM_CONTEXT:u,[ze]:Fe()}:{}},...c?{managedAgentPolicy:c}:{},...l?{managedRoomContextToken:u??null,managedRoomExecutor:u?m??null:null}:{}})}function oe(e,n,a){const s=n.managedRoomContextToken;s&&s!==a&&e.revokeManagedRoomContextToken?.(s),n.managedRoomContextToken=a}function B(e,n){const a=n?.managedRoomContextToken;!n||!a||(n.managedRoomContextToken=null,e.revokeManagedRoomContextToken?.(a))}function Xe(e,n,a){if(e!=="claude"||!a)return n;const s=n.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?$e(a)??n:n}function Ye(e,n,a,s){let r=null;function u(t,o={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:Le(t,n,o),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}function c(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function m(t){if(!t.currentRunId||!t.currentRunPhase)return;const o=t.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:n,runId:t.currentRunId,seq:o,runPhase:t.currentRunPhase},seq:o,id:`agent-heartbeat-${t.currentRunId}-${o}-${Date.now()}`})}function l(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{m(t)},Ke),t.heartbeatTimer.unref?.())}function y(t){const o=t?.pendingTextEvent;!t||!o||!o.text||($(n,{id:`agent-${o.runId}-${o.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:o.text}),_(e.client),u({state:"delta",runId:o.runId,seq:o.seq,text:o.text,thinking:o.thinking||void 0}),t.pendingTextEvent=null)}s.on("agentEvent",t=>{t.errorCode==="acp_auth_required"&&Ve(e).catch(()=>{});const o=e.sessions.get(n),k=Qe(t),v=t.state==="final"||t.state==="error"||t.state==="aborted";if(o&&(o.nextEventSeq=t.seq+1,v||(o.currentRunId=t.runId),!v&&k&&(o.currentRunPhase=k,l(o)),t.agentSessionId&&(o.agentSessionId=t.agentSessionId),o.journalRunId)){const h={agentSessionId:t.agentSessionId??o.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...v?{}:{phase:k==="waiting_approval"?"waiting_approval":"running"}};e.runJournal?.update(n,o.journalRunId,h)}if(e.managerRuntime?.noteAgentEvent(n,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&C({level:"info",sessionId:n,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:a}});let E=!1;if(t.state==="tool-call"||t.state==="tool-result"){const h=t.toolCallId?`agent-tool-${q("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;Ne({sessionId:n,toolCallId:h,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?j:$)(n,{id:h,sessionId:n,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:h,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),E=!0}else t.state==="approval-pending"?($(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:qe({...t.approval,permission:t.permission})}),E=!0,o&&U({sessionId:n,agentType:a,workDir:o.workDir,agentSessionId:o.agentSessionId,attentionId:Ie("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&($(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:t.message}),E=!0);E&&_(e.client);const w=`${n}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&e.runTextAcc.set(w,(e.runTextAcc.get(w)??"")+t.text),t.agentSessionId&&t.agentSessionId!==r&&(r=t.agentSessionId,e.nativeFusion?.noteManagedSourceSession(n,Se(a,t.source),t.agentSessionId),o&&U({sessionId:n,agentType:a,workDir:o.workDir,agentSessionId:t.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n,agentType:a,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const h=t.text??"";if(!h)return;o?.pendingTextEvent&&o.pendingTextEvent.runId!==t.runId&&y(o),o&&!o.pendingTextEvent&&(o.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),o?.pendingTextEvent&&(o.pendingTextEvent.text+=h,o.pendingTextEvent.seq=t.seq);return}let N={};if(t.state==="final"){y(o);const h=e.runTextAcc.get(w)??"";h&&(N={messageSummary:Ue(h)}),e.runTextAcc.delete(w)}else t.state==="error"||t.state==="aborted"?(y(o),e.runTextAcc.delete(w)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&y(o);v&&o?.currentRunId===t.runId&&(B(e,o),o.currentRunId=null,o.currentRunPhase=null,o.nextEventSeq=0,c(o),e.chatQueue?.noteTerminal(n),U({sessionId:n,agentType:a,workDir:o.workDir,agentSessionId:o.agentSessionId,status:t.state==="final"?"completed":"failed",attentionId:Ie("terminal",t.runId),lastActivityAt:new Date().toISOString()}),_(e.client),o.journalRunId&&(e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null)),u(t,N)}),s.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${n} agentType=${a}: ${t.message}`);const o=e.sessions.get(n);B(e,o),o?.journalRunId&&(e.runJournal?.update(n,o.journalRunId,{phase:"terminal"}),e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null),e.sessions.delete(n),e.chatQueue?.noteTerminal(n),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:t.message,runId:"",seq:0}})})}function Ze(e,n){if(e.processedReqIds.add(n),e.processedReqIds.size>1e3){const a=e.processedReqIds.values().next().value;e.processedReqIds.delete(a)}}async function K(e,n){B(e,n),n.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null),n.adapter.removeAllListeners(),await n.adapter.stop().catch(()=>{})}function Ae(e,n,a,s,r,u,c){return c?e.send(n,a,s,r,u,c):u?.trim()?e.send(n,a,s,r,u):r?.length?e.send(n,a,s,r):s?e.send(n,a,s):e.send(n,a)}function en(e,n,a,s,r,u,c){return e.prepareSend?e.prepareSend(n,a,s,r,u,c):Promise.resolve()}async function Pe(e,n,a,s,r,u,c,m,l,y="user"){e.evictIdleSessions();const t=be(a);if(!t)throw new Error(`Unsupported agent: ${a}`);const o=s==="manager"&&a!=="manager"?new Ce(t,a):t;L(o,n,a,c,m,null,l,e.managedRoomExecutor),y==="internal"?await o.start(n,r,u,{nativeSessionVisibility:y}):await o.start(n,r,u);const k={adapter:o,workDir:r,agentType:a,sessionMode:s,nativeSessionVisibility:y,agentSessionId:u??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:c??null,externalReplyTarget:m??null,externalChannelEnv:{...ke(a),...we(n,c,m)},managedRoomContextToken:null,journalRunId:null};return e.sessions.set(n,k),Ye(e,n,a,o),k}async function An(e,n,a=()=>{}){let s=null,r=null,u=null,c;if(n.source==="managed_room"||n.source==="managed_direct"){const l=await e.prepareManagedRecovery?.(n);if(!l)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery requires a fresh permission context"};if(l.agentType!==n.agentType||l.sessionMode!==n.sessionMode||e.resolvePath(l.workDir)!==e.resolvePath(n.workDir)||l.managedRoomPromptSnapshot.managedRoomPolicyVersion!==n.managedPolicyVersion||l.managedRoomPromptSnapshot.runtimePermissionPolicyHash!==n.managedRuntimePolicyHash)return e.revokeManagedRoomContextToken?.(l.managedRoomContextToken),{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery authority no longer matches the interrupted run"};const y={source:"room_activation",managedAgentPolicy:l.managedAgentPolicy,managedRoomPromptSnapshot:l.managedRoomPromptSnapshot};he(y,l.systemPrompt,l.managedRoomContextToken),s=l.managedAgentPolicy,r=l.managedRoomContextToken,u=l.systemPrompt,c={...y,recovery:"upgrade"}}else if(n.source==="manager_worker"){const l=n.parentSessionId;if(s=l?e.managerRuntime?.getManagedAgentPolicyForWorker(l,n.workDir)??null:null,!s)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker recovery requires the current parent policy"};if(q("sha256").update(JSON.stringify({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement})).digest("hex")!==n.managedRuntimePolicyHash)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker policy changed after interruption"};u=ye({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement,resolvedWorkDir:s.adapterPolicy.workDir})}c??={source:"upgrade_recovery",recovery:"upgrade"};let m=e.sessions.get(n.sessionId);return m||(m=await Pe(e,n.sessionId,n.agentType,n.sessionMode,n.workDir,n.agentSessionId,null,null,s,n.nativeSessionVisibility)),r&&(oe(e,m,r),L(m.adapter,n.sessionId,n.agentType,null,null,r,s,e.managedRoomExecutor)),m.journalRunId=n.runId,m.currentRunId=n.providerRunId??`recovery:${n.runId}`,m.currentRunPhase="thinking",m.adapter.recoverInterruptedRun({sessionId:n.sessionId,shennianRunId:n.runId,workDir:n.workDir,agentSessionId:n.agentSessionId,modelId:n.modelId,reasoningEffort:n.reasoningEffort,providerRunId:n.providerRunId,lastObservedEventSeq:n.lastObservedEventSeq,continueDispatchState:n.continueDispatchState,systemPrompt:u,sendContext:c,beforeContinueDispatch:a})}function nn(e,n){const a=e.sessions.get(n),s=a?.currentRunId;if(!a||!s)return;const r=a.nextEventSeq;e.runTextAcc.delete(`${n}:${s}`),B(e,a),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:s,seq:r},seq:r,id:`agent-evt-${s}-${r}`}),a.journalRunId&&(e.runJournal?.remove(n,a.journalRunId),e.recoveryBarrier?.end(n),a.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function Pn(e,n,a){const s=a?n.params.managedRoomContextToken??null:null;let r=!1;try{await tn(e,n,a,()=>{r=!0})}finally{s&&!r&&e.revokeManagedRoomContextToken?.(s)}}async function tn(e,n,a,s){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:r,text:u,agentType:c,sessionMode:m,managerConfig:l,workDir:y,agentSessionId:t,modelId:o,systemPrompt:k,managerDefaultWorkerAgentType:v,managerDefaultWorkerModelId:E,reasoningEffort:w,clientMessageId:N,sessionListProjection:h,waitForDispatch:Q,responseId:_e,managedRoomContextToken:O,suppressExternalOwnerEcho:ve,queuedBatchItems:G,managedWorkerParentSessionId:M,managedRecoverySource:Ee}=n.params,I=_e||n.id;Oe(h);const F=null,X="";if(a?.source==="room_activation"&&(he(a,k,O),c==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(Ze(e,n.id),!r||!u){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(r)&&await e.recoveryBarrier.wait(r);const p=c,D=p==="manager"||m==="manager"?"manager":"standard";D==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(r,v??null,E??null);const W=(p==="claude"||p==="codex"||p==="workbuddy"||p==="pi-coding-agent"||p.startsWith("acp:"))&&typeof w=="string"&&w.trim()?w.trim():void 0,A=e.resolvePath(Xe(p,y||pe.homedir(),t)||pe.homedir()),P=a?.managedAgentPolicy??(M?e.managerRuntime?.getManagedAgentPolicyForWorker(M,A)??null:null);if(M&&!P)throw new Error("managed_worker_permission_context_unavailable");const Y=p==="codex"&&(a?.source==="room_activation"||M)?"internal":"user",Z=M&&P?ye({requestedPolicy:P.requestedPolicy,enforcement:P.enforcement,resolvedWorkDir:P.adapterPolicy.workDir}):k,xe=A,z=He(n.params.attachments);z?.length&&Je(A,z);const R={text:u,attachments:z,localized:!1};let d=e.sessions.get(r);if(d){if(d.lastActiveAt=Date.now(),d.agentType!==p||(d.sessionMode??(d.agentType==="manager"?"manager":"standard"))!==D||d.workDir!==A||(d.nativeSessionVisibility??"user")!==Y||JSON.stringify(d.externalChannel??null)!==JSON.stringify(F??null)){e.sessions.delete(r);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}else if(t&&d.agentSessionId!==t)try{await d.adapter.resume(t),d.agentSessionId=t}catch{e.sessions.delete(r);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}}if(!d)try{d=await Pe(e,r,p,D,A,t,F,X,P,Y)}catch(i){const f=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${c}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${r} agentType=${c} workDir=${A} agentSessionId=${t??""}: ${f}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:f,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:f});return}const S={id:N??`user-${n.id}`,sessionId:r,role:"user",ts:Date.now(),payload:me(R.text,R.attachments)},re=Array.isArray(G)&&G.length>0?G.map(i=>({id:i.clientMessageId??i.id,sessionId:r,role:"user",ts:Date.parse(i.createdAt),payload:me(i.text,i.attachments)})):null,V=re??[S],x=je(r,S.id),se=x.state==="queued";if(x.state!=="not_found"&&!se){e.client.sendRes({type:"res",id:I,ok:!0,payload:x});return}if(Q){a?.source==="room_activation"&&L(d.adapter,r,p,F,X,O,a.managedAgentPolicy,e.managedRoomExecutor);try{await en(d.adapter,R.text,o,W,R.attachments,Z,a?{source:a.source}:void 0)}catch(i){e.processedReqIds.delete(n.id),e.sessions.delete(r),await K(e,d),e.client.sendRes({type:"res",id:I,ok:!1,error:i instanceof Error?i.message:String(i)});return}}C({level:"info",sessionId:r,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:p,sessionMode:D,managerConfig:l??null,modelId:o,managerDefaultWorkerAgentType:v??null,managerDefaultWorkerModelId:E??null,reasoningEffort:W,...a?.source==="room_activation"?{managedRoomPromptSnapshot:a.managedRoomPromptSnapshot}:{}}});const H=(i,f)=>({...fe(ae()),sessionId:r,clientMessageId:S.id,messageId:S.id,deliveryState:i,bodyRevision:f,committedAt:new Date(S.ts).toISOString()}),ie=i=>{e.nativeFusion?.registerManagedSend({sessionId:r,agentType:p,sourceAgentType:Se(p,o),canonicalMessageId:S.id,sourceSessionKey:d.agentSessionId??t??null,text:R.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"&&!ve?"import_following":"suppress_following",externalRunId:i?.deliveryMode==="external_owner_queue"?`codex-external-${i.queuedSubmissionId??S.id}`:null})},de=()=>{d.currentRunId||(d.currentRunId=`dispatch:${n.id}`,d.currentRunPhase="thinking",d.nextEventSeq=0)},le=()=>{if(!e.runJournal||d.journalRunId)return;const i=`run:${De()}`;e.runJournal.begin({daemonInstallationId:ae(),sessionId:r,runId:i,clientMessageId:S.id,agentType:p,sessionMode:D,workDir:A,agentSessionId:d.agentSessionId??t??null,modelId:o??null,reasoningEffort:W??null,nativeSessionVisibility:Y,providerRunId:null,source:a?.source==="room_activation"?Ee==="managed_direct"?"managed_direct":"managed_room":M?"manager_worker":"personal",parentSessionId:M??null,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:a?.managedRoomPromptSnapshot.managedRoomPolicyVersion??null,managedRuntimePolicyHash:a?.managedRoomPromptSnapshot.runtimePermissionPolicyHash??(P?q("sha256").update(JSON.stringify({requestedPolicy:P.requestedPolicy,enforcement:P.enforcement})).digest("hex"):null)}),d.journalRunId=i},ue=()=>{if(ie(),se)return{...fe(ae()),sessionId:r,clientMessageId:x.clientMessageId,messageId:x.messageId,deliveryState:x.deliveryState,bodyRevision:x.bodyRevision,committedAt:x.committedAt};try{Ge(e,{sessionId:r,agentType:p,sessionMode:D,managerConfig:l??null,workDir:xe,agentSessionId:d.agentSessionId??t??null,modelId:o,managerDefaultWorkerAgentType:v??null,managerDefaultWorkerModelId:E??null});let i=0;for(const[f,g]of V.entries()){const T=re?j(r,g,"committed"):$(r,g,"committed");f===0&&(i=T)}return Be(A,z??[]),_(e.client),H("committed",i)}catch(i){throw e.nativeFusion?.cancelManagedSend?.(S.id),i}},ce=i=>{d.currentRunId||(d.nextEventSeq=0),ie(i);const f=i?.deliveryMode==="external_owner_queue"?"queued":"executing";let g=0;for(const[T,J]of V.entries()){const b=j(r,J,f);T===0&&(g=b)}return _(e.client),H(f,g)},ee=async(i,f)=>{e.nativeFusion?.cancelManagedSend?.(S.id);const g=Re(p,i);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${r} agentType=${c} workDir=${A} agentSessionId=${d.agentSessionId??t??""}: ${g}`),d.adapter.hasPendingAuthenticationRetry?.()===!0){f&&e.client.sendRes({type:"res",id:I,ok:!0,payload:H("queued",0)});return}e.sessions.delete(r),d.journalRunId&&(e.runJournal?.update(r,d.journalRunId,{phase:"terminal"}),e.runJournal?.remove(r,d.journalRunId),e.recoveryBarrier?.end(r),d.journalRunId=null);try{await K(e,d)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:g,runId:"",seq:0}}),!f){const J={id:`agent-error-${n.id}-${Date.now()}`,sessionId:r,role:"agent",ts:Date.now(),payload:g};$(r,J),_(e.client)}f&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:g}))};if(Q){try{ue()}catch(g){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:`Durable message commit failed: ${g instanceof Error?g.message:String(g)}`});return}de(),le();let i;try{a?.source==="room_activation"&&(oe(e,d,O),s());const g=R.attachments;i=await Ae(d.adapter,R.text,o,W,g,Z,a?{source:a.source}:void 0),C({level:"info",sessionId:r,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(g){if(d.adapter.hasPendingAuthenticationRetry?.()){let b=0;for(const[ne,te]of V.entries()){const Te=j(r,te,"queued");ne===0&&(b=Te)}_(e.client),await ee(g,!1),e.client.sendRes({type:"res",id:I,ok:!0,payload:H("queued",b)});return}let T=0;for(const[b,ne]of V.entries()){const te=j(r,ne,"failed");b===0&&(T=te)}_(e.client);const J=Re(p,g);await ee(g,!1),e.client.sendRes({type:"res",id:I,ok:!0,payload:{...H("failed",T),failureMessage:J}});return}const f=ce(i??void 0);e.client.sendRes({type:"res",id:I,ok:!0,payload:{...f,...R.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}),C({level:"info",sessionId:r,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let ge;try{ge=ue()}catch(i){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:I,ok:!1,error:`Durable message commit failed: ${i instanceof Error?i.message:String(i)}`});return}de(),le(),a?.source==="room_activation"&&(L(d.adapter,r,p,F,X,O,a.managedAgentPolicy,e.managedRoomExecutor),oe(e,d,O),s()),ce(),e.client.sendRes({type:"res",id:I,ok:!0,payload:{...ge,...R.localized?{localizedAttachments:!0}:{}}}),C({level:"info",sessionId:r,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Me=R.attachments;Ae(d.adapter,R.text,o,W,Me,Z,a?{source:a.source}:void 0).then(()=>{C({level:"info",sessionId:r,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(i=>{j(r,S,d.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),_(e.client),ee(i,!1)})}async function _n(e,n){const{sessionId:a}=n.params,s=e.sessions.get(a);if(s){s.journalRunId&&e.runJournal?.markAborted(a,s.journalRunId),B(e,s);try{await s.adapter.stop()}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}nn(e,a),e.activityPublisher?.publish(a,null)}e.client.sendRes({type:"res",id:n.id,ok:!0})}export{_n as handleChatAbort,Pn as handleChatSend,An as recoverJournaledRun,Ge as sendSessionUpdateEvent};
|
|
1
|
+
import fe from"node:os";import{createHash as C,randomUUID as be}from"node:crypto";import{createAgent as qe}from"../../agents/adapter.js";import{buildApprovalPendingPayload as Ce,buildUserMessagePayload as me}from"@shennian/wire";import{ManagerModeAdapter as $e}from"../../agents/manager.js";import{reportLog as $}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as je}from"../../native-fusion/parsers.js";import{appendMessage as j,getDaemonInstallationId as oe,getMessageDeliveryStatus as Oe,recordSession as U,upsertMessage as D}from"../store.js";import{mergeProjectedSessions as We}from"../projection.js";import{buildManagedAgentEnv as He}from"../../agents/config-status.js";import{parsePersonalAttachmentReferences as Je}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as Be,markAttachmentReferences as Ne}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as w}from"../index-publisher.js";import{writeToolDetail as Fe}from"../tool-detail-store.js";import{getPersonalSyncIdentity as ye}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as Ie}from"../../room/managed-prompt-composer.js";import{getManagedRoomIpcRoot as ze,MANAGED_ROOM_IPC_ROOT_ENV as Ve}from"../../daemon-ipc/paths.js";import{refreshMachineAgents as Ue}from"./agents.js";function he(e,n,a){if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const s=e.managedRoomPromptSnapshot;if(!s)throw new Error("managed_room_prompt_snapshot_missing");if(!n?.trim())throw new Error("managed_room_prompt_incomplete");if(!a||!/^mrc_[A-Za-z0-9_-]{43}$/.test(a))throw new Error("managed_room_context_unavailable");const o=C("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),u=C("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(s.runtimePermissionPolicyHash!==o||s.resolvedWorkDirHash!==u||s.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function Le(e){const n=e.indexOf(`
|
|
2
|
+
`),a=n>0?Math.min(n,80):Math.min(e.length,80);return e.slice(0,a)}function Re(e,n,a){return`${e}:${C("sha256").update(`${n}\0${a??""}`).digest("hex")}`}function Ke(e,n,a={}){if(e.state==="tool-call"||e.state==="tool-result"){const s={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:n,detailRef:s,status:e.state==="tool-call"?"running":"completed",detailAvailable:!0,...e.durationMs!==void 0?{durationMs:e.durationMs}:{},...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...a}}return{...e,sessionId:n,...a}}const Qe=3e4;function Ge(e){return e.state==="heartbeat"?e.runPhase??null:e.state==="tool-call"||e.state==="tool-result"?"tool_running":e.state==="approval-pending"?"waiting_approval":e.state==="delta"?e.thinking?"thinking":"streaming_text":e.state==="init"||e.state==="start"?"thinking":null}function Se(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function we(e,n){return e!=="manager"?e:n==="claude"?"claude":"codex"}function Xe(e,n){U({sessionId:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,workDir:n.workDir,status:"active",externalChannel:null}}})}function ke(e){return He(e)}function _e(e,n,a){return{}}function L(e,n,a,s,o,u,c,f){const l=a==="codex";e.configure?.({sessionId:n,externalChannel:s??null,env:{...ke(a),..._e(n,s,o),...u&&!l?{SHENNIAN_MANAGED_ROOM_CONTEXT:u,[Ve]:ze()}:{}},...c?{managedAgentPolicy:c}:{},...l?{managedRoomContextToken:u??null,managedRoomExecutor:u?f??null:null}:{}})}function re(e,n,a){const s=n.managedRoomContextToken;s&&s!==a&&e.revokeManagedRoomContextToken?.(s),n.managedRoomContextToken=a}function N(e,n){const a=n?.managedRoomContextToken;!n||!a||(n.managedRoomContextToken=null,e.revokeManagedRoomContextToken?.(a))}function Ye(e,n,a){if(e!=="claude"||!a)return n;const s=n.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?je(a)??n:n}function Ze(e,n,a,s){let o=null;function u(t,r={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:Ke(t,n,r),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}function c(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function f(t){if(!t.currentRunId||!t.currentRunPhase)return;const r=t.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:n,runId:t.currentRunId,seq:r,runPhase:t.currentRunPhase},seq:r,id:`agent-heartbeat-${t.currentRunId}-${r}-${Date.now()}`})}function l(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{f(t)},Qe),t.heartbeatTimer.unref?.())}function y(t){const r=t?.pendingTextEvent;!t||!r||!r.text||(j(n,{id:`agent-${r.runId}-${r.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:r.text}),w(e.client),u({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),t.pendingTextEvent=null)}s.on("agentEvent",t=>{t.errorCode==="acp_auth_required"&&Ue(e).catch(()=>{});const r=e.sessions.get(n),k=Ge(t),x=t.state==="final"||t.state==="error"||t.state==="aborted";if(r&&(r.nextEventSeq=t.seq+1,x||(r.currentRunId=t.runId),!x&&k&&(r.currentRunPhase=k,l(r)),t.agentSessionId&&(r.agentSessionId=t.agentSessionId),r.journalRunId)){const I={agentSessionId:t.agentSessionId??r.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...x?{}:{phase:k==="waiting_approval"?"waiting_approval":"running"}};e.runJournal?.update(n,r.journalRunId,I)}if(e.managerRuntime?.noteAgentEvent(n,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&$({level:"info",sessionId:n,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:a}});let P=!1;if(t.state==="tool-call"||t.state==="tool-result"){const I=t.toolCallId?`agent-tool-${C("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;Fe({sessionId:n,toolCallId:I,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?D:j)(n,{id:I,sessionId:n,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:I,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),P=!0}else t.state==="approval-pending"?(j(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:Ce({...t.approval,permission:t.permission})}),P=!0,r&&U({sessionId:n,agentType:a,workDir:r.workDir,agentSessionId:r.agentSessionId,attentionId:Re("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&(j(n,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:n,role:"agent",ts:Date.now(),payload:t.message}),P=!0);P&&w(e.client);const _=`${n}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&e.runTextAcc.set(_,(e.runTextAcc.get(_)??"")+t.text),t.agentSessionId&&t.agentSessionId!==o&&(o=t.agentSessionId,e.nativeFusion?.noteManagedSourceSession(n,we(a,t.source),t.agentSessionId),r&&U({sessionId:n,agentType:a,workDir:r.workDir,agentSessionId:t.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n,agentType:a,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const I=t.text??"";if(!I)return;r?.pendingTextEvent&&r.pendingTextEvent.runId!==t.runId&&y(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=I,r.pendingTextEvent.seq=t.seq);return}let F={};if(t.state==="final"){y(r);const I=e.runTextAcc.get(_)??"";I&&(F={messageSummary:Le(I)}),e.runTextAcc.delete(_)}else t.state==="error"||t.state==="aborted"?(y(r),e.runTextAcc.delete(_)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&y(r);x&&r?.currentRunId===t.runId&&(N(e,r),r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,c(r),e.chatQueue?.noteTerminal(n),U({sessionId:n,agentType:a,workDir:r.workDir,agentSessionId:r.agentSessionId,status:t.state==="final"?"completed":"failed",attentionId:Re("terminal",t.runId),lastActivityAt:new Date().toISOString()}),w(e.client),r.journalRunId&&(e.runJournal?.remove(n,r.journalRunId),e.recoveryBarrier?.end(n),r.journalRunId=null)),u(t,F)}),s.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${n} agentType=${a}: ${t.message}`);const r=e.sessions.get(n);N(e,r),r?.journalRunId&&(e.runJournal?.update(n,r.journalRunId,{phase:"terminal"}),e.runJournal?.remove(n,r.journalRunId),e.recoveryBarrier?.end(n),r.journalRunId=null),e.sessions.delete(n),e.chatQueue?.noteTerminal(n),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:t.message,runId:"",seq:0}})})}function en(e,n){if(e.processedReqIds.add(n),e.processedReqIds.size>1e3){const a=e.processedReqIds.values().next().value;e.processedReqIds.delete(a)}}async function K(e,n){N(e,n),n.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null),n.adapter.removeAllListeners(),await n.adapter.stop().catch(()=>{})}function ve(e,n,a,s,o,u,c){return c?e.send(n,a,s,o,u,c):u?.trim()?e.send(n,a,s,o,u):o?.length?e.send(n,a,s,o):s?e.send(n,a,s):e.send(n,a)}function nn(e,n,a,s,o,u,c){return e.prepareSend?e.prepareSend(n,a,s,o,u,c):Promise.resolve()}async function Ae(e,n,a,s,o,u,c,f,l,y="user"){e.evictIdleSessions();const t=qe(a);if(!t)throw new Error(`Unsupported agent: ${a}`);const r=s==="manager"&&a!=="manager"?new $e(t,a):t;L(r,n,a,c,f,null,l,e.managedRoomExecutor),y==="internal"?await r.start(n,o,u,{nativeSessionVisibility:y}):await r.start(n,o,u);const k={adapter:r,workDir:o,agentType:a,sessionMode:s,nativeSessionVisibility:y,agentSessionId:u??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:c??null,externalReplyTarget:f??null,externalChannelEnv:{...ke(a),..._e(n,c,f)},managedRoomContextToken:null,journalRunId:null};return e.sessions.set(n,k),Ze(e,n,a,r),k}async function vn(e,n,a=()=>{}){let s=null,o=null,u=null,c;if(n.source==="managed_room"||n.source==="managed_direct"){const l=await e.prepareManagedRecovery?.(n);if(!l)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery requires a fresh permission context"};if(l.agentType!==n.agentType||l.sessionMode!==n.sessionMode||e.resolvePath(l.workDir)!==e.resolvePath(n.workDir)||l.managedRoomPromptSnapshot.managedRoomPolicyVersion!==n.managedPolicyVersion||l.managedRoomPromptSnapshot.runtimePermissionPolicyHash!==n.managedRuntimePolicyHash)return e.revokeManagedRoomContextToken?.(l.managedRoomContextToken),{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery authority no longer matches the interrupted run"};const y={source:"room_activation",managedAgentPolicy:l.managedAgentPolicy,managedRoomPromptSnapshot:l.managedRoomPromptSnapshot};he(y,l.systemPrompt,l.managedRoomContextToken),s=l.managedAgentPolicy,o=l.managedRoomContextToken,u=l.systemPrompt,c={...y,recovery:"upgrade"}}else if(n.source==="manager_worker"){const l=n.parentSessionId;if(s=l?e.managerRuntime?.getManagedAgentPolicyForWorker(l,n.workDir)??null:null,!s)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker recovery requires the current parent policy"};if(C("sha256").update(JSON.stringify({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement})).digest("hex")!==n.managedRuntimePolicyHash)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker policy changed after interruption"};u=Ie({requestedPolicy:s.requestedPolicy,enforcement:s.enforcement,resolvedWorkDir:s.adapterPolicy.workDir})}c??={source:"upgrade_recovery",recovery:"upgrade"};let f=e.sessions.get(n.sessionId);return f||(f=await Ae(e,n.sessionId,n.agentType,n.sessionMode,n.workDir,n.agentSessionId,null,null,s,n.nativeSessionVisibility)),o&&(re(e,f,o),L(f.adapter,n.sessionId,n.agentType,null,null,o,s,e.managedRoomExecutor)),f.journalRunId=n.runId,f.currentRunId=n.providerRunId??`recovery:${n.runId}`,f.currentRunPhase="thinking",n.agentType==="codex"&&n.deliveryMode==="external_owner_queue"&&n.agentSessionId&&n.externalRunId&&e.nativeFusion?.restoreExternalObservation({sessionId:n.sessionId,sourceSessionKey:n.agentSessionId,runId:n.externalRunId,canonicalMessageId:n.clientMessageId,createdAt:Date.parse(n.createdAt)})?{result:"reattached"}:f.adapter.recoverInterruptedRun({sessionId:n.sessionId,shennianRunId:n.runId,workDir:n.workDir,agentSessionId:n.agentSessionId,modelId:n.modelId,reasoningEffort:n.reasoningEffort,providerRunId:n.providerRunId,lastObservedEventSeq:n.lastObservedEventSeq,continueDispatchState:n.continueDispatchState,systemPrompt:u,sendContext:c,beforeContinueDispatch:a})}function tn(e,n){const a=e.sessions.get(n),s=a?.currentRunId;if(!a||!s)return;const o=a.nextEventSeq;e.runTextAcc.delete(`${n}:${s}`),N(e,a),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),a.journalRunId&&(e.runJournal?.remove(n,a.journalRunId),e.recoveryBarrier?.end(n),a.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function An(e,n,a){const s=a?n.params.managedRoomContextToken??null:null;let o=!1;try{await an(e,n,a,()=>{o=!0})}finally{s&&!o&&e.revokeManagedRoomContextToken?.(s)}}async function an(e,n,a,s){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:o,text:u,agentType:c,sessionMode:f,managerConfig:l,workDir:y,agentSessionId:t,modelId:r,systemPrompt:k,managerDefaultWorkerAgentType:x,managerDefaultWorkerModelId:P,reasoningEffort:_,clientMessageId:F,sessionListProjection:I,waitForDispatch:Q,responseId:xe,managedRoomContextToken:O,suppressExternalOwnerEcho:Pe,queuedBatchItems:G,managedWorkerParentSessionId:E,managedRecoverySource:Me}=n.params,h=xe||n.id;We(I);const z=null,X="";if(a?.source==="room_activation"&&(he(a,k,O),c==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(en(e,n.id),!o||!u){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(o)&&await e.recoveryBarrier.wait(o);const p=c,b=p==="manager"||f==="manager"?"manager":"standard";b==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(o,x??null,P??null);const W=(p==="claude"||p==="codex"||p==="workbuddy"||p==="pi-coding-agent"||p.startsWith("acp:"))&&typeof _=="string"&&_.trim()?_.trim():void 0,v=e.resolvePath(Ye(p,y||fe.homedir(),t)||fe.homedir()),A=a?.managedAgentPolicy??(E?e.managerRuntime?.getManagedAgentPolicyForWorker(E,v)??null:null);if(E&&!A)throw new Error("managed_worker_permission_context_unavailable");const Y=p==="codex"&&(a?.source==="room_activation"||E)?"internal":"user",Z=E&&A?Ie({requestedPolicy:A.requestedPolicy,enforcement:A.enforcement,resolvedWorkDir:A.adapterPolicy.workDir}):k,Ee=v,V=Je(n.params.attachments);V?.length&&Be(v,V);const S={text:u,attachments:V,localized:!1};let d=e.sessions.get(o);if(d){if(d.lastActiveAt=Date.now(),d.agentType!==p||(d.sessionMode??(d.agentType==="manager"?"manager":"standard"))!==b||d.workDir!==v||(d.nativeSessionVisibility??"user")!==Y||JSON.stringify(d.externalChannel??null)!==JSON.stringify(z??null)){e.sessions.delete(o);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}else if(t&&d.agentSessionId!==t)try{await d.adapter.resume(t),d.agentSessionId=t}catch{e.sessions.delete(o);try{await K(e,d)}catch{e.processedReqIds.delete(n.id)}d=void 0}}if(!d)try{d=await Ae(e,o,p,b,v,t,z,X,A,Y)}catch(i){const m=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${c}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${o} agentType=${c} workDir=${v} agentSessionId=${t??""}: ${m}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:m,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:m});return}const R={id:F??`user-${n.id}`,sessionId:o,role:"user",ts:Date.now(),payload:me(S.text,S.attachments)},se=Array.isArray(G)&&G.length>0?G.map(i=>({id:i.clientMessageId??i.id,sessionId:o,role:"user",ts:Date.parse(i.createdAt),payload:me(i.text,i.attachments)})):null,H=se??[R],M=Oe(o,R.id),ie=M.state==="queued";if(M.state!=="not_found"&&!ie){e.client.sendRes({type:"res",id:h,ok:!0,payload:M});return}if(Q){a?.source==="room_activation"&&L(d.adapter,o,p,z,X,O,a.managedAgentPolicy,e.managedRoomExecutor);try{await nn(d.adapter,S.text,r,W,S.attachments,Z,a?{source:a.source}:void 0)}catch(i){e.processedReqIds.delete(n.id),e.sessions.delete(o),await K(e,d),e.client.sendRes({type:"res",id:h,ok:!1,error:i instanceof Error?i.message:String(i)});return}}$({level:"info",sessionId:o,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:p,sessionMode:b,managerConfig:l??null,modelId:r,managerDefaultWorkerAgentType:x??null,managerDefaultWorkerModelId:P??null,reasoningEffort:W,...a?.source==="room_activation"?{managedRoomPromptSnapshot:a.managedRoomPromptSnapshot}:{}}});const J=(i,m)=>({...ye(oe()),sessionId:o,clientMessageId:R.id,messageId:R.id,deliveryState:i,bodyRevision:m,committedAt:new Date(R.ts).toISOString()}),ee=i=>{e.nativeFusion?.registerManagedSend({sessionId:o,agentType:p,sourceAgentType:we(p,r),canonicalMessageId:R.id,sourceSessionKey:d.agentSessionId??t??null,text:S.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"&&!Pe?"import_following":"suppress_following",externalRunId:i?.deliveryMode==="external_owner_queue"?`codex-external-${i.queuedSubmissionId??R.id}`:null})},de=()=>{d.currentRunId||(d.currentRunId=`dispatch:${n.id}`,d.currentRunPhase="thinking",d.nextEventSeq=0)},le=()=>{if(!e.runJournal||d.journalRunId)return;const i=`run:${be()}`;e.runJournal.begin({daemonInstallationId:oe(),sessionId:o,runId:i,clientMessageId:R.id,agentType:p,sessionMode:b,workDir:v,agentSessionId:d.agentSessionId??t??null,modelId:r??null,reasoningEffort:W??null,nativeSessionVisibility:Y,providerRunId:null,source:a?.source==="room_activation"?Me==="managed_direct"?"managed_direct":"managed_room":E?"manager_worker":"personal",parentSessionId:E??null,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:a?.managedRoomPromptSnapshot.managedRoomPolicyVersion??null,managedRuntimePolicyHash:a?.managedRoomPromptSnapshot.runtimePermissionPolicyHash??(A?C("sha256").update(JSON.stringify({requestedPolicy:A.requestedPolicy,enforcement:A.enforcement})).digest("hex"):null)}),d.journalRunId=i},ue=()=>{if(ee(),ie)return{...ye(oe()),sessionId:o,clientMessageId:M.clientMessageId,messageId:M.messageId,deliveryState:M.deliveryState,bodyRevision:M.bodyRevision,committedAt:M.committedAt};try{Xe(e,{sessionId:o,agentType:p,sessionMode:b,managerConfig:l??null,workDir:Ee,agentSessionId:d.agentSessionId??t??null,modelId:r,managerDefaultWorkerAgentType:x??null,managerDefaultWorkerModelId:P??null});let i=0;for(const[m,g]of H.entries()){const T=se?D(o,g,"committed"):j(o,g,"committed");m===0&&(i=T)}return Ne(v,V??[]),w(e.client),J("committed",i)}catch(i){throw e.nativeFusion?.cancelManagedSend?.(R.id),i}},ce=i=>{d.journalRunId&&e.runJournal?.update(o,d.journalRunId,{deliveryMode:i?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:i?.deliveryMode==="external_owner_queue"?`codex-external-${i.queuedSubmissionId??R.id}`:null})},ge=i=>{d.currentRunId||(d.nextEventSeq=0),ce(i),ee(i);const m=i?.deliveryMode==="external_owner_queue"?"queued":"executing";let g=0;for(const[T,B]of H.entries()){const q=D(o,B,m);T===0&&(g=q)}return w(e.client),J(m,g)},ne=async(i,m)=>{e.nativeFusion?.cancelManagedSend?.(R.id);const g=Se(p,i);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${o} agentType=${c} workDir=${v} agentSessionId=${d.agentSessionId??t??""}: ${g}`),d.adapter.hasPendingAuthenticationRetry?.()===!0){m&&e.client.sendRes({type:"res",id:h,ok:!0,payload:J("queued",0)});return}e.sessions.delete(o),d.journalRunId&&(e.runJournal?.update(o,d.journalRunId,{phase:"terminal"}),e.runJournal?.remove(o,d.journalRunId),e.recoveryBarrier?.end(o),d.journalRunId=null);try{await K(e,d)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:g,runId:"",seq:0}}),!m){const B={id:`agent-error-${n.id}-${Date.now()}`,sessionId:o,role:"agent",ts:Date.now(),payload:g};j(o,B),w(e.client)}m&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:g}))};if(Q){try{ue()}catch(g){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:`Durable message commit failed: ${g instanceof Error?g.message:String(g)}`});return}de(),le();let i;try{a?.source==="room_activation"&&(re(e,d,O),s());const g=S.attachments;i=await ve(d.adapter,S.text,r,W,g,Z,a?{source:a.source}:void 0),$({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(g){if(d.adapter.hasPendingAuthenticationRetry?.()){let q=0;for(const[te,ae]of H.entries()){const De=D(o,ae,"queued");te===0&&(q=De)}w(e.client),await ne(g,!1),e.client.sendRes({type:"res",id:h,ok:!0,payload:J("queued",q)});return}let T=0;for(const[q,te]of H.entries()){const ae=D(o,te,"failed");q===0&&(T=ae)}w(e.client);const B=Se(p,g);await ne(g,!1),e.client.sendRes({type:"res",id:h,ok:!0,payload:{...J("failed",T),failureMessage:B}});return}const m=ge(i??void 0);e.client.sendRes({type:"res",id:h,ok:!0,payload:{...m,...S.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}),$({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let pe;try{pe=ue()}catch(i){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:h,ok:!1,error:`Durable message commit failed: ${i instanceof Error?i.message:String(i)}`});return}de(),le(),a?.source==="room_activation"&&(L(d.adapter,o,p,z,X,O,a.managedAgentPolicy,e.managedRoomExecutor),re(e,d,O),s()),ge(),e.client.sendRes({type:"res",id:h,ok:!0,payload:{...pe,...S.localized?{localizedAttachments:!0}:{}}}),$({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Te=S.attachments;ve(d.adapter,S.text,r,W,Te,Z,a?{source:a.source}:void 0).then(i=>{if(i?.deliveryMode==="external_owner_queue"){ce(i),ee(i);for(const m of H)D(o,m,"queued");w(e.client)}$({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(i=>{D(o,R,d.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),w(e.client),ne(i,!1)})}async function xn(e,n){const{sessionId:a}=n.params,s=e.sessions.get(a);if(s){s.journalRunId&&e.runJournal?.markAborted(a,s.journalRunId),N(e,s);try{await s.adapter.stop()}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}tn(e,a),e.activityPublisher?.publish(a,null)}e.client.sendRes({type:"res",id:n.id,ok:!0})}export{xn as handleChatAbort,An as handleChatSend,vn as recoverJournaledRun,Xe as sendSessionUpdateEvent};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isAvailableAgentType as S}from"@shennian/wire";const w=/^[A-Za-z0-9_.:@/-]{1,191}$/,f=new Set(["roomId","agentIdentityId","nianSessionId","assignmentIntentId","agentType"]),R=new Set(["roomId","bindingId","agentIdentityId","previousNianSessionId","nianSessionId","assignmentIntentId","agentType"]);async function T(e,t,n){if(!t)throw new Error("Managed Room binding is unavailable.");if(Object.keys(n.params).some(
|
|
1
|
+
import{isAvailableAgentType as S}from"@shennian/wire";const w=/^[A-Za-z0-9_.:@/-]{1,191}$/,f=new Set(["roomId","agentIdentityId","nianSessionId","assignmentIntentId","agentType"]),R=new Set(["roomId","bindingId","agentIdentityId","previousNianSessionId","nianSessionId","assignmentIntentId","agentType"]);async function T(e,t,n){if(!t)throw new Error("Managed Room binding is unavailable.");if(Object.keys(n.params).some(g=>!f.has(g)))throw new Error("Managed Room binding contains unsupported parameters.");const d=s(n.params.roomId,"roomId"),r=s(n.params.agentIdentityId,"agentIdentityId"),a=s(n.params.nianSessionId,"nianSessionId"),o=s(n.params.assignmentIntentId,"assignmentIntentId"),i=m(n.params.agentType);await c(e,a);const I=await t.bind({roomId:d,agentIdentityId:r,nianSessionId:a,assignmentIntentId:o,sourceSessionKey:p(a),agentType:i});e.client.sendRes({type:"res",id:n.id,ok:!0,payload:I})}async function b(e,t,n){if(!t)throw new Error("Managed Room binding is unavailable.");if(Object.keys(n.params).some(u=>!R.has(u)))throw new Error("Managed Room restart contains unsupported parameters.");const d=s(n.params.roomId,"roomId"),r=s(n.params.bindingId,"bindingId"),a=s(n.params.agentIdentityId,"agentIdentityId"),o=s(n.params.previousNianSessionId,"previousNianSessionId"),i=s(n.params.nianSessionId,"nianSessionId"),I=s(n.params.assignmentIntentId,"assignmentIntentId"),g=m(n.params.agentType);if(e.sessions.get(o)?.currentRunId||(e.chatQueue?.getSnapshot(o).pending.length??0)>0)throw new Error("managed_agent_active_turn");await c(e,i);const y=await t.restart({roomId:d,bindingId:r,agentIdentityId:a,previousNianSessionId:o,nianSessionId:i,assignmentIntentId:I,sourceSessionKey:p(i),agentType:g});e.client.sendRes({type:"res",id:n.id,ok:!0,payload:y})}function s(e,t){if(typeof e!="string"||!w.test(e))throw new Error(`Invalid ${t}.`);return e}function m(e){if(typeof e!="string"||!S(e)||e==="manager"||e==="pi"||e==="openclaw")throw new Error("managed_agent_runtime_unsupported");return e}function p(e){return`managed:${e}`}async function c(e,t){const n=e.sessions.get(t);n&&(e.sessions.delete(t),n.managedRoomContextToken&&(e.revokeManagedRoomContextToken?.(n.managedRoomContextToken),n.managedRoomContextToken=null),n.heartbeatTimer&&clearInterval(n.heartbeatTimer),n.adapter.removeAllListeners(),await n.adapter.stop())}export{T as handleManagedRoomBind,b as handleManagedRoomRestart};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RunJournalRecord } from './schema.js';
|
|
2
|
-
type JournalInput = Omit<RunJournalRecord, 'schemaVersion' | 'lastObservedEventSeq' | 'phase' | 'upgradeJobId' | 'interruptionReason' | 'continueDispatchState' | 'recoveryAttempts' | 'createdAt' | 'updatedAt' | 'recoveryReason'>;
|
|
2
|
+
type JournalInput = Omit<RunJournalRecord, 'schemaVersion' | 'lastObservedEventSeq' | 'phase' | 'upgradeJobId' | 'interruptionReason' | 'continueDispatchState' | 'recoveryAttempts' | 'createdAt' | 'updatedAt' | 'recoveryReason' | 'deliveryMode' | 'externalRunId'>;
|
|
3
3
|
export type RunJournalLoadResult = {
|
|
4
4
|
records: RunJournalRecord[];
|
|
5
5
|
quarantined: string[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import n from"node:fs";import s from"node:path";import{createHash as p,randomUUID as u}from"node:crypto";import{resolveShennianPath as S}from"../../config/index.js";import{RUN_JOURNAL_SCHEMA_VERSION as w,isRecoverableJournalPhase as y,parseRunJournalRecord as h}from"./schema.js";function f(a,t){return p("sha256").update(`${a}\0${t}`).digest("hex")+".json"}function c(a){try{const t=n.lstatSync(a);if(t.isSymbolicLink()||!t.isFile())throw new Error("journal target is not a regular file")}catch(t){if(t.code!=="ENOENT")throw t}}function l(a){if(process.platform==="win32")return;const t=n.openSync(a,"r");try{n.fsyncSync(t)}finally{n.closeSync(t)}}function m(a){for(let t=0;t<3;t+=1){n.mkdirSync(a,{recursive:!0,mode:448});try{const r=n.lstatSync(a);if(r.isSymbolicLink()||!r.isDirectory())throw new Error("journal directory is unsafe");process.platform!=="win32"&&n.chmodSync(a,448);return}catch(r){if(r.code!=="ENOENT"||t===2)throw r}}}class
|
|
2
|
-
`,{encoding:"utf8",mode:384,flag:"wx"}),process.platform!=="win32"&&n.chmodSync(o,384);const i=n.openSync(o,process.platform==="win32"?"r+":"r");try{n.fsyncSync(i)}finally{n.closeSync(i)}n.renameSync(o,e),l(this.directory)}finally{try{n.unlinkSync(o)}catch{}}}quarantine(t){const r=s.join(this.quarantineDirectory,`${s.basename(t)}.${Date.now()}.${u()}.invalid`);try{return c(t),n.renameSync(t,r),process.platform!=="win32"&&n.chmodSync(r,384),l(this.quarantineDirectory),r}catch{return t}}}export{
|
|
1
|
+
import n from"node:fs";import s from"node:path";import{createHash as p,randomUUID as u}from"node:crypto";import{resolveShennianPath as S}from"../../config/index.js";import{RUN_JOURNAL_SCHEMA_VERSION as w,isRecoverableJournalPhase as y,parseRunJournalRecord as h}from"./schema.js";function f(a,t){return p("sha256").update(`${a}\0${t}`).digest("hex")+".json"}function c(a){try{const t=n.lstatSync(a);if(t.isSymbolicLink()||!t.isFile())throw new Error("journal target is not a regular file")}catch(t){if(t.code!=="ENOENT")throw t}}function l(a){if(process.platform==="win32")return;const t=n.openSync(a,"r");try{n.fsyncSync(t)}finally{n.closeSync(t)}}function m(a){for(let t=0;t<3;t+=1){n.mkdirSync(a,{recursive:!0,mode:448});try{const r=n.lstatSync(a);if(r.isSymbolicLink()||!r.isDirectory())throw new Error("journal directory is unsafe");process.platform!=="win32"&&n.chmodSync(a,448);return}catch(r){if(r.code!=="ENOENT"||t===2)throw r}}}class R{daemonInstallationId;directory;quarantineDirectory;constructor(t,r={}){this.daemonInstallationId=t,this.directory=r.directory??S("runtime","run-recovery","active"),this.quarantineDirectory=s.join(s.dirname(this.directory),"quarantine"),m(this.directory),m(this.quarantineDirectory)}begin(t){const r=new Date().toISOString(),e={...t,schemaVersion:w,lastObservedEventSeq:-1,phase:"dispatching",upgradeJobId:null,interruptionReason:null,continueDispatchState:"none",deliveryMode:"direct",externalRunId:null,recoveryAttempts:0,recoveryReason:null,createdAt:r,updatedAt:r};return this.write(e),e}update(t,r,e){const o=this.get(t,r);if(!o)return null;const i=h({...o,...e,updatedAt:new Date().toISOString()});return this.write(i),i}get(t,r){const e=this.recordPath(t,r);try{c(e);const o=h(JSON.parse(n.readFileSync(e,"utf8")));if(o.sessionId!==t||o.runId!==r)throw new Error("journal identity mismatch");return o}catch(o){return o.code==="ENOENT"||this.quarantine(e),null}}loadRecoverable(){return this.load(t=>y(t.phase))}loadPendingReconciliation(){return this.load(t=>y(t.phase)||t.phase==="interrupted_by_upgrade"||t.phase==="recovery_failed"||t.phase==="aborted")}load(t){const r=[],e=[];for(const o of n.readdirSync(this.directory)){if(!o.endsWith(".json"))continue;const i=s.join(this.directory,o);try{c(i);const d=h(JSON.parse(n.readFileSync(i,"utf8")));if(d.daemonInstallationId!==this.daemonInstallationId)throw new Error("daemon installation identity mismatch");if(f(d.sessionId,d.runId)!==o)throw new Error("journal filename identity mismatch");t(d)&&r.push(d)}catch{e.push(this.quarantine(i))}}return r.sort((o,i)=>o.createdAt.localeCompare(i.createdAt)),{records:r,quarantined:e}}markPlannedUpgrade(t){const{records:r}=this.loadRecoverable();for(const e of r)this.update(e.sessionId,e.runId,{upgradeJobId:t,interruptionReason:"planned_upgrade"});return l(this.directory),r.length}markAborted(t,r){this.update(t,r,{phase:"aborted"})}markSessionAborted(t){const r=this.loadRecoverable().records.filter(e=>e.sessionId===t);for(const e of r)this.markAborted(e.sessionId,e.runId);return this.sync(),r.length}remove(t,r){const e=this.recordPath(t,r);c(e);try{n.unlinkSync(e)}catch(o){if(o.code!=="ENOENT")throw o}l(this.directory)}sync(){for(const t of n.readdirSync(this.directory)){if(!t.endsWith(".json"))continue;const r=s.join(this.directory,t);c(r);const e=n.openSync(r,process.platform==="win32"?"r+":"r");try{n.fsyncSync(e)}finally{n.closeSync(e)}}l(this.directory)}recordPath(t,r){return s.join(this.directory,f(t,r))}write(t){if(t.daemonInstallationId!==this.daemonInstallationId)throw new Error("daemon installation identity mismatch");const r=h(t),e=this.recordPath(r.sessionId,r.runId);c(e);const o=`${e}.tmp-${process.pid}-${u()}`;try{n.writeFileSync(o,`${JSON.stringify(r,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"}),process.platform!=="win32"&&n.chmodSync(o,384);const i=n.openSync(o,process.platform==="win32"?"r+":"r");try{n.fsyncSync(i)}finally{n.closeSync(i)}n.renameSync(o,e),l(this.directory)}finally{try{n.unlinkSync(o)}catch{}}}quarantine(t){const r=s.join(this.quarantineDirectory,`${s.basename(t)}.${Date.now()}.${u()}.invalid`);try{return c(t),n.renameSync(t,r),process.platform!=="win32"&&n.chmodSync(r,384),l(this.quarantineDirectory),r}catch{return t}}}export{R as ActiveRunJournal};
|
|
@@ -4,6 +4,7 @@ export declare const RECOVERY_CONTINUE_TEXT: "Continue.";
|
|
|
4
4
|
export type RunJournalPhase = 'dispatching' | 'running' | 'waiting_approval' | 'recovering' | 'terminal' | 'interrupted_by_upgrade' | 'recovery_failed' | 'aborted';
|
|
5
5
|
export type RunRecoverySource = 'personal' | 'managed_room' | 'managed_direct' | 'manager_worker';
|
|
6
6
|
export type ContinueDispatchState = 'none' | 'intent' | 'accepted';
|
|
7
|
+
export type RunDeliveryMode = 'direct' | 'external_owner_queue';
|
|
7
8
|
export type RunJournalRecord = {
|
|
8
9
|
schemaVersion: typeof RUN_JOURNAL_SCHEMA_VERSION;
|
|
9
10
|
daemonInstallationId: string;
|
|
@@ -32,6 +33,8 @@ export type RunJournalRecord = {
|
|
|
32
33
|
upgradeJobId: string | null;
|
|
33
34
|
interruptionReason: 'daemon_crash' | 'planned_upgrade' | 'os_restart' | null;
|
|
34
35
|
continueDispatchState: ContinueDispatchState;
|
|
36
|
+
deliveryMode: RunDeliveryMode;
|
|
37
|
+
externalRunId: string | null;
|
|
35
38
|
recoveryAttempts: number;
|
|
36
39
|
/** Non-sensitive stable reason used to replay a pending terminal commit. */
|
|
37
40
|
recoveryReason?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isAvailableAgentType as d}from"@shennian/wire";const a=1,m="Continue.",
|
|
1
|
+
import{isAvailableAgentType as d}from"@shennian/wire";const a=1,m="Continue.",u=new Set(["dispatching","running","waiting_approval","recovering","terminal","interrupted_by_upgrade","recovery_failed","aborted"]),c=new Set(["personal","managed_room","managed_direct","manager_worker"]),l=new Set(["none","intent","accepted"]),p=new Set(["standard","manager"]);function t(n,e){if(typeof n!="string"||!n.trim())throw new Error(`invalid ${e}`);return n}function r(n,e){if(n==null)return null;if(typeof n!="string"||!n.trim())throw new Error(`invalid ${e}`);return n}function s(n,e){const o=t(n,e);if(!Number.isFinite(Date.parse(o)))throw new Error(`invalid ${e}`);return o}function v(n){if(!n||typeof n!="object"||Array.isArray(n))throw new Error("invalid run journal record");const e=n;if(e.schemaVersion!==a)throw new Error(`unsupported run journal schema: ${String(e.schemaVersion)}`);const o=t(e.agentType,"agentType");if(!d(o))throw new Error("invalid agentType");if(!u.has(e.phase))throw new Error("invalid phase");if(!c.has(e.source))throw new Error("invalid source");if(!l.has(e.continueDispatchState))throw new Error("invalid continueDispatchState");if(e.deliveryMode!=null&&e.deliveryMode!=="direct"&&e.deliveryMode!=="external_owner_queue")throw new Error("invalid deliveryMode");if(!p.has(e.sessionMode))throw new Error("invalid sessionMode");if(!Number.isSafeInteger(e.lastObservedEventSeq)||Number(e.lastObservedEventSeq)<-1)throw new Error("invalid lastObservedEventSeq");if(!Number.isSafeInteger(e.recoveryAttempts)||Number(e.recoveryAttempts)<0)throw new Error("invalid recoveryAttempts");if(e.activationHopCount!=null&&(!Number.isSafeInteger(e.activationHopCount)||Number(e.activationHopCount)<0))throw new Error("invalid activationHopCount");if(e.source==="managed_room"&&(!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount==null||!e.managedPolicyVersion||!e.managedRuntimePolicyHash))throw new Error("managed room recovery identity is incomplete");if(e.source==="manager_worker"&&(!e.parentSessionId||!e.managedRuntimePolicyHash))throw new Error("manager worker recovery identity is incomplete");const i=e.interruptionReason;if(i!=null&&i!=="daemon_crash"&&i!=="planned_upgrade"&&i!=="os_restart")throw new Error("invalid interruptionReason");return{schemaVersion:a,daemonInstallationId:t(e.daemonInstallationId,"daemonInstallationId"),sessionId:t(e.sessionId,"sessionId"),runId:t(e.runId,"runId"),clientMessageId:t(e.clientMessageId,"clientMessageId"),agentType:o,sessionMode:e.sessionMode,workDir:t(e.workDir,"workDir"),agentSessionId:r(e.agentSessionId,"agentSessionId"),modelId:r(e.modelId,"modelId"),reasoningEffort:r(e.reasoningEffort,"reasoningEffort"),nativeSessionVisibility:e.nativeSessionVisibility==="internal"?"internal":"user",providerRunId:r(e.providerRunId,"providerRunId"),lastObservedEventSeq:Number(e.lastObservedEventSeq),phase:e.phase,source:e.source,parentSessionId:r(e.parentSessionId,"parentSessionId"),roomContextRegistryKey:r(e.roomContextRegistryKey,"roomContextRegistryKey"),activationCauseMessageId:r(e.activationCauseMessageId,"activationCauseMessageId"),rootCauseMessageId:r(e.rootCauseMessageId,"rootCauseMessageId"),activationSequence:r(e.activationSequence,"activationSequence"),activationHopCount:e.activationHopCount==null?null:Number(e.activationHopCount),managedPolicyVersion:r(e.managedPolicyVersion,"managedPolicyVersion"),managedRuntimePolicyHash:r(e.managedRuntimePolicyHash,"managedRuntimePolicyHash"),upgradeJobId:r(e.upgradeJobId,"upgradeJobId"),interruptionReason:i,continueDispatchState:e.continueDispatchState,deliveryMode:e.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:r(e.externalRunId,"externalRunId"),recoveryAttempts:Number(e.recoveryAttempts),recoveryReason:r(e.recoveryReason,"recoveryReason"),createdAt:s(e.createdAt,"createdAt"),updatedAt:s(e.updatedAt,"updatedAt")}}function y(n){return n==="dispatching"||n==="running"||n==="waiting_approval"||n==="recovering"}export{m as RECOVERY_CONTINUE_TEXT,a as RUN_JOURNAL_SCHEMA_VERSION,y as isRecoverableJournalPhase,v as parseRunJournalRecord};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentType, ManagerConfig, SessionMode } from './session.ts';
|
|
2
2
|
import type { AgentRepairAction, AgentRuntimeAvailability, RoomActivationMode } from './room.ts';
|
|
3
3
|
export declare const MANAGED_AGENT_PERMISSION_POLICY_VERSION = 1;
|
|
4
|
+
export type ManagedAgentExecutionMode = 'native-full' | 'restricted';
|
|
4
5
|
export type ManagedAgentFileAccess = 'workspace-read' | 'workspace-write' | 'host-full';
|
|
5
6
|
export type ManagedAgentExternalCapabilities = {
|
|
6
7
|
commandNetwork: boolean;
|
|
@@ -12,6 +13,8 @@ export type ManagedAgentExternalCapabilities = {
|
|
|
12
13
|
export type ManagedAgentPermissionPolicy = {
|
|
13
14
|
/** Monotonic AgentIdentity policy revision, owned by the server. */
|
|
14
15
|
version: number;
|
|
16
|
+
/** Optional on the wire only for clients released before execution modes. */
|
|
17
|
+
executionMode?: ManagedAgentExecutionMode;
|
|
15
18
|
fileAccess: ManagedAgentFileAccess;
|
|
16
19
|
externalCapabilities: ManagedAgentExternalCapabilities;
|
|
17
20
|
};
|
|
@@ -44,6 +47,8 @@ export type ManagedAgentPermissionConfirmationRequest = {
|
|
|
44
47
|
runtimeVersion: string;
|
|
45
48
|
platform: string;
|
|
46
49
|
executableFingerprint: string;
|
|
50
|
+
/** Missing values belong to confirmations created before execution modes. */
|
|
51
|
+
executionMode?: ManagedAgentExecutionMode;
|
|
47
52
|
hostFullAccess: boolean;
|
|
48
53
|
limitedProtection: boolean;
|
|
49
54
|
};
|
|
@@ -53,6 +58,10 @@ export type ManagedAgentPermissionConfirmation = ManagedAgentPermissionConfirmat
|
|
|
53
58
|
confirmedAt: string;
|
|
54
59
|
};
|
|
55
60
|
export declare const DEFAULT_MANAGED_AGENT_PERMISSION_POLICY: ManagedAgentPermissionPolicy;
|
|
61
|
+
/** Explicit default sent by current creation surfaces; omission remains restricted. */
|
|
62
|
+
export declare const DEFAULT_NATIVE_FULL_MANAGED_AGENT_PERMISSION_POLICY: ManagedAgentPermissionPolicy;
|
|
63
|
+
/** Named alias used where the old-client fallback must be obvious at the call site. */
|
|
64
|
+
export declare const DEFAULT_RESTRICTED_MANAGED_AGENT_PERMISSION_POLICY: ManagedAgentPermissionPolicy;
|
|
56
65
|
/**
|
|
57
66
|
* Compatibility projection for payloads created before managed permissions existed.
|
|
58
67
|
* Missing policy data must never be presented as if a restrictive sandbox were active.
|
|
@@ -65,6 +74,7 @@ export declare const LEGACY_MANAGED_AGENT_PERMISSION_POLICY: ManagedAgentPermiss
|
|
|
65
74
|
export declare function resolveManagedAgentEffectivePermissionPolicy(requested: ManagedAgentPermissionPolicy, protection?: ManagedAgentRuntimeProtection | null): ManagedAgentPermissionPolicy;
|
|
66
75
|
/** Strictly parse an explicit policy. Invalid or incomplete values are not silently repaired. */
|
|
67
76
|
export declare function parseManagedAgentPermissionPolicy(value: unknown): ManagedAgentPermissionPolicy | null;
|
|
77
|
+
export declare function managedAgentExecutionMode(policy: ManagedAgentPermissionPolicy): ManagedAgentExecutionMode;
|
|
68
78
|
export declare function resolveManagedAgentPermissionPolicy(value: unknown, fallback?: 'default' | 'legacy'): ManagedAgentPermissionPolicy;
|
|
69
79
|
export type AgentWorkspaceRoomLink = {
|
|
70
80
|
bindingId: string;
|
|
@@ -90,6 +100,8 @@ export type AgentWorkspaceSession = {
|
|
|
90
100
|
};
|
|
91
101
|
export type AgentWorkspace = {
|
|
92
102
|
id: string;
|
|
103
|
+
/** Monotonic server-owned revision of the complete managed Agent configuration. */
|
|
104
|
+
configurationVersion?: number;
|
|
93
105
|
displayName: string;
|
|
94
106
|
description: string;
|
|
95
107
|
systemPrompt: string;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
export const MANAGED_AGENT_PERMISSION_POLICY_VERSION = 1;
|
|
4
4
|
export const DEFAULT_MANAGED_AGENT_PERMISSION_POLICY = {
|
|
5
5
|
version: MANAGED_AGENT_PERMISSION_POLICY_VERSION,
|
|
6
|
+
executionMode: 'restricted',
|
|
6
7
|
fileAccess: 'workspace-read',
|
|
7
8
|
externalCapabilities: {
|
|
8
9
|
commandNetwork: false,
|
|
@@ -12,12 +13,28 @@ export const DEFAULT_MANAGED_AGENT_PERMISSION_POLICY = {
|
|
|
12
13
|
mcp: false,
|
|
13
14
|
},
|
|
14
15
|
};
|
|
16
|
+
/** Explicit default sent by current creation surfaces; omission remains restricted. */
|
|
17
|
+
export const DEFAULT_NATIVE_FULL_MANAGED_AGENT_PERMISSION_POLICY = {
|
|
18
|
+
version: MANAGED_AGENT_PERMISSION_POLICY_VERSION,
|
|
19
|
+
executionMode: 'native-full',
|
|
20
|
+
fileAccess: 'host-full',
|
|
21
|
+
externalCapabilities: {
|
|
22
|
+
commandNetwork: true,
|
|
23
|
+
webSearch: true,
|
|
24
|
+
browser: true,
|
|
25
|
+
computerUse: true,
|
|
26
|
+
mcp: true,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
/** Named alias used where the old-client fallback must be obvious at the call site. */
|
|
30
|
+
export const DEFAULT_RESTRICTED_MANAGED_AGENT_PERMISSION_POLICY = DEFAULT_MANAGED_AGENT_PERMISSION_POLICY;
|
|
15
31
|
/**
|
|
16
32
|
* Compatibility projection for payloads created before managed permissions existed.
|
|
17
33
|
* Missing policy data must never be presented as if a restrictive sandbox were active.
|
|
18
34
|
*/
|
|
19
35
|
export const LEGACY_MANAGED_AGENT_PERMISSION_POLICY = {
|
|
20
36
|
version: MANAGED_AGENT_PERMISSION_POLICY_VERSION,
|
|
37
|
+
executionMode: 'restricted',
|
|
21
38
|
fileAccess: 'host-full',
|
|
22
39
|
externalCapabilities: {
|
|
23
40
|
commandNetwork: true,
|
|
@@ -36,6 +53,7 @@ export function resolveManagedAgentEffectivePermissionPolicy(requested, protecti
|
|
|
36
53
|
if (!matrix) {
|
|
37
54
|
return {
|
|
38
55
|
version: requested.version,
|
|
56
|
+
executionMode: requested.executionMode ?? 'restricted',
|
|
39
57
|
fileAccess: 'host-full',
|
|
40
58
|
externalCapabilities: {
|
|
41
59
|
commandNetwork: true,
|
|
@@ -57,7 +75,12 @@ export function resolveManagedAgentEffectivePermissionPolicy(requested, protecti
|
|
|
57
75
|
externalCapabilities[capability] = true;
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
|
-
return {
|
|
78
|
+
return {
|
|
79
|
+
version: requested.version,
|
|
80
|
+
executionMode: requested.executionMode ?? 'restricted',
|
|
81
|
+
fileAccess,
|
|
82
|
+
externalCapabilities,
|
|
83
|
+
};
|
|
61
84
|
}
|
|
62
85
|
function copyManagedAgentPermissionPolicy(policy) {
|
|
63
86
|
return {
|
|
@@ -72,6 +95,11 @@ export function parseManagedAgentPermissionPolicy(value) {
|
|
|
72
95
|
const policy = value;
|
|
73
96
|
if (!Number.isSafeInteger(policy.version) || Number(policy.version) < 1)
|
|
74
97
|
return null;
|
|
98
|
+
if (policy.executionMode !== undefined &&
|
|
99
|
+
policy.executionMode !== 'native-full' &&
|
|
100
|
+
policy.executionMode !== 'restricted') {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
75
103
|
if (policy.fileAccess !== 'workspace-read' &&
|
|
76
104
|
policy.fileAccess !== 'workspace-write' &&
|
|
77
105
|
policy.fileAccess !== 'host-full') {
|
|
@@ -92,6 +120,7 @@ export function parseManagedAgentPermissionPolicy(value) {
|
|
|
92
120
|
}
|
|
93
121
|
return {
|
|
94
122
|
version: Number(policy.version),
|
|
123
|
+
executionMode: policy.executionMode === 'native-full' ? 'native-full' : 'restricted',
|
|
95
124
|
fileAccess: policy.fileAccess,
|
|
96
125
|
externalCapabilities: {
|
|
97
126
|
commandNetwork: capabilities.commandNetwork,
|
|
@@ -102,6 +131,9 @@ export function parseManagedAgentPermissionPolicy(value) {
|
|
|
102
131
|
},
|
|
103
132
|
};
|
|
104
133
|
}
|
|
134
|
+
export function managedAgentExecutionMode(policy) {
|
|
135
|
+
return policy.executionMode === 'native-full' ? 'native-full' : 'restricted';
|
|
136
|
+
}
|
|
105
137
|
export function resolveManagedAgentPermissionPolicy(value, fallback = 'legacy') {
|
|
106
138
|
const parsed = parseManagedAgentPermissionPolicy(value);
|
|
107
139
|
if (parsed)
|
|
@@ -131,6 +131,8 @@ export type AgentInfo = {
|
|
|
131
131
|
catalogRevision?: string;
|
|
132
132
|
/** True when this provider can back a stable Shennian Agent and managed Room session. */
|
|
133
133
|
supportsManagedAgent?: boolean;
|
|
134
|
+
/** True when managed Rooms can reuse this provider's ordinary native full-access launch path. */
|
|
135
|
+
supportsManagedNativeFull?: boolean;
|
|
134
136
|
/** True when Manager mode can create this provider as a worker. */
|
|
135
137
|
supportsWorker?: boolean;
|
|
136
138
|
/** True only after this real provider passed Manager-mode runtime validation. */
|