[{"data":1,"prerenderedAt":982},["ShallowReactive",2],{"docs:/docs/agents/composition":3},{"id":4,"title":5,"body":6,"description":975,"extension":976,"meta":977,"navigation":136,"path":978,"seo":979,"stem":980,"__hash__":981},"docs/docs/agents/composition.md","Blueprint Composition for Agents",{"type":7,"value":8,"toc":960},"minimark",[9,14,18,23,31,43,48,67,71,80,486,490,548,552,562,866,870,874,877,881,884,888,898,902,956],[10,11,13],"h1",{"id":12},"blueprint-composition","Blueprint Composition",[15,16,17],"p",{},"Combine the agents Blueprint with other Blueprints to build powerful real-time applications.",[19,20,22],"h2",{"id":21},"how-composition-works","How Composition Works",[15,24,25,26,30],{},"NoLag Blueprints are independent apps within the same project. Each Blueprint manages its own topics, rooms, and QoS settings. Composition happens through ",[27,28,29],"strong",{},"cross-app actor access",": a single actor can connect to multiple apps simultaneously.",[15,32,33,34,38,39,42],{},"For example, an actor representing a chatbot can connect to both a ",[35,36,37],"code",{},"@nolag/chat"," app (for user-facing messaging) and a ",[35,40,41],{},"@nolag/agents"," app (for AI coordination). The actor bridges the two apps, forwarding user messages to the agent workflow and sending agent responses back to the chat.",[44,45,47],"h3",{"id":46},"key-concepts","Key concepts",[49,50,51,58,61,64],"ul",{},[52,53,54,57],"li",{},[27,55,56],{},"Actors are created at the project level"," and granted access to specific apps",[52,59,60],{},"A single actor can have tokens for multiple apps",[52,62,63],{},"Each app connection is independent - different rooms, topics, and QoS",[52,65,66],{},"The actor code bridges the apps by listening on one and publishing on the other",[19,68,70],{"id":69},"example-agentic-chatbot","Example: Agentic Chatbot",[15,72,73,74,76,77,79],{},"A customer support chatbot that uses ",[35,75,37],{}," for the user-facing interface and ",[35,78,41],{}," for the AI backend. When a user sends a message, the bot dispatches it as a task to a customer-support agent, then sends the response back to the chat room.",[81,82,83],"code-tabs",{},[84,85,91],"pre",{"className":86,"code":87,"filename":88,"language":89,"meta":90,"style":90},"language-typescript shiki shiki-themes github-light github-dark","import { NoLagChat } from \"@nolag/chat\";\nimport { NoLagAgents } from \"@nolag/agents\";\n\n// Same actor connects to both apps\nconst chat = new NoLagChat(ACTOR_TOKEN_CHAT);\nconst agents = new NoLagAgents(ACTOR_TOKEN_AGENTS);\n\nawait Promise.all([chat.connect(), agents.connect()]);\n\n// User-facing chat room\nconst chatRoom = chat.joinRoom(\"support\");\n\n// Agent coordination room\nconst agentRoom = agents.joinRoom(\"support-agents\");\n\n// When user sends a message, dispatch to agent workflow\nchatRoom.on(\"message\", async (msg) => {\n  if (msg.sender.id !== \"bot\") {\n    await agentRoom.handoff.dispatch({\n      type: \"respond\",\n      payload: { userMessage: msg.text, context: chatRoom.getMessages() },\n      capabilities: [\"customer-support\"],\n    });\n  }\n});\n\n// When agent completes, send response back to chat\nagentRoom.handoff.onResult(async (result) => {\n  await chatRoom.sendMessage(result.data.response);\n});\n","TypeScript","typescript","",[35,92,93,116,131,138,145,174,196,201,230,235,241,264,269,275,297,302,308,344,362,377,389,401,413,419,425,431,436,442,466,481],{"__ignoreMap":90},[94,95,98,102,106,109,113],"span",{"class":96,"line":97},"line",1,[94,99,101],{"class":100},"szBVR","import",[94,103,105],{"class":104},"sVt8B"," { NoLagChat } ",[94,107,108],{"class":100},"from",[94,110,112],{"class":111},"sZZnC"," \"@nolag/chat\"",[94,114,115],{"class":104},";\n",[94,117,119,121,124,126,129],{"class":96,"line":118},2,[94,120,101],{"class":100},[94,122,123],{"class":104}," { NoLagAgents } ",[94,125,108],{"class":100},[94,127,128],{"class":111}," \"@nolag/agents\"",[94,130,115],{"class":104},[94,132,134],{"class":96,"line":133},3,[94,135,137],{"emptyLinePlaceholder":136},true,"\n",[94,139,141],{"class":96,"line":140},4,[94,142,144],{"class":143},"sJ8bj","// Same actor connects to both apps\n",[94,146,148,151,155,158,161,165,168,171],{"class":96,"line":147},5,[94,149,150],{"class":100},"const",[94,152,154],{"class":153},"sj4cs"," chat",[94,156,157],{"class":100}," =",[94,159,160],{"class":100}," new",[94,162,164],{"class":163},"sScJk"," NoLagChat",[94,166,167],{"class":104},"(",[94,169,170],{"class":153},"ACTOR_TOKEN_CHAT",[94,172,173],{"class":104},");\n",[94,175,177,179,182,184,186,189,191,194],{"class":96,"line":176},6,[94,178,150],{"class":100},[94,180,181],{"class":153}," agents",[94,183,157],{"class":100},[94,185,160],{"class":100},[94,187,188],{"class":163}," NoLagAgents",[94,190,167],{"class":104},[94,192,193],{"class":153},"ACTOR_TOKEN_AGENTS",[94,195,173],{"class":104},[94,197,199],{"class":96,"line":198},7,[94,200,137],{"emptyLinePlaceholder":136},[94,202,204,207,210,213,216,219,222,225,227],{"class":96,"line":203},8,[94,205,206],{"class":100},"await",[94,208,209],{"class":153}," Promise",[94,211,212],{"class":104},".",[94,214,215],{"class":163},"all",[94,217,218],{"class":104},"([chat.",[94,220,221],{"class":163},"connect",[94,223,224],{"class":104},"(), agents.",[94,226,221],{"class":163},[94,228,229],{"class":104},"()]);\n",[94,231,233],{"class":96,"line":232},9,[94,234,137],{"emptyLinePlaceholder":136},[94,236,238],{"class":96,"line":237},10,[94,239,240],{"class":143},"// User-facing chat room\n",[94,242,244,246,249,251,254,257,259,262],{"class":96,"line":243},11,[94,245,150],{"class":100},[94,247,248],{"class":153}," chatRoom",[94,250,157],{"class":100},[94,252,253],{"class":104}," chat.",[94,255,256],{"class":163},"joinRoom",[94,258,167],{"class":104},[94,260,261],{"class":111},"\"support\"",[94,263,173],{"class":104},[94,265,267],{"class":96,"line":266},12,[94,268,137],{"emptyLinePlaceholder":136},[94,270,272],{"class":96,"line":271},13,[94,273,274],{"class":143},"// Agent coordination room\n",[94,276,278,280,283,285,288,290,292,295],{"class":96,"line":277},14,[94,279,150],{"class":100},[94,281,282],{"class":153}," agentRoom",[94,284,157],{"class":100},[94,286,287],{"class":104}," agents.",[94,289,256],{"class":163},[94,291,167],{"class":104},[94,293,294],{"class":111},"\"support-agents\"",[94,296,173],{"class":104},[94,298,300],{"class":96,"line":299},15,[94,301,137],{"emptyLinePlaceholder":136},[94,303,305],{"class":96,"line":304},16,[94,306,307],{"class":143},"// When user sends a message, dispatch to agent workflow\n",[94,309,311,314,317,319,322,325,328,331,335,338,341],{"class":96,"line":310},17,[94,312,313],{"class":104},"chatRoom.",[94,315,316],{"class":163},"on",[94,318,167],{"class":104},[94,320,321],{"class":111},"\"message\"",[94,323,324],{"class":104},", ",[94,326,327],{"class":100},"async",[94,329,330],{"class":104}," (",[94,332,334],{"class":333},"s4XuR","msg",[94,336,337],{"class":104},") ",[94,339,340],{"class":100},"=>",[94,342,343],{"class":104}," {\n",[94,345,347,350,353,356,359],{"class":96,"line":346},18,[94,348,349],{"class":100},"  if",[94,351,352],{"class":104}," (msg.sender.id ",[94,354,355],{"class":100},"!==",[94,357,358],{"class":111}," \"bot\"",[94,360,361],{"class":104},") {\n",[94,363,365,368,371,374],{"class":96,"line":364},19,[94,366,367],{"class":100},"    await",[94,369,370],{"class":104}," agentRoom.handoff.",[94,372,373],{"class":163},"dispatch",[94,375,376],{"class":104},"({\n",[94,378,380,383,386],{"class":96,"line":379},20,[94,381,382],{"class":104},"      type: ",[94,384,385],{"class":111},"\"respond\"",[94,387,388],{"class":104},",\n",[94,390,392,395,398],{"class":96,"line":391},21,[94,393,394],{"class":104},"      payload: { userMessage: msg.text, context: chatRoom.",[94,396,397],{"class":163},"getMessages",[94,399,400],{"class":104},"() },\n",[94,402,404,407,410],{"class":96,"line":403},22,[94,405,406],{"class":104},"      capabilities: [",[94,408,409],{"class":111},"\"customer-support\"",[94,411,412],{"class":104},"],\n",[94,414,416],{"class":96,"line":415},23,[94,417,418],{"class":104},"    });\n",[94,420,422],{"class":96,"line":421},24,[94,423,424],{"class":104},"  }\n",[94,426,428],{"class":96,"line":427},25,[94,429,430],{"class":104},"});\n",[94,432,434],{"class":96,"line":433},26,[94,435,137],{"emptyLinePlaceholder":136},[94,437,439],{"class":96,"line":438},27,[94,440,441],{"class":143},"// When agent completes, send response back to chat\n",[94,443,445,448,451,453,455,457,460,462,464],{"class":96,"line":444},28,[94,446,447],{"class":104},"agentRoom.handoff.",[94,449,450],{"class":163},"onResult",[94,452,167],{"class":104},[94,454,327],{"class":100},[94,456,330],{"class":104},[94,458,459],{"class":333},"result",[94,461,337],{"class":104},[94,463,340],{"class":100},[94,465,343],{"class":104},[94,467,469,472,475,478],{"class":96,"line":468},29,[94,470,471],{"class":100},"  await",[94,473,474],{"class":104}," chatRoom.",[94,476,477],{"class":163},"sendMessage",[94,479,480],{"class":104},"(result.data.response);\n",[94,482,484],{"class":96,"line":483},30,[94,485,430],{"class":104},[44,487,489],{"id":488},"architecture","Architecture",[491,492,493,509],"table",{},[494,495,496],"thead",{},[497,498,499,503,506],"tr",{},[500,501,502],"th",{},"Component",[500,504,505],{},"Blueprint",[500,507,508],{},"Role",[510,511,512,525,536],"tbody",{},[497,513,514,518,522],{},[515,516,517],"td",{},"Chat UI",[515,519,520],{},[35,521,37],{},[515,523,524],{},"User-facing chat rooms with presence and typing",[497,526,527,530,533],{},[515,528,529],{},"Bot bridge",[515,531,532],{},"Both",[515,534,535],{},"Listens to chat, dispatches to agents, sends responses",[497,537,538,541,545],{},[515,539,540],{},"AI workers",[515,542,543],{},[35,544,41],{},[515,546,547],{},"Process user queries with LLM, return responses",[19,549,551],{"id":550},"example-monitored-iot-fleet","Example: Monitored IoT Fleet",[15,553,554,555,558,559,561],{},"A delivery fleet that uses ",[35,556,557],{},"@nolag/track"," for real-time GPS tracking and ",[35,560,41],{}," for intelligent monitoring. When a vehicle enters a geofence, an agent analyzes the delivery and updates shared fleet status.",[81,563,564],{},[84,565,567],{"className":86,"code":566,"filename":88,"language":89,"meta":90,"style":90},"import { NoLagTrack } from \"@nolag/track\";\nimport { NoLagAgents } from \"@nolag/agents\";\n\nconst track = new NoLagTrack(ACTOR_TOKEN_TRACK);\nconst agents = new NoLagAgents(ACTOR_TOKEN_AGENTS);\n\nawait Promise.all([track.connect(), agents.connect()]);\n\nconst fleet = track.joinRoom(\"delivery-fleet\");\nconst agentRoom = agents.joinRoom(\"fleet-monitor\");\n\n// When a vehicle enters a geofence, trigger agent analysis\nfleet.on(\"geofence:enter\", async (event) => {\n  await agentRoom.handoff.dispatch({\n    type: \"analyze-delivery\",\n    payload: { vehicleId: event.vehicleId, zone: event.zone },\n    capabilities: [\"logistics\"],\n  });\n});\n\n// Agent updates shared state with fleet overview\nagentRoom.handoff.onResult(async (result) => {\n  await agentRoom.blackboard.update(\"fleet-status\", (prev) => ({\n    ...prev,\n    [result.data.vehicleId]: result.data.status,\n  }));\n});\n",[35,568,569,583,595,599,620,638,642,663,667,688,707,711,716,743,753,763,768,778,783,787,791,796,816,844,852,857,862],{"__ignoreMap":90},[94,570,571,573,576,578,581],{"class":96,"line":97},[94,572,101],{"class":100},[94,574,575],{"class":104}," { NoLagTrack } ",[94,577,108],{"class":100},[94,579,580],{"class":111}," \"@nolag/track\"",[94,582,115],{"class":104},[94,584,585,587,589,591,593],{"class":96,"line":118},[94,586,101],{"class":100},[94,588,123],{"class":104},[94,590,108],{"class":100},[94,592,128],{"class":111},[94,594,115],{"class":104},[94,596,597],{"class":96,"line":133},[94,598,137],{"emptyLinePlaceholder":136},[94,600,601,603,606,608,610,613,615,618],{"class":96,"line":140},[94,602,150],{"class":100},[94,604,605],{"class":153}," track",[94,607,157],{"class":100},[94,609,160],{"class":100},[94,611,612],{"class":163}," NoLagTrack",[94,614,167],{"class":104},[94,616,617],{"class":153},"ACTOR_TOKEN_TRACK",[94,619,173],{"class":104},[94,621,622,624,626,628,630,632,634,636],{"class":96,"line":147},[94,623,150],{"class":100},[94,625,181],{"class":153},[94,627,157],{"class":100},[94,629,160],{"class":100},[94,631,188],{"class":163},[94,633,167],{"class":104},[94,635,193],{"class":153},[94,637,173],{"class":104},[94,639,640],{"class":96,"line":176},[94,641,137],{"emptyLinePlaceholder":136},[94,643,644,646,648,650,652,655,657,659,661],{"class":96,"line":198},[94,645,206],{"class":100},[94,647,209],{"class":153},[94,649,212],{"class":104},[94,651,215],{"class":163},[94,653,654],{"class":104},"([track.",[94,656,221],{"class":163},[94,658,224],{"class":104},[94,660,221],{"class":163},[94,662,229],{"class":104},[94,664,665],{"class":96,"line":203},[94,666,137],{"emptyLinePlaceholder":136},[94,668,669,671,674,676,679,681,683,686],{"class":96,"line":232},[94,670,150],{"class":100},[94,672,673],{"class":153}," fleet",[94,675,157],{"class":100},[94,677,678],{"class":104}," track.",[94,680,256],{"class":163},[94,682,167],{"class":104},[94,684,685],{"class":111},"\"delivery-fleet\"",[94,687,173],{"class":104},[94,689,690,692,694,696,698,700,702,705],{"class":96,"line":237},[94,691,150],{"class":100},[94,693,282],{"class":153},[94,695,157],{"class":100},[94,697,287],{"class":104},[94,699,256],{"class":163},[94,701,167],{"class":104},[94,703,704],{"class":111},"\"fleet-monitor\"",[94,706,173],{"class":104},[94,708,709],{"class":96,"line":243},[94,710,137],{"emptyLinePlaceholder":136},[94,712,713],{"class":96,"line":266},[94,714,715],{"class":143},"// When a vehicle enters a geofence, trigger agent analysis\n",[94,717,718,721,723,725,728,730,732,734,737,739,741],{"class":96,"line":271},[94,719,720],{"class":104},"fleet.",[94,722,316],{"class":163},[94,724,167],{"class":104},[94,726,727],{"class":111},"\"geofence:enter\"",[94,729,324],{"class":104},[94,731,327],{"class":100},[94,733,330],{"class":104},[94,735,736],{"class":333},"event",[94,738,337],{"class":104},[94,740,340],{"class":100},[94,742,343],{"class":104},[94,744,745,747,749,751],{"class":96,"line":277},[94,746,471],{"class":100},[94,748,370],{"class":104},[94,750,373],{"class":163},[94,752,376],{"class":104},[94,754,755,758,761],{"class":96,"line":299},[94,756,757],{"class":104},"    type: ",[94,759,760],{"class":111},"\"analyze-delivery\"",[94,762,388],{"class":104},[94,764,765],{"class":96,"line":304},[94,766,767],{"class":104},"    payload: { vehicleId: event.vehicleId, zone: event.zone },\n",[94,769,770,773,776],{"class":96,"line":310},[94,771,772],{"class":104},"    capabilities: [",[94,774,775],{"class":111},"\"logistics\"",[94,777,412],{"class":104},[94,779,780],{"class":96,"line":346},[94,781,782],{"class":104},"  });\n",[94,784,785],{"class":96,"line":364},[94,786,430],{"class":104},[94,788,789],{"class":96,"line":379},[94,790,137],{"emptyLinePlaceholder":136},[94,792,793],{"class":96,"line":391},[94,794,795],{"class":143},"// Agent updates shared state with fleet overview\n",[94,797,798,800,802,804,806,808,810,812,814],{"class":96,"line":403},[94,799,447],{"class":104},[94,801,450],{"class":163},[94,803,167],{"class":104},[94,805,327],{"class":100},[94,807,330],{"class":104},[94,809,459],{"class":333},[94,811,337],{"class":104},[94,813,340],{"class":100},[94,815,343],{"class":104},[94,817,818,820,823,826,828,831,834,837,839,841],{"class":96,"line":415},[94,819,471],{"class":100},[94,821,822],{"class":104}," agentRoom.blackboard.",[94,824,825],{"class":163},"update",[94,827,167],{"class":104},[94,829,830],{"class":111},"\"fleet-status\"",[94,832,833],{"class":104},", (",[94,835,836],{"class":333},"prev",[94,838,337],{"class":104},[94,840,340],{"class":100},[94,842,843],{"class":104}," ({\n",[94,845,846,849],{"class":96,"line":421},[94,847,848],{"class":100},"    ...",[94,850,851],{"class":104},"prev,\n",[94,853,854],{"class":96,"line":427},[94,855,856],{"class":104},"    [result.data.vehicleId]: result.data.status,\n",[94,858,859],{"class":96,"line":433},[94,860,861],{"class":104},"  }));\n",[94,863,864],{"class":96,"line":438},[94,865,430],{"class":104},[19,867,869],{"id":868},"composition-patterns","Composition Patterns",[44,871,873],{"id":872},"event-bridge","Event bridge",[15,875,876],{},"The simplest pattern: listen for events on one Blueprint and trigger actions on another. The chatbot example above uses this - chat messages trigger agent tasks.",[44,878,880],{"id":879},"shared-state-sync","Shared state sync",[15,882,883],{},"Use the Blackboard pattern to maintain state that's derived from events in other Blueprints. The IoT example updates fleet status based on tracking events.",[44,885,887],{"id":886},"approval-pipeline","Approval pipeline",[15,889,890,891,893,894,897],{},"Combine ",[35,892,41],{}," (Approve pattern) with ",[35,895,896],{},"@nolag/notify"," to send approval requests as notifications. When a human approves via the notification, the agent workflow continues.",[19,899,901],{"id":900},"which-blueprints-compose-well","Which Blueprints compose well?",[491,903,904,914],{},[494,905,906],{},[497,907,908,911],{},[500,909,910],{},"Combination",[500,912,913],{},"Use case",[510,915,916,924,932,940,948],{},[497,917,918,921],{},[515,919,920],{},"Agents + Chat",[515,922,923],{},"Agentic chatbots, AI-assisted customer support",[497,925,926,929],{},[515,927,928],{},"Agents + Notify",[515,930,931],{},"Agent-triggered notifications, approval requests",[497,933,934,937],{},[515,935,936],{},"Agents + Track",[515,938,939],{},"Intelligent fleet monitoring, autonomous logistics",[497,941,942,945],{},[515,943,944],{},"Agents + Dash",[515,946,947],{},"AI-powered dashboards, automated reporting",[497,949,950,953],{},[515,951,952],{},"Agents + IoT",[515,954,955],{},"Autonomous device management, predictive maintenance",[957,958,959],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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":90,"searchDepth":118,"depth":118,"links":961},[962,965,968,969,974],{"id":21,"depth":118,"text":22,"children":963},[964],{"id":46,"depth":133,"text":47},{"id":69,"depth":118,"text":70,"children":966},[967],{"id":488,"depth":133,"text":489},{"id":550,"depth":118,"text":551},{"id":868,"depth":118,"text":869,"children":970},[971,972,973],{"id":872,"depth":133,"text":873},{"id":879,"depth":133,"text":880},{"id":886,"depth":133,"text":887},{"id":900,"depth":118,"text":901},"How to compose the agents Blueprint with chat, notify, track, and other Blueprints via cross-app actor access.","md",{},"/docs/agents/composition",{"title":5,"description":975},"docs/agents/composition","CyM3e54ySLRa3KYbRKrCcb2mmoUk7VoAKsFX1adC_TI",1788160342098]