mirror of
https://github.com/xmanrui/OpenClaw-bot-review.git
synced 2026-07-30 19:33:06 +00:00
Idle characters now have a 40% chance to walk to nearby furniture (water cooler, bookshelf, whiteboard, fridge) and linger for 5-15s. Agents spawning from offline walk in from doorway tiles instead of appearing directly at their seat.
113 lines
3.4 KiB
TypeScript
113 lines
3.4 KiB
TypeScript
import { OfficeState } from './engine/officeState'
|
|
|
|
export interface SubagentInfo {
|
|
toolId: string
|
|
label: string
|
|
}
|
|
|
|
export interface AgentActivity {
|
|
agentId: string
|
|
name: string
|
|
emoji: string
|
|
state: 'idle' | 'working' | 'waiting' | 'offline'
|
|
currentTool?: string
|
|
toolStatus?: string
|
|
lastActive: number
|
|
subagents?: SubagentInfo[]
|
|
}
|
|
|
|
/** Track which subagent toolIds were active last sync, per parent agent */
|
|
const prevSubagentKeys = new Map<string, Set<string>>()
|
|
|
|
/** Track previous agent states to detect offline→working transitions */
|
|
const prevAgentStates = new Map<string, string>()
|
|
|
|
export function syncAgentsToOffice(
|
|
activities: AgentActivity[],
|
|
office: OfficeState,
|
|
agentIdMap: Map<string, number>,
|
|
nextIdRef: { current: number },
|
|
): void {
|
|
const currentAgentIds = new Set(activities.map(a => a.agentId))
|
|
|
|
// Remove agents that are no longer present
|
|
for (const [agentId, charId] of agentIdMap) {
|
|
if (!currentAgentIds.has(agentId)) {
|
|
office.removeAllSubagents(charId)
|
|
office.removeAgent(charId)
|
|
agentIdMap.delete(agentId)
|
|
prevSubagentKeys.delete(agentId)
|
|
}
|
|
}
|
|
|
|
for (const activity of activities) {
|
|
if (activity.state === 'offline') {
|
|
if (agentIdMap.has(activity.agentId)) {
|
|
const charId = agentIdMap.get(activity.agentId)!
|
|
office.removeAllSubagents(charId)
|
|
office.removeAgent(charId)
|
|
agentIdMap.delete(activity.agentId)
|
|
prevSubagentKeys.delete(activity.agentId)
|
|
}
|
|
prevAgentStates.set(activity.agentId, 'offline')
|
|
continue
|
|
}
|
|
|
|
let charId = agentIdMap.get(activity.agentId)
|
|
if (charId === undefined) {
|
|
charId = nextIdRef.current++
|
|
agentIdMap.set(activity.agentId, charId)
|
|
// Spawn at door if agent was previously offline or is brand new
|
|
const wasOffline = prevAgentStates.get(activity.agentId) === 'offline'
|
|
const isNew = !prevAgentStates.has(activity.agentId)
|
|
office.addAgent(charId, undefined, undefined, undefined, undefined, wasOffline || isNew)
|
|
}
|
|
|
|
// Set label (agent name or id)
|
|
const ch = office.characters.get(charId)
|
|
if (ch) {
|
|
ch.label = activity.name || activity.agentId
|
|
}
|
|
|
|
switch (activity.state) {
|
|
case 'working':
|
|
office.setAgentActive(charId, true)
|
|
office.setAgentTool(charId, activity.currentTool || null)
|
|
break
|
|
case 'idle':
|
|
office.setAgentActive(charId, false)
|
|
office.setAgentTool(charId, null)
|
|
break
|
|
case 'waiting':
|
|
office.setAgentActive(charId, true)
|
|
office.showWaitingBubble(charId)
|
|
break
|
|
}
|
|
|
|
// Sync subagents
|
|
const currentSubKeys = new Set<string>()
|
|
if (activity.subagents) {
|
|
for (const sub of activity.subagents) {
|
|
currentSubKeys.add(sub.toolId)
|
|
const existingSubId = office.getSubagentId(charId, sub.toolId)
|
|
if (existingSubId === null) {
|
|
const subId = office.addSubagent(charId, sub.toolId)
|
|
office.setAgentActive(subId, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove subagents that are no longer active
|
|
const prevKeys = prevSubagentKeys.get(activity.agentId)
|
|
if (prevKeys) {
|
|
for (const toolId of prevKeys) {
|
|
if (!currentSubKeys.has(toolId)) {
|
|
office.removeSubagent(charId, toolId)
|
|
}
|
|
}
|
|
}
|
|
prevSubagentKeys.set(activity.agentId, currentSubKeys)
|
|
prevAgentStates.set(activity.agentId, activity.state)
|
|
}
|
|
}
|