workspace.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /** Application-owned identities. Hermes profile/session IDs never identify a chat. */
  2. export interface WorkspaceAgent {
  3. id: string
  4. name: string
  5. avatar: string
  6. instructions: string
  7. /** Explicit account-owner grant; absent on older records means disabled. */
  8. execution?: 'profile' | 'computer'
  9. computer?: 'auto' | 'cloud' | 'vm' | 'local' | 'browser' | 'off'
  10. allowHostEnvironment?: boolean
  11. browserProfile?: 'persistent' | 'temporary'
  12. computerEnvironmentId?:string
  13. computerEnvironmentName?:string
  14. canManageTeam?: boolean
  15. teamAuthorizationVersion?: number
  16. temporaryGoalId?:string
  17. helperActivation?:number
  18. helperRunnerId?:string
  19. retiredAt?:number
  20. cleanupState?:'pending'|'complete'
  21. createdByAgentId?: string
  22. createdFromRunId?: string
  23. nodeId: string
  24. profile: string
  25. remoteAgentId?: string
  26. archived: boolean
  27. revision: number
  28. createdAt: number
  29. updatedAt: number
  30. }
  31. export function supportsHostEnvironment(agent: Pick<WorkspaceAgent,'computer'|'execution'>):boolean {
  32. return agent.computer==='vm'||agent.computer==='cloud'||(!agent.computer&&agent.execution==='computer')
  33. }
  34. export function allowsHostEnvironment(agent: Pick<WorkspaceAgent,'computer'|'execution'|'allowHostEnvironment'|'archived'|'remoteAgentId'|'temporaryGoalId'>):boolean {
  35. return agent.allowHostEnvironment===true&&supportsHostEnvironment(agent)&&!agent.archived&&!agent.remoteAgentId&&!agent.temporaryGoalId
  36. }
  37. export interface WorkspaceMemberRole {
  38. name: string
  39. description: string
  40. }
  41. export interface WorkspaceConversation {
  42. id: string
  43. kind: 'direct' | 'group'
  44. name: string
  45. avatar: string
  46. memberIds: string[]
  47. memberRoles?: Record<string, WorkspaceMemberRole>
  48. instructions: string
  49. administratorId: string
  50. mode: 'host' | 'free'
  51. autoReplyIds: string[]
  52. maxReplyRounds: number
  53. archived: boolean
  54. pinned: boolean
  55. readSeq: number
  56. lastSeq: number
  57. lastMessageAt?: number
  58. preview: string
  59. previewAgentId?: string
  60. activeRunId?: string
  61. activeAgentId?: string
  62. activeRunStatus?: WorkspaceRun['status']
  63. activeAgentStates?: Record<string, 'running' | 'waiting' | 'uncertain' | 'queued'>
  64. avatarSignals?: Record<string, { id: string; state: 'success' | 'failure'; at: number }>
  65. queuedMessageCount?: number
  66. unread?: boolean
  67. /** Changes when new attention arrives, so an older read cannot clear it. */
  68. unreadVersion?: number
  69. /** Compatibility signal for older clients: always 0 or 1. */
  70. unreadCount?: number
  71. createdAt: number
  72. updatedAt: number
  73. }
  74. /** Shared by the HTTP lists, snapshots and Web/desktop incremental state. */
  75. export function workspaceConversationTimestamp(value: Pick<WorkspaceConversation, 'lastMessageAt' | 'createdAt'>): number {
  76. return value.lastMessageAt ?? value.createdAt
  77. }
  78. export function compareWorkspaceConversations(a: WorkspaceConversation, b: WorkspaceConversation): number {
  79. return Number(b.pinned) - Number(a.pinned)
  80. || workspaceConversationTimestamp(b) - workspaceConversationTimestamp(a)
  81. || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
  82. }
  83. export interface WorkspaceTask {
  84. id: string
  85. conversationId: string
  86. title: string
  87. titleSource: 'automatic' | 'user'
  88. messageCount: number
  89. readSeq: number
  90. lastSeq: number
  91. unread?: boolean
  92. unreadVersion?: number
  93. /** Compatibility signal for older clients: always 0 or 1. */
  94. unreadCount: number
  95. activeRunId?: string
  96. activeRunStatus?: WorkspaceRun['status']
  97. lastMessageAt?: number
  98. createdAt: number
  99. updatedAt: number
  100. goal?: import('./agentTasks.js').AgentGoal
  101. }
  102. export function workspaceHasUnread(value: { unread?: boolean; unreadCount?: number; lastSeq: number; readSeq: number }): boolean {
  103. return value.unread ?? (value.unreadCount !== undefined ? value.unreadCount > 0 : value.lastSeq > value.readSeq)
  104. }
  105. export interface WorkspaceFile {
  106. id: string
  107. name: string
  108. mimeType: string
  109. size: number
  110. createdAt: number
  111. sourcePath?: string
  112. conversationId?: string
  113. messageId?: string
  114. profile?: string
  115. sender: 'user' | 'agent'
  116. }
  117. export interface WorkspaceMessage {
  118. execution?:'profile'|'computer'
  119. id: string
  120. conversationId: string
  121. /** User-visible task scope. `taskId` below remains the scheduler turn ID. */
  122. conversationTaskId?: string
  123. seq: number
  124. role: 'user' | 'assistant' | 'system'
  125. taskReference?: { conversationId: string; taskId: string }
  126. agentId?: string
  127. agentName?: string
  128. content: string
  129. reasoning: string
  130. runId?: string
  131. taskId?: string
  132. visible?: boolean
  133. error?: string
  134. status: 'queued' | 'streaming' | 'complete' | 'failed' | 'interrupted' | 'uncertain'
  135. attachments: WorkspaceFile[]
  136. tools: Array<Record<string, unknown>>
  137. createdAt: number
  138. }
  139. export interface WorkspaceRun {
  140. id: string
  141. conversationId: string
  142. conversationTaskId?: string
  143. messageId: string
  144. mentionIds: string[]
  145. activeAgentId?: string
  146. status: 'queued' | 'running' | 'waiting' | 'complete' | 'failed' | 'interrupted' | 'uncertain'
  147. round: number
  148. error?: string
  149. stopRequested?: boolean
  150. assignmentId?: string
  151. /** Structured delivery run; ordinary chat does not carry a goal. */
  152. goalId?: string
  153. targetAgentId?: string
  154. triggerKind?: 'assignment' | 'task_review' | 'task_result'
  155. internalInstruction?: string
  156. authorizationVersion?: number
  157. createdAt: number
  158. updatedAt: number
  159. }
  160. export interface WorkspaceInteraction {
  161. id: string
  162. conversationId: string
  163. conversationTaskId?: string
  164. runId: string
  165. agentId: string
  166. kind: 'approval' | 'clarification'
  167. message: string
  168. choices: string[]
  169. resolved: boolean
  170. }
  171. export interface WorkspaceEvent {
  172. seq: number
  173. type: string
  174. conversationId?: string
  175. data: unknown
  176. }
  177. /** Additional fields are optional while clients can still connect to older servers. */
  178. export interface WorkspaceSendReceipt {
  179. requestId?: string
  180. run: WorkspaceRun
  181. message?: WorkspaceMessage
  182. conversation?: WorkspaceConversation
  183. task?: WorkspaceTask | null
  184. cursor?: number
  185. }
  186. export interface WorkspaceSource {
  187. nodeId: string
  188. profile: string
  189. name: string
  190. }