[{"data":1,"prerenderedAt":2010},["ShallowReactive",2],{"docs:/docs/agents/patterns":3},{"id":4,"title":5,"body":6,"description":2003,"extension":2004,"meta":2005,"navigation":184,"path":2006,"seo":2007,"stem":2008,"__hash__":2009},"docs/docs/agents/patterns.md","Agent Coordination Patterns",{"type":7,"value":8,"toc":1969},"minimark",[9,14,23,28,31,36,49,53,312,316,491,495,556,560,563,566,577,581,720,723,749,753,756,759,770,773,1020,1023,1061,1065,1068,1071,1085,1088,1311,1314,1353,1357,1360,1363,1377,1380,1598,1601,1639,1643,1646,1649,1660,1663,1880,1883,1933,1937,1946,1957,1965],[10,11,13],"h1",{"id":12},"coordination-patterns","Coordination Patterns",[15,16,17,18,22],"p",{},"The ",[19,20,21],"code",{},"@nolag/agents"," SDK provides six coordination patterns. Each pattern maps to specific topics and QoS settings under the hood, but you interact with them through high-level APIs.",[24,25,27],"h2",{"id":26},"handoff","Handoff",[15,29,30],{},"The Handoff pattern implements task dispatch and result collection. An orchestrator dispatches tasks tagged with required capabilities. Workers register their capabilities and receive only tasks they can handle. Results flow back to the orchestrator automatically.",[32,33,35],"h3",{"id":34},"when-to-use","When to use",[37,38,39,43,46],"ul",{},[40,41,42],"li",{},"Distributing work across a pool of specialized agents",[40,44,45],{},"Load balancing tasks based on agent capabilities",[40,47,48],{},"Fan-out/fan-in workflows where multiple agents process subtasks",[32,50,52],{"id":51},"dispatching-tasks","Dispatching tasks",[54,55,56],"code-tabs",{},[57,58,64],"pre",{"className":59,"code":60,"filename":61,"language":62,"meta":63,"style":63},"language-typescript shiki shiki-themes github-light github-dark","// Orchestrator dispatches a task\nconst task = await room.handoff.dispatch({\n  type: \"summarize\",\n  payload: { url: \"https://example.com/article\" },\n  capabilities: [\"research\"],       // Only workers with this tag receive it\n  priority: \"urgent\",               // Optional priority tag\n  timeout: 30000,                   // Optional timeout in ms\n});\n\n// Listen for the result\nroom.handoff.onResult((result) => {\n  if (result.taskId === task.id) {\n    console.log(\"Summary:\", result.data.summary);\n  }\n});\n\n// Handle timeout\nroom.handoff.onTimeout((taskId) => {\n  console.log(\"Task timed out:\", taskId);\n});\n","TypeScript","typescript","",[19,65,66,75,103,116,128,143,158,173,179,186,192,217,232,250,256,261,266,272,291,307],{"__ignoreMap":63},[67,68,71],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"sJ8bj","// Orchestrator dispatches a task\n",[67,76,78,82,86,89,92,96,100],{"class":69,"line":77},2,[67,79,81],{"class":80},"szBVR","const",[67,83,85],{"class":84},"sj4cs"," task",[67,87,88],{"class":80}," =",[67,90,91],{"class":80}," await",[67,93,95],{"class":94},"sVt8B"," room.handoff.",[67,97,99],{"class":98},"sScJk","dispatch",[67,101,102],{"class":94},"({\n",[67,104,106,109,113],{"class":69,"line":105},3,[67,107,108],{"class":94},"  type: ",[67,110,112],{"class":111},"sZZnC","\"summarize\"",[67,114,115],{"class":94},",\n",[67,117,119,122,125],{"class":69,"line":118},4,[67,120,121],{"class":94},"  payload: { url: ",[67,123,124],{"class":111},"\"https://example.com/article\"",[67,126,127],{"class":94}," },\n",[67,129,131,134,137,140],{"class":69,"line":130},5,[67,132,133],{"class":94},"  capabilities: [",[67,135,136],{"class":111},"\"research\"",[67,138,139],{"class":94},"],       ",[67,141,142],{"class":73},"// Only workers with this tag receive it\n",[67,144,146,149,152,155],{"class":69,"line":145},6,[67,147,148],{"class":94},"  priority: ",[67,150,151],{"class":111},"\"urgent\"",[67,153,154],{"class":94},",               ",[67,156,157],{"class":73},"// Optional priority tag\n",[67,159,161,164,167,170],{"class":69,"line":160},7,[67,162,163],{"class":94},"  timeout: ",[67,165,166],{"class":84},"30000",[67,168,169],{"class":94},",                   ",[67,171,172],{"class":73},"// Optional timeout in ms\n",[67,174,176],{"class":69,"line":175},8,[67,177,178],{"class":94},"});\n",[67,180,182],{"class":69,"line":181},9,[67,183,185],{"emptyLinePlaceholder":184},true,"\n",[67,187,189],{"class":69,"line":188},10,[67,190,191],{"class":73},"// Listen for the result\n",[67,193,195,198,201,204,208,211,214],{"class":69,"line":194},11,[67,196,197],{"class":94},"room.handoff.",[67,199,200],{"class":98},"onResult",[67,202,203],{"class":94},"((",[67,205,207],{"class":206},"s4XuR","result",[67,209,210],{"class":94},") ",[67,212,213],{"class":80},"=>",[67,215,216],{"class":94}," {\n",[67,218,220,223,226,229],{"class":69,"line":219},12,[67,221,222],{"class":80},"  if",[67,224,225],{"class":94}," (result.taskId ",[67,227,228],{"class":80},"===",[67,230,231],{"class":94}," task.id) {\n",[67,233,235,238,241,244,247],{"class":69,"line":234},13,[67,236,237],{"class":94},"    console.",[67,239,240],{"class":98},"log",[67,242,243],{"class":94},"(",[67,245,246],{"class":111},"\"Summary:\"",[67,248,249],{"class":94},", result.data.summary);\n",[67,251,253],{"class":69,"line":252},14,[67,254,255],{"class":94},"  }\n",[67,257,259],{"class":69,"line":258},15,[67,260,178],{"class":94},[67,262,264],{"class":69,"line":263},16,[67,265,185],{"emptyLinePlaceholder":184},[67,267,269],{"class":69,"line":268},17,[67,270,271],{"class":73},"// Handle timeout\n",[67,273,275,277,280,282,285,287,289],{"class":69,"line":274},18,[67,276,197],{"class":94},[67,278,279],{"class":98},"onTimeout",[67,281,203],{"class":94},[67,283,284],{"class":206},"taskId",[67,286,210],{"class":94},[67,288,213],{"class":80},[67,290,216],{"class":94},[67,292,294,297,299,301,304],{"class":69,"line":293},19,[67,295,296],{"class":94},"  console.",[67,298,240],{"class":98},[67,300,243],{"class":94},[67,302,303],{"class":111},"\"Task timed out:\"",[67,305,306],{"class":94},", taskId);\n",[67,308,310],{"class":69,"line":309},20,[67,311,178],{"class":94},[32,313,315],{"id":314},"handling-tasks","Handling tasks",[54,317,318],{},[57,319,321],{"className":59,"code":320,"filename":61,"language":62,"meta":63,"style":63},"// Worker registers capabilities\nroom.handoff.register({\n  capabilities: [\"research\", \"finance\"],\n  concurrency: 3,  // Handle up to 3 tasks at once\n});\n\n// Handle incoming tasks\nroom.handoff.onTask(async (task) => {\n  console.log(\"Received:\", task.type, task.payload);\n\n  try {\n    const result = await doResearch(task.payload);\n    await task.complete({ summary: result });\n  } catch (err) {\n    await task.fail({ error: err.message });\n  }\n});\n",[19,322,323,328,337,352,366,370,374,379,403,417,421,428,446,460,471,483,487],{"__ignoreMap":63},[67,324,325],{"class":69,"line":70},[67,326,327],{"class":73},"// Worker registers capabilities\n",[67,329,330,332,335],{"class":69,"line":77},[67,331,197],{"class":94},[67,333,334],{"class":98},"register",[67,336,102],{"class":94},[67,338,339,341,343,346,349],{"class":69,"line":105},[67,340,133],{"class":94},[67,342,136],{"class":111},[67,344,345],{"class":94},", ",[67,347,348],{"class":111},"\"finance\"",[67,350,351],{"class":94},"],\n",[67,353,354,357,360,363],{"class":69,"line":118},[67,355,356],{"class":94},"  concurrency: ",[67,358,359],{"class":84},"3",[67,361,362],{"class":94},",  ",[67,364,365],{"class":73},"// Handle up to 3 tasks at once\n",[67,367,368],{"class":69,"line":130},[67,369,178],{"class":94},[67,371,372],{"class":69,"line":145},[67,373,185],{"emptyLinePlaceholder":184},[67,375,376],{"class":69,"line":160},[67,377,378],{"class":73},"// Handle incoming tasks\n",[67,380,381,383,386,388,391,394,397,399,401],{"class":69,"line":175},[67,382,197],{"class":94},[67,384,385],{"class":98},"onTask",[67,387,243],{"class":94},[67,389,390],{"class":80},"async",[67,392,393],{"class":94}," (",[67,395,396],{"class":206},"task",[67,398,210],{"class":94},[67,400,213],{"class":80},[67,402,216],{"class":94},[67,404,405,407,409,411,414],{"class":69,"line":181},[67,406,296],{"class":94},[67,408,240],{"class":98},[67,410,243],{"class":94},[67,412,413],{"class":111},"\"Received:\"",[67,415,416],{"class":94},", task.type, task.payload);\n",[67,418,419],{"class":69,"line":188},[67,420,185],{"emptyLinePlaceholder":184},[67,422,423,426],{"class":69,"line":194},[67,424,425],{"class":80},"  try",[67,427,216],{"class":94},[67,429,430,433,436,438,440,443],{"class":69,"line":219},[67,431,432],{"class":80},"    const",[67,434,435],{"class":84}," result",[67,437,88],{"class":80},[67,439,91],{"class":80},[67,441,442],{"class":98}," doResearch",[67,444,445],{"class":94},"(task.payload);\n",[67,447,448,451,454,457],{"class":69,"line":234},[67,449,450],{"class":80},"    await",[67,452,453],{"class":94}," task.",[67,455,456],{"class":98},"complete",[67,458,459],{"class":94},"({ summary: result });\n",[67,461,462,465,468],{"class":69,"line":252},[67,463,464],{"class":94},"  } ",[67,466,467],{"class":80},"catch",[67,469,470],{"class":94}," (err) {\n",[67,472,473,475,477,480],{"class":69,"line":258},[67,474,450],{"class":80},[67,476,453],{"class":94},[67,478,479],{"class":98},"fail",[67,481,482],{"class":94},"({ error: err.message });\n",[67,484,485],{"class":69,"line":263},[67,486,255],{"class":94},[67,488,489],{"class":69,"line":268},[67,490,178],{"class":94},[32,492,494],{"id":493},"topic-mapping","Topic mapping",[496,497,498,514],"table",{},[499,500,501],"thead",{},[502,503,504,508,511],"tr",{},[505,506,507],"th",{},"Topic",[505,509,510],{},"Purpose",[505,512,513],{},"QoS",[515,516,517,531,543],"tbody",{},[502,518,519,525,528],{},[520,521,522],"td",{},[19,523,524],{},"_handoff/dispatch",[520,526,527],{},"Task dispatch from orchestrator",[520,529,530],{},"2 (exactly once)",[502,532,533,538,541],{},[520,534,535],{},[19,536,537],{},"_handoff/result",[520,539,540],{},"Results from workers",[520,542,530],{},[502,544,545,550,553],{},[520,546,547],{},[19,548,549],{},"_handoff/claim",[520,551,552],{},"Worker claims a task",[520,554,555],{},"1 (at least once)",[24,557,559],{"id":558},"inbox","Inbox",[15,561,562],{},"The Inbox pattern provides direct actor-to-actor messaging. Unlike Handoff which broadcasts to capable workers, Inbox sends messages to a specific agent by ID. Use it for point-to-point communication between known agents.",[32,564,35],{"id":565},"when-to-use-1",[37,567,568,571,574],{},[40,569,570],{},"Sending instructions to a specific agent",[40,572,573],{},"Agent-to-agent conversation threads",[40,575,576],{},"Passing results between pipeline stages with known recipients",[32,578,580],{"id":579},"code-example","Code example",[54,582,583],{},[57,584,586],{"className":59,"code":585,"filename":61,"language":62,"meta":63,"style":63},"// Send a direct message to a specific agent\nawait room.inbox.send(\"reviewer-agent\", {\n  type: \"review-request\",\n  document: draftContent,\n  deadline: \"2024-01-15\",\n});\n\n// Receive direct messages\nroom.inbox.on(\"message\", (msg) => {\n  console.log(\"From:\", msg.sender);\n  console.log(\"Type:\", msg.data.type);\n  console.log(\"Content:\", msg.data);\n});\n",[19,587,588,593,612,621,626,636,640,644,649,674,688,702,716],{"__ignoreMap":63},[67,589,590],{"class":69,"line":70},[67,591,592],{"class":73},"// Send a direct message to a specific agent\n",[67,594,595,598,601,604,606,609],{"class":69,"line":77},[67,596,597],{"class":80},"await",[67,599,600],{"class":94}," room.inbox.",[67,602,603],{"class":98},"send",[67,605,243],{"class":94},[67,607,608],{"class":111},"\"reviewer-agent\"",[67,610,611],{"class":94},", {\n",[67,613,614,616,619],{"class":69,"line":105},[67,615,108],{"class":94},[67,617,618],{"class":111},"\"review-request\"",[67,620,115],{"class":94},[67,622,623],{"class":69,"line":118},[67,624,625],{"class":94},"  document: draftContent,\n",[67,627,628,631,634],{"class":69,"line":130},[67,629,630],{"class":94},"  deadline: ",[67,632,633],{"class":111},"\"2024-01-15\"",[67,635,115],{"class":94},[67,637,638],{"class":69,"line":145},[67,639,178],{"class":94},[67,641,642],{"class":69,"line":160},[67,643,185],{"emptyLinePlaceholder":184},[67,645,646],{"class":69,"line":175},[67,647,648],{"class":73},"// Receive direct messages\n",[67,650,651,654,657,659,662,665,668,670,672],{"class":69,"line":181},[67,652,653],{"class":94},"room.inbox.",[67,655,656],{"class":98},"on",[67,658,243],{"class":94},[67,660,661],{"class":111},"\"message\"",[67,663,664],{"class":94},", (",[67,666,667],{"class":206},"msg",[67,669,210],{"class":94},[67,671,213],{"class":80},[67,673,216],{"class":94},[67,675,676,678,680,682,685],{"class":69,"line":188},[67,677,296],{"class":94},[67,679,240],{"class":98},[67,681,243],{"class":94},[67,683,684],{"class":111},"\"From:\"",[67,686,687],{"class":94},", msg.sender);\n",[67,689,690,692,694,696,699],{"class":69,"line":194},[67,691,296],{"class":94},[67,693,240],{"class":98},[67,695,243],{"class":94},[67,697,698],{"class":111},"\"Type:\"",[67,700,701],{"class":94},", msg.data.type);\n",[67,703,704,706,708,710,713],{"class":69,"line":219},[67,705,296],{"class":94},[67,707,240],{"class":98},[67,709,243],{"class":94},[67,711,712],{"class":111},"\"Content:\"",[67,714,715],{"class":94},", msg.data);\n",[67,717,718],{"class":69,"line":234},[67,719,178],{"class":94},[32,721,494],{"id":722},"topic-mapping-1",[496,724,725,735],{},[499,726,727],{},[502,728,729,731,733],{},[505,730,507],{},[505,732,510],{},[505,734,513],{},[515,736,737],{},[502,738,739,744,747],{},[520,740,741],{},[19,742,743],{},"_inbox/{actorId}",[520,745,746],{},"Messages for a specific agent",[520,748,530],{},[24,750,752],{"id":751},"blackboard","Blackboard",[15,754,755],{},"The Blackboard pattern provides shared key-value state with versioning. All agents in a room see the same state. Updates are broadcast in real time so every agent stays synchronized. Versioning prevents conflicts from concurrent updates.",[32,757,35],{"id":758},"when-to-use-2",[37,760,761,764,767],{},[40,762,763],{},"Sharing workflow state across multiple agents",[40,765,766],{},"Maintaining a shared plan or configuration",[40,768,769],{},"Accumulating results from multiple agents into a single view",[32,771,580],{"id":772},"code-example-1",[54,774,775],{},[57,776,778],{"className":59,"code":777,"filename":61,"language":62,"meta":63,"style":63},"// Write shared state\nawait room.blackboard.set(\"workflow-plan\", {\n  steps: [\"research\", \"draft\", \"review\", \"publish\"],\n  currentStep: 0,\n  assignees: {},\n});\n\n// Read shared state\nconst plan = room.blackboard.get(\"workflow-plan\");\nconsole.log(\"Current step:\", plan.steps[plan.currentStep]);\n\n// Update atomically\nawait room.blackboard.update(\"workflow-plan\", (prev) => ({\n  ...prev,\n  currentStep: prev.currentStep + 1,\n}));\n\n// Watch for changes\nroom.blackboard.on(\"change\", (key, value, version) => {\n  console.log(`${key} updated to version ${version}`);\n});\n",[19,779,780,785,802,826,836,841,845,849,854,875,890,894,899,924,932,945,950,954,959,992,1015],{"__ignoreMap":63},[67,781,782],{"class":69,"line":70},[67,783,784],{"class":73},"// Write shared state\n",[67,786,787,789,792,795,797,800],{"class":69,"line":77},[67,788,597],{"class":80},[67,790,791],{"class":94}," room.blackboard.",[67,793,794],{"class":98},"set",[67,796,243],{"class":94},[67,798,799],{"class":111},"\"workflow-plan\"",[67,801,611],{"class":94},[67,803,804,807,809,811,814,816,819,821,824],{"class":69,"line":105},[67,805,806],{"class":94},"  steps: [",[67,808,136],{"class":111},[67,810,345],{"class":94},[67,812,813],{"class":111},"\"draft\"",[67,815,345],{"class":94},[67,817,818],{"class":111},"\"review\"",[67,820,345],{"class":94},[67,822,823],{"class":111},"\"publish\"",[67,825,351],{"class":94},[67,827,828,831,834],{"class":69,"line":118},[67,829,830],{"class":94},"  currentStep: ",[67,832,833],{"class":84},"0",[67,835,115],{"class":94},[67,837,838],{"class":69,"line":130},[67,839,840],{"class":94},"  assignees: {},\n",[67,842,843],{"class":69,"line":145},[67,844,178],{"class":94},[67,846,847],{"class":69,"line":160},[67,848,185],{"emptyLinePlaceholder":184},[67,850,851],{"class":69,"line":175},[67,852,853],{"class":73},"// Read shared state\n",[67,855,856,858,861,863,865,868,870,872],{"class":69,"line":181},[67,857,81],{"class":80},[67,859,860],{"class":84}," plan",[67,862,88],{"class":80},[67,864,791],{"class":94},[67,866,867],{"class":98},"get",[67,869,243],{"class":94},[67,871,799],{"class":111},[67,873,874],{"class":94},");\n",[67,876,877,880,882,884,887],{"class":69,"line":188},[67,878,879],{"class":94},"console.",[67,881,240],{"class":98},[67,883,243],{"class":94},[67,885,886],{"class":111},"\"Current step:\"",[67,888,889],{"class":94},", plan.steps[plan.currentStep]);\n",[67,891,892],{"class":69,"line":194},[67,893,185],{"emptyLinePlaceholder":184},[67,895,896],{"class":69,"line":219},[67,897,898],{"class":73},"// Update atomically\n",[67,900,901,903,905,908,910,912,914,917,919,921],{"class":69,"line":234},[67,902,597],{"class":80},[67,904,791],{"class":94},[67,906,907],{"class":98},"update",[67,909,243],{"class":94},[67,911,799],{"class":111},[67,913,664],{"class":94},[67,915,916],{"class":206},"prev",[67,918,210],{"class":94},[67,920,213],{"class":80},[67,922,923],{"class":94}," ({\n",[67,925,926,929],{"class":69,"line":252},[67,927,928],{"class":80},"  ...",[67,930,931],{"class":94},"prev,\n",[67,933,934,937,940,943],{"class":69,"line":258},[67,935,936],{"class":94},"  currentStep: prev.currentStep ",[67,938,939],{"class":80},"+",[67,941,942],{"class":84}," 1",[67,944,115],{"class":94},[67,946,947],{"class":69,"line":263},[67,948,949],{"class":94},"}));\n",[67,951,952],{"class":69,"line":268},[67,953,185],{"emptyLinePlaceholder":184},[67,955,956],{"class":69,"line":274},[67,957,958],{"class":73},"// Watch for changes\n",[67,960,961,964,966,968,971,973,976,978,981,983,986,988,990],{"class":69,"line":293},[67,962,963],{"class":94},"room.blackboard.",[67,965,656],{"class":98},[67,967,243],{"class":94},[67,969,970],{"class":111},"\"change\"",[67,972,664],{"class":94},[67,974,975],{"class":206},"key",[67,977,345],{"class":94},[67,979,980],{"class":206},"value",[67,982,345],{"class":94},[67,984,985],{"class":206},"version",[67,987,210],{"class":94},[67,989,213],{"class":80},[67,991,216],{"class":94},[67,993,994,996,998,1000,1003,1005,1008,1010,1013],{"class":69,"line":309},[67,995,296],{"class":94},[67,997,240],{"class":98},[67,999,243],{"class":94},[67,1001,1002],{"class":111},"`${",[67,1004,975],{"class":94},[67,1006,1007],{"class":111},"} updated to version ${",[67,1009,985],{"class":94},[67,1011,1012],{"class":111},"}`",[67,1014,874],{"class":94},[67,1016,1018],{"class":69,"line":1017},21,[67,1019,178],{"class":94},[32,1021,494],{"id":1022},"topic-mapping-2",[496,1024,1025,1035],{},[499,1026,1027],{},[502,1028,1029,1031,1033],{},[505,1030,507],{},[505,1032,510],{},[505,1034,513],{},[515,1036,1037,1049],{},[502,1038,1039,1044,1047],{},[520,1040,1041],{},[19,1042,1043],{},"_blackboard/state",[520,1045,1046],{},"State updates (retained)",[520,1048,530],{},[502,1050,1051,1056,1059],{},[520,1052,1053],{},[19,1054,1055],{},"_blackboard/change",[520,1057,1058],{},"Change notifications",[520,1060,555],{},[24,1062,1064],{"id":1063},"observe","Observe",[15,1066,1067],{},"The Observe pattern provides a real-time event stream for monitoring. Every action in the system (task dispatch, completion, state changes, approvals) emits an event. Subscribe to all events or filter by type for dashboards, logging, and debugging.",[32,1069,35],{"id":1070},"when-to-use-3",[37,1072,1073,1076,1079,1082],{},[40,1074,1075],{},"Building monitoring dashboards for agent workflows",[40,1077,1078],{},"Audit logging of all agent decisions",[40,1080,1081],{},"Debugging agent behavior in real time",[40,1083,1084],{},"Triggering side effects on specific events",[32,1086,580],{"id":1087},"code-example-2",[54,1089,1090],{},[57,1091,1093],{"className":59,"code":1092,"filename":61,"language":62,"meta":63,"style":63},"// Watch all events\nroom.observe.on(\"*\", (event) => {\n  console.log(`[${event.timestamp}] ${event.agent} -> ${event.type}`);\n});\n\n// Watch specific event types\nroom.observe.on(\"task:dispatched\", (event) => {\n  console.log(\"New task:\", event.data.taskId);\n});\n\nroom.observe.on(\"task:completed\", (event) => {\n  console.log(\"Done:\", event.data.taskId, event.data.result);\n});\n\n// Emit custom events\nawait room.observe.emit(\"custom:checkpoint\", {\n  step: \"research-complete\",\n  duration: 4200,\n});\n",[19,1094,1095,1100,1123,1166,1170,1174,1179,1200,1214,1218,1222,1243,1257,1261,1265,1270,1287,1297,1307],{"__ignoreMap":63},[67,1096,1097],{"class":69,"line":70},[67,1098,1099],{"class":73},"// Watch all events\n",[67,1101,1102,1105,1107,1109,1112,1114,1117,1119,1121],{"class":69,"line":77},[67,1103,1104],{"class":94},"room.observe.",[67,1106,656],{"class":98},[67,1108,243],{"class":94},[67,1110,1111],{"class":111},"\"*\"",[67,1113,664],{"class":94},[67,1115,1116],{"class":206},"event",[67,1118,210],{"class":94},[67,1120,213],{"class":80},[67,1122,216],{"class":94},[67,1124,1125,1127,1129,1131,1134,1136,1139,1142,1145,1147,1149,1152,1155,1157,1159,1162,1164],{"class":69,"line":105},[67,1126,296],{"class":94},[67,1128,240],{"class":98},[67,1130,243],{"class":94},[67,1132,1133],{"class":111},"`[${",[67,1135,1116],{"class":94},[67,1137,1138],{"class":111},".",[67,1140,1141],{"class":94},"timestamp",[67,1143,1144],{"class":111},"}] ${",[67,1146,1116],{"class":94},[67,1148,1138],{"class":111},[67,1150,1151],{"class":94},"agent",[67,1153,1154],{"class":111},"} -> ${",[67,1156,1116],{"class":94},[67,1158,1138],{"class":111},[67,1160,1161],{"class":94},"type",[67,1163,1012],{"class":111},[67,1165,874],{"class":94},[67,1167,1168],{"class":69,"line":118},[67,1169,178],{"class":94},[67,1171,1172],{"class":69,"line":130},[67,1173,185],{"emptyLinePlaceholder":184},[67,1175,1176],{"class":69,"line":145},[67,1177,1178],{"class":73},"// Watch specific event types\n",[67,1180,1181,1183,1185,1187,1190,1192,1194,1196,1198],{"class":69,"line":160},[67,1182,1104],{"class":94},[67,1184,656],{"class":98},[67,1186,243],{"class":94},[67,1188,1189],{"class":111},"\"task:dispatched\"",[67,1191,664],{"class":94},[67,1193,1116],{"class":206},[67,1195,210],{"class":94},[67,1197,213],{"class":80},[67,1199,216],{"class":94},[67,1201,1202,1204,1206,1208,1211],{"class":69,"line":175},[67,1203,296],{"class":94},[67,1205,240],{"class":98},[67,1207,243],{"class":94},[67,1209,1210],{"class":111},"\"New task:\"",[67,1212,1213],{"class":94},", event.data.taskId);\n",[67,1215,1216],{"class":69,"line":181},[67,1217,178],{"class":94},[67,1219,1220],{"class":69,"line":188},[67,1221,185],{"emptyLinePlaceholder":184},[67,1223,1224,1226,1228,1230,1233,1235,1237,1239,1241],{"class":69,"line":194},[67,1225,1104],{"class":94},[67,1227,656],{"class":98},[67,1229,243],{"class":94},[67,1231,1232],{"class":111},"\"task:completed\"",[67,1234,664],{"class":94},[67,1236,1116],{"class":206},[67,1238,210],{"class":94},[67,1240,213],{"class":80},[67,1242,216],{"class":94},[67,1244,1245,1247,1249,1251,1254],{"class":69,"line":219},[67,1246,296],{"class":94},[67,1248,240],{"class":98},[67,1250,243],{"class":94},[67,1252,1253],{"class":111},"\"Done:\"",[67,1255,1256],{"class":94},", event.data.taskId, event.data.result);\n",[67,1258,1259],{"class":69,"line":234},[67,1260,178],{"class":94},[67,1262,1263],{"class":69,"line":252},[67,1264,185],{"emptyLinePlaceholder":184},[67,1266,1267],{"class":69,"line":258},[67,1268,1269],{"class":73},"// Emit custom events\n",[67,1271,1272,1274,1277,1280,1282,1285],{"class":69,"line":263},[67,1273,597],{"class":80},[67,1275,1276],{"class":94}," room.observe.",[67,1278,1279],{"class":98},"emit",[67,1281,243],{"class":94},[67,1283,1284],{"class":111},"\"custom:checkpoint\"",[67,1286,611],{"class":94},[67,1288,1289,1292,1295],{"class":69,"line":268},[67,1290,1291],{"class":94},"  step: ",[67,1293,1294],{"class":111},"\"research-complete\"",[67,1296,115],{"class":94},[67,1298,1299,1302,1305],{"class":69,"line":274},[67,1300,1301],{"class":94},"  duration: ",[67,1303,1304],{"class":84},"4200",[67,1306,115],{"class":94},[67,1308,1309],{"class":69,"line":293},[67,1310,178],{"class":94},[32,1312,494],{"id":1313},"topic-mapping-3",[496,1315,1316,1326],{},[499,1317,1318],{},[502,1319,1320,1322,1324],{},[505,1321,507],{},[505,1323,510],{},[505,1325,513],{},[515,1327,1328,1340],{},[502,1329,1330,1335,1338],{},[520,1331,1332],{},[19,1333,1334],{},"_observe/events",[520,1336,1337],{},"All system events",[520,1339,555],{},[502,1341,1342,1347,1350],{},[520,1343,1344],{},[19,1345,1346],{},"_observe/custom",[520,1348,1349],{},"Custom application events",[520,1351,1352],{},"0 (fire and forget)",[24,1354,1356],{"id":1355},"approve","Approve",[15,1358,1359],{},"The Approve pattern implements human-in-the-loop gating. An agent can pause its workflow and request approval from a human (or supervisor agent) before proceeding. The request includes context about the pending action so the approver can make an informed decision.",[32,1361,35],{"id":1362},"when-to-use-4",[37,1364,1365,1368,1371,1374],{},[40,1366,1367],{},"Gating destructive or high-stakes actions",[40,1369,1370],{},"Compliance workflows requiring human sign-off",[40,1372,1373],{},"Multi-level approval chains",[40,1375,1376],{},"Allowing humans to modify agent outputs before execution",[32,1378,580],{"id":1379},"code-example-3",[54,1381,1382],{},[57,1383,1385],{"className":59,"code":1384,"filename":61,"language":62,"meta":63,"style":63},"// Agent requests approval\nconst approval = await room.approve.request({\n  action: \"send-email\",\n  description: \"Send quarterly report to investors\",\n  payload: { to: \"investors@company.com\", body: reportHtml },\n  timeout: 600000,  // 10 minutes to respond\n});\n\nif (approval.approved) {\n  await sendEmail(approval.payload);\n} else {\n  console.log(\"Rejected:\", approval.reason);\n}\n\n// Human (or supervisor agent) handles approval requests\nroom.approve.onRequest((request) => {\n  // Show in UI or evaluate programmatically\n  displayApprovalDialog(request);\n});\n\n// Approve or reject\nawait room.approve.respond(request.id, {\n  approved: true,\n  // Or: approved: false, reason: \"Budget not approved\"\n});\n",[19,1386,1387,1392,1411,1421,1431,1442,1454,1458,1462,1470,1481,1491,1505,1510,1514,1519,1537,1542,1550,1554,1558,1563,1576,1587,1593],{"__ignoreMap":63},[67,1388,1389],{"class":69,"line":70},[67,1390,1391],{"class":73},"// Agent requests approval\n",[67,1393,1394,1396,1399,1401,1403,1406,1409],{"class":69,"line":77},[67,1395,81],{"class":80},[67,1397,1398],{"class":84}," approval",[67,1400,88],{"class":80},[67,1402,91],{"class":80},[67,1404,1405],{"class":94}," room.approve.",[67,1407,1408],{"class":98},"request",[67,1410,102],{"class":94},[67,1412,1413,1416,1419],{"class":69,"line":105},[67,1414,1415],{"class":94},"  action: ",[67,1417,1418],{"class":111},"\"send-email\"",[67,1420,115],{"class":94},[67,1422,1423,1426,1429],{"class":69,"line":118},[67,1424,1425],{"class":94},"  description: ",[67,1427,1428],{"class":111},"\"Send quarterly report to investors\"",[67,1430,115],{"class":94},[67,1432,1433,1436,1439],{"class":69,"line":130},[67,1434,1435],{"class":94},"  payload: { to: ",[67,1437,1438],{"class":111},"\"investors@company.com\"",[67,1440,1441],{"class":94},", body: reportHtml },\n",[67,1443,1444,1446,1449,1451],{"class":69,"line":145},[67,1445,163],{"class":94},[67,1447,1448],{"class":84},"600000",[67,1450,362],{"class":94},[67,1452,1453],{"class":73},"// 10 minutes to respond\n",[67,1455,1456],{"class":69,"line":160},[67,1457,178],{"class":94},[67,1459,1460],{"class":69,"line":175},[67,1461,185],{"emptyLinePlaceholder":184},[67,1463,1464,1467],{"class":69,"line":181},[67,1465,1466],{"class":80},"if",[67,1468,1469],{"class":94}," (approval.approved) {\n",[67,1471,1472,1475,1478],{"class":69,"line":188},[67,1473,1474],{"class":80},"  await",[67,1476,1477],{"class":98}," sendEmail",[67,1479,1480],{"class":94},"(approval.payload);\n",[67,1482,1483,1486,1489],{"class":69,"line":194},[67,1484,1485],{"class":94},"} ",[67,1487,1488],{"class":80},"else",[67,1490,216],{"class":94},[67,1492,1493,1495,1497,1499,1502],{"class":69,"line":219},[67,1494,296],{"class":94},[67,1496,240],{"class":98},[67,1498,243],{"class":94},[67,1500,1501],{"class":111},"\"Rejected:\"",[67,1503,1504],{"class":94},", approval.reason);\n",[67,1506,1507],{"class":69,"line":234},[67,1508,1509],{"class":94},"}\n",[67,1511,1512],{"class":69,"line":252},[67,1513,185],{"emptyLinePlaceholder":184},[67,1515,1516],{"class":69,"line":258},[67,1517,1518],{"class":73},"// Human (or supervisor agent) handles approval requests\n",[67,1520,1521,1524,1527,1529,1531,1533,1535],{"class":69,"line":263},[67,1522,1523],{"class":94},"room.approve.",[67,1525,1526],{"class":98},"onRequest",[67,1528,203],{"class":94},[67,1530,1408],{"class":206},[67,1532,210],{"class":94},[67,1534,213],{"class":80},[67,1536,216],{"class":94},[67,1538,1539],{"class":69,"line":268},[67,1540,1541],{"class":73},"  // Show in UI or evaluate programmatically\n",[67,1543,1544,1547],{"class":69,"line":274},[67,1545,1546],{"class":98},"  displayApprovalDialog",[67,1548,1549],{"class":94},"(request);\n",[67,1551,1552],{"class":69,"line":293},[67,1553,178],{"class":94},[67,1555,1556],{"class":69,"line":309},[67,1557,185],{"emptyLinePlaceholder":184},[67,1559,1560],{"class":69,"line":1017},[67,1561,1562],{"class":73},"// Approve or reject\n",[67,1564,1566,1568,1570,1573],{"class":69,"line":1565},22,[67,1567,597],{"class":80},[67,1569,1405],{"class":94},[67,1571,1572],{"class":98},"respond",[67,1574,1575],{"class":94},"(request.id, {\n",[67,1577,1579,1582,1585],{"class":69,"line":1578},23,[67,1580,1581],{"class":94},"  approved: ",[67,1583,1584],{"class":84},"true",[67,1586,115],{"class":94},[67,1588,1590],{"class":69,"line":1589},24,[67,1591,1592],{"class":73},"  // Or: approved: false, reason: \"Budget not approved\"\n",[67,1594,1596],{"class":69,"line":1595},25,[67,1597,178],{"class":94},[32,1599,494],{"id":1600},"topic-mapping-4",[496,1602,1603,1613],{},[499,1604,1605],{},[502,1606,1607,1609,1611],{},[505,1608,507],{},[505,1610,510],{},[505,1612,513],{},[515,1614,1615,1627],{},[502,1616,1617,1622,1625],{},[520,1618,1619],{},[19,1620,1621],{},"_approve/request",[520,1623,1624],{},"Approval requests",[520,1626,530],{},[502,1628,1629,1634,1637],{},[520,1630,1631],{},[19,1632,1633],{},"_approve/response",[520,1635,1636],{},"Approval decisions",[520,1638,530],{},[24,1640,1642],{"id":1641},"tools","Tools",[15,1644,1645],{},"The Tools pattern enables remote tool invocation. One agent can register tools that other agents can discover and call. This is similar to MCP tool use but runs over the NoLag messaging layer for real-time, multi-agent scenarios.",[32,1647,35],{"id":1648},"when-to-use-5",[37,1650,1651,1654,1657],{},[40,1652,1653],{},"Sharing capabilities across agents (search, database access, APIs)",[40,1655,1656],{},"Building tool-augmented agents that compose external services",[40,1658,1659],{},"Centralizing tool access with access control",[32,1661,580],{"id":1662},"code-example-4",[54,1664,1665],{},[57,1666,1668],{"className":59,"code":1667,"filename":61,"language":62,"meta":63,"style":63},"// Register a tool that other agents can invoke\nroom.tools.register(\"web-search\", {\n  description: \"Search the web for information\",\n  parameters: { query: \"string\" },\n  handler: async (params) => {\n    const results = await searchWeb(params.query);\n    return { results };\n  },\n});\n\n// Invoke a tool from another agent\nconst result = await room.tools.invoke(\"web-search\", {\n  query: \"latest quarterly earnings ACME Corp\",\n});\n\nconsole.log(\"Search results:\", result.results);\n\n// List available tools\nconst tools = room.tools.list();\nconsole.log(\"Available:\", tools.map(t => t.name));\n",[19,1669,1670,1675,1689,1698,1708,1729,1746,1754,1759,1763,1767,1772,1794,1804,1808,1812,1826,1830,1835,1852],{"__ignoreMap":63},[67,1671,1672],{"class":69,"line":70},[67,1673,1674],{"class":73},"// Register a tool that other agents can invoke\n",[67,1676,1677,1680,1682,1684,1687],{"class":69,"line":77},[67,1678,1679],{"class":94},"room.tools.",[67,1681,334],{"class":98},[67,1683,243],{"class":94},[67,1685,1686],{"class":111},"\"web-search\"",[67,1688,611],{"class":94},[67,1690,1691,1693,1696],{"class":69,"line":105},[67,1692,1425],{"class":94},[67,1694,1695],{"class":111},"\"Search the web for information\"",[67,1697,115],{"class":94},[67,1699,1700,1703,1706],{"class":69,"line":118},[67,1701,1702],{"class":94},"  parameters: { query: ",[67,1704,1705],{"class":111},"\"string\"",[67,1707,127],{"class":94},[67,1709,1710,1713,1716,1718,1720,1723,1725,1727],{"class":69,"line":130},[67,1711,1712],{"class":98},"  handler",[67,1714,1715],{"class":94},": ",[67,1717,390],{"class":80},[67,1719,393],{"class":94},[67,1721,1722],{"class":206},"params",[67,1724,210],{"class":94},[67,1726,213],{"class":80},[67,1728,216],{"class":94},[67,1730,1731,1733,1736,1738,1740,1743],{"class":69,"line":145},[67,1732,432],{"class":80},[67,1734,1735],{"class":84}," results",[67,1737,88],{"class":80},[67,1739,91],{"class":80},[67,1741,1742],{"class":98}," searchWeb",[67,1744,1745],{"class":94},"(params.query);\n",[67,1747,1748,1751],{"class":69,"line":160},[67,1749,1750],{"class":80},"    return",[67,1752,1753],{"class":94}," { results };\n",[67,1755,1756],{"class":69,"line":175},[67,1757,1758],{"class":94},"  },\n",[67,1760,1761],{"class":69,"line":181},[67,1762,178],{"class":94},[67,1764,1765],{"class":69,"line":188},[67,1766,185],{"emptyLinePlaceholder":184},[67,1768,1769],{"class":69,"line":194},[67,1770,1771],{"class":73},"// Invoke a tool from another agent\n",[67,1773,1774,1776,1778,1780,1782,1785,1788,1790,1792],{"class":69,"line":219},[67,1775,81],{"class":80},[67,1777,435],{"class":84},[67,1779,88],{"class":80},[67,1781,91],{"class":80},[67,1783,1784],{"class":94}," room.tools.",[67,1786,1787],{"class":98},"invoke",[67,1789,243],{"class":94},[67,1791,1686],{"class":111},[67,1793,611],{"class":94},[67,1795,1796,1799,1802],{"class":69,"line":234},[67,1797,1798],{"class":94},"  query: ",[67,1800,1801],{"class":111},"\"latest quarterly earnings ACME Corp\"",[67,1803,115],{"class":94},[67,1805,1806],{"class":69,"line":252},[67,1807,178],{"class":94},[67,1809,1810],{"class":69,"line":258},[67,1811,185],{"emptyLinePlaceholder":184},[67,1813,1814,1816,1818,1820,1823],{"class":69,"line":263},[67,1815,879],{"class":94},[67,1817,240],{"class":98},[67,1819,243],{"class":94},[67,1821,1822],{"class":111},"\"Search results:\"",[67,1824,1825],{"class":94},", result.results);\n",[67,1827,1828],{"class":69,"line":268},[67,1829,185],{"emptyLinePlaceholder":184},[67,1831,1832],{"class":69,"line":274},[67,1833,1834],{"class":73},"// List available tools\n",[67,1836,1837,1839,1842,1844,1846,1849],{"class":69,"line":293},[67,1838,81],{"class":80},[67,1840,1841],{"class":84}," tools",[67,1843,88],{"class":80},[67,1845,1784],{"class":94},[67,1847,1848],{"class":98},"list",[67,1850,1851],{"class":94},"();\n",[67,1853,1854,1856,1858,1860,1863,1866,1869,1871,1874,1877],{"class":69,"line":309},[67,1855,879],{"class":94},[67,1857,240],{"class":98},[67,1859,243],{"class":94},[67,1861,1862],{"class":111},"\"Available:\"",[67,1864,1865],{"class":94},", tools.",[67,1867,1868],{"class":98},"map",[67,1870,243],{"class":94},[67,1872,1873],{"class":206},"t",[67,1875,1876],{"class":80}," =>",[67,1878,1879],{"class":94}," t.name));\n",[32,1881,494],{"id":1882},"topic-mapping-5",[496,1884,1885,1895],{},[499,1886,1887],{},[502,1888,1889,1891,1893],{},[505,1890,507],{},[505,1892,510],{},[505,1894,513],{},[515,1896,1897,1909,1921],{},[502,1898,1899,1904,1907],{},[520,1900,1901],{},[19,1902,1903],{},"_tools/registry",[520,1905,1906],{},"Tool registration (retained)",[520,1908,530],{},[502,1910,1911,1916,1919],{},[520,1912,1913],{},[19,1914,1915],{},"_tools/invoke",[520,1917,1918],{},"Tool invocation requests",[520,1920,530],{},[502,1922,1923,1928,1931],{},[520,1924,1925],{},[19,1926,1927],{},"_tools/result",[520,1929,1930],{},"Tool invocation results",[520,1932,530],{},[24,1934,1936],{"id":1935},"tenant-isolation","Tenant Isolation",[15,1938,1939,1940,1945],{},"All six coordination patterns work seamlessly with ",[1941,1942,1944],"a",{"href":1943},"/docs/scopes/getting-started","Access Scopes"," for multi-tenant deployments. When you assign an agent actor to a scope, the coordination topics are automatically namespaced under the scope slug.",[15,1947,1948,1949,1952,1953,1956],{},"For example, a Handoff dispatch topic for a scoped actor becomes ",[19,1950,1951],{},"agents-app/tenant-slug/_handoff/dispatch"," instead of ",[19,1954,1955],{},"agents-app/_handoff/dispatch",". This means an orchestrator in one tenant cannot dispatch tasks to workers in another tenant. The isolation applies to all patterns - Inbox, Blackboard, Observe, Approve, and Tools - with no changes to your agent code.",[15,1958,1959,1960,1964],{},"To set up tenant isolation for your agents, create a scope for each tenant and assign each tenant's agent actors to that scope. See the ",[1941,1961,1963],{"href":1962},"/docs/scopes/multi-tenancy","Multi-Tenant Patterns"," guide for step-by-step implementation details.",[1966,1967,1968],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":63,"searchDepth":77,"depth":77,"links":1970},[1971,1977,1982,1987,1992,1997,2002],{"id":26,"depth":77,"text":27,"children":1972},[1973,1974,1975,1976],{"id":34,"depth":105,"text":35},{"id":51,"depth":105,"text":52},{"id":314,"depth":105,"text":315},{"id":493,"depth":105,"text":494},{"id":558,"depth":77,"text":559,"children":1978},[1979,1980,1981],{"id":565,"depth":105,"text":35},{"id":579,"depth":105,"text":580},{"id":722,"depth":105,"text":494},{"id":751,"depth":77,"text":752,"children":1983},[1984,1985,1986],{"id":758,"depth":105,"text":35},{"id":772,"depth":105,"text":580},{"id":1022,"depth":105,"text":494},{"id":1063,"depth":77,"text":1064,"children":1988},[1989,1990,1991],{"id":1070,"depth":105,"text":35},{"id":1087,"depth":105,"text":580},{"id":1313,"depth":105,"text":494},{"id":1355,"depth":77,"text":1356,"children":1993},[1994,1995,1996],{"id":1362,"depth":105,"text":35},{"id":1379,"depth":105,"text":580},{"id":1600,"depth":105,"text":494},{"id":1641,"depth":77,"text":1642,"children":1998},[1999,2000,2001],{"id":1648,"depth":105,"text":35},{"id":1662,"depth":105,"text":580},{"id":1882,"depth":105,"text":494},{"id":1935,"depth":77,"text":1936},"Deep dive on the six coordination patterns in @nolag/agents: Handoff, Inbox, Blackboard, Observe, Approve, and Tools.","md",{},"/docs/agents/patterns",{"title":5,"description":2003},"docs/agents/patterns","Z5sIXMplKA_HkmEAYaewzn0FrwczgIiYkOvo2RluA8A",1788160342377]