[{"data":1,"prerenderedAt":981},["ShallowReactive",2],{"blog:/blog/human-to-agent-realtime":3},{"id":4,"title":5,"author":6,"body":7,"category":970,"date":971,"description":972,"excerpt":973,"extension":974,"meta":975,"navigation":465,"path":976,"readTime":977,"seo":978,"stem":979,"__hash__":980},"blog/blog/human-to-agent-realtime.md","From Human Realtime to Agent Realtime","Henco Burger",{"type":8,"value":9,"toc":960},"minimark",[10,14,17,22,25,40,51,55,66,86,100,104,107,342,397,408,412,419,802,805,809,820,827,831,834,923,926,930,933,936,940,943,950,956],[11,12,13],"p",{},"NoLag was built to power human real-time experiences: chat rooms where people exchange messages, dashboards where operators monitor live data, and tracking systems where dispatchers watch vehicles move on a map. When we started exploring multi-agent AI systems, we realized the infrastructure we built for humans maps almost perfectly to agent coordination.",[11,15,16],{},"This post explains how NoLag's real-time primitives translate to agent coordination patterns, the design decisions we made for each, and the performance characteristics that matter for agent workloads.",[18,19,21],"h2",{"id":20},"the-mapping","The Mapping",[11,23,24],{},"Real-time messaging has three core primitives: topics (named channels for routing), rooms (groups of related topics), and presence (who is connected). Agent coordination has the same three needs: task routing, workflow grouping, and agent health tracking.",[26,27,28],"code-tabs",{},[29,30,37],"pre",{"className":31,"code":33,"filename":34,"language":35,"meta":36},[32],"language-text","# Human chat (@nolag/chat): the topics inside a room\nmessages     chat messages\n_typing      typing indicators, ephemeral\n_stream      live token chunks of a streamed message, ephemeral\n\n# Agent coordination (@nolag/agents): the topics inside a room\ntasks        task envelopes (Handoff)\nresults      result envelopes, routed to the dispatcher by filter\nstate        shared key-value state (Blackboard), published retained\nevents       observability stream (Observe)\ninbox        direct agent-to-agent messages (Inbox)\ntools        tool requests (Tools)\napproval     human-in-the-loop requests and decisions (Approve), published retained\n","Topic Mapping","text","",[38,39,33],"code",{"__ignoreMap":36},[11,41,42,43,46,47,50],{},"The topic names change. The semantics are different. But the underlying infrastructure - message routing, delivery guarantees, retained state, and fan-out - is identical. Both wrappers publish at the client's default QoS (1 on the broker hop); the two agent topics that hold state rather than a stream, ",[38,44,45],{},"state"," and ",[38,48,49],{},"approval",", are published retained so a late joiner receives the latest value.",[18,52,54],{"id":53},"topics-as-task-queues","Topics as Task Queues",[11,56,57,58,61,62,65],{},"In a chat app, a topic is a channel where messages flow from publishers to subscribers. In an agent system, a topic is a task queue. The Handoff pattern uses ",[38,59,60],{},"tasks"," as a work queue: the orchestrator publishes task envelopes, workers subscribe and act on the ones whose ",[38,63,64],{},"capability"," they registered for.",[11,67,68,69,71,72,75,76,79,80,46,82,85],{},"The property that turns a topic into a queue is not a QoS level, it is load balancing. By default every subscriber to ",[38,70,60],{}," receives every task, which is what you want for a single worker per capability and wrong for a pool of identical workers. Connect the pool with ",[38,73,74],{},"loadBalance: true"," and a shared ",[38,77,78],{},"loadBalanceGroup"," and the broker delivers each task to exactly one member of the group. The agents SDK inherits that setting from the core client for ",[38,81,60],{},[38,83,84],{},"tools"," only, and forces it off for the broadcast topics.",[11,87,88,89,46,91,93,94,99],{},"Retained messages serve a different purpose in each context. For chat, retention on the broker is not used: history lives in your own store. For agents, retention is how ",[38,90,45],{},[38,92,49],{}," behave like a whiteboard rather than a stream: whoever joins sees the current value without waiting for the next write. Holding a task until a worker is available is a separate feature, replay, and it applies only to load-balanced worker groups with persistent sessions on the hosted platform (see ",[95,96,98],"a",{"href":97},"/docs/concepts/replay","replay","); a lone worker that was offline when a task was dispatched does not get it later.",[18,101,103],{"id":102},"presence-as-health-monitoring","Presence as Health Monitoring",[11,105,106],{},"Human presence is simple: online, away, or offline. Agent presence needs more metadata: capabilities, model, provider, whatever routing needs. We extended the presence payload to carry this information without changing the underlying protocol.",[26,108,109,212],{},[29,110,115],{"className":111,"code":112,"filename":113,"language":114,"meta":36,"style":36},"language-json shiki shiki-themes github-light github-dark","{\n  \"actorTokenId\": \"at_live_7f3a...\",\n  \"presence\": {\n    \"userId\": \"u_8x2k9\",\n    \"username\": \"Alice\",\n    \"status\": \"online\"\n  },\n  \"joinedAt\": 1745827200000\n}\n","Human: a chat user's presence","json",[38,116,117,126,143,152,165,178,189,195,206],{"__ignoreMap":36},[118,119,122],"span",{"class":120,"line":121},"line",1,[118,123,125],{"class":124},"sVt8B","{\n",[118,127,129,133,136,140],{"class":120,"line":128},2,[118,130,132],{"class":131},"sj4cs","  \"actorTokenId\"",[118,134,135],{"class":124},": ",[118,137,139],{"class":138},"sZZnC","\"at_live_7f3a...\"",[118,141,142],{"class":124},",\n",[118,144,146,149],{"class":120,"line":145},3,[118,147,148],{"class":131},"  \"presence\"",[118,150,151],{"class":124},": {\n",[118,153,155,158,160,163],{"class":120,"line":154},4,[118,156,157],{"class":131},"    \"userId\"",[118,159,135],{"class":124},[118,161,162],{"class":138},"\"u_8x2k9\"",[118,164,142],{"class":124},[118,166,168,171,173,176],{"class":120,"line":167},5,[118,169,170],{"class":131},"    \"username\"",[118,172,135],{"class":124},[118,174,175],{"class":138},"\"Alice\"",[118,177,142],{"class":124},[118,179,181,184,186],{"class":120,"line":180},6,[118,182,183],{"class":131},"    \"status\"",[118,185,135],{"class":124},[118,187,188],{"class":138},"\"online\"\n",[118,190,192],{"class":120,"line":191},7,[118,193,194],{"class":124},"  },\n",[118,196,198,201,203],{"class":120,"line":197},8,[118,199,200],{"class":131},"  \"joinedAt\"",[118,202,135],{"class":124},[118,204,205],{"class":131},"1745827200000\n",[118,207,209],{"class":120,"line":208},9,[118,210,211],{"class":124},"}\n",[29,213,216],{"className":111,"code":214,"filename":215,"language":114,"meta":36,"style":36},"{\n  \"actorTokenId\": \"at_live_c41d...\",\n  \"presence\": {\n    \"name\": \"research-worker-3\",\n    \"role\": \"agent\",\n    \"capabilities\": [\"research\", \"finance\"],\n    \"metadata\": { \"model\": \"llama3.2\", \"provider\": \"local\" }\n  },\n  \"joinedAt\": 1745827200000,\n  \"status\": \"online\"\n}\n","Agent: a worker's presence",[38,217,218,222,233,239,251,263,283,312,316,327,337],{"__ignoreMap":36},[118,219,220],{"class":120,"line":121},[118,221,125],{"class":124},[118,223,224,226,228,231],{"class":120,"line":128},[118,225,132],{"class":131},[118,227,135],{"class":124},[118,229,230],{"class":138},"\"at_live_c41d...\"",[118,232,142],{"class":124},[118,234,235,237],{"class":120,"line":145},[118,236,148],{"class":131},[118,238,151],{"class":124},[118,240,241,244,246,249],{"class":120,"line":154},[118,242,243],{"class":131},"    \"name\"",[118,245,135],{"class":124},[118,247,248],{"class":138},"\"research-worker-3\"",[118,250,142],{"class":124},[118,252,253,256,258,261],{"class":120,"line":167},[118,254,255],{"class":131},"    \"role\"",[118,257,135],{"class":124},[118,259,260],{"class":138},"\"agent\"",[118,262,142],{"class":124},[118,264,265,268,271,274,277,280],{"class":120,"line":180},[118,266,267],{"class":131},"    \"capabilities\"",[118,269,270],{"class":124},": [",[118,272,273],{"class":138},"\"research\"",[118,275,276],{"class":124},", ",[118,278,279],{"class":138},"\"finance\"",[118,281,282],{"class":124},"],\n",[118,284,285,288,291,294,296,299,301,304,306,309],{"class":120,"line":191},[118,286,287],{"class":131},"    \"metadata\"",[118,289,290],{"class":124},": { ",[118,292,293],{"class":131},"\"model\"",[118,295,135],{"class":124},[118,297,298],{"class":138},"\"llama3.2\"",[118,300,276],{"class":124},[118,302,303],{"class":131},"\"provider\"",[118,305,135],{"class":124},[118,307,308],{"class":138},"\"local\"",[118,310,311],{"class":124}," }\n",[118,313,314],{"class":120,"line":197},[118,315,194],{"class":124},[118,317,318,320,322,325],{"class":120,"line":208},[118,319,200],{"class":131},[118,321,135],{"class":124},[118,323,324],{"class":131},"1745827200000",[118,326,142],{"class":124},[118,328,330,333,335],{"class":120,"line":329},10,[118,331,332],{"class":131},"  \"status\"",[118,334,135],{"class":124},[118,336,188],{"class":138},[118,338,340],{"class":120,"line":339},11,[118,341,211],{"class":124},[11,343,344,345,348,349,352,353,356,357,360,361,363,364,367,368,276,371,374,375,46,378,381,382,385,386,276,389,392,393,396],{},"Both are the same ",[38,346,347],{},"ActorPresence"," shape: an ",[38,350,351],{},"actorTokenId",", the ",[38,354,355],{},"presence"," data the actor set, and (in fetched snapshots) ",[38,358,359],{},"joinedAt",". The agents SDK fills ",[38,362,355],{}," with ",[38,365,366],{},"AgentPresenceData"," (",[38,369,370],{},"name",[38,372,373],{},"role",", optional ",[38,376,377],{},"capabilities",[38,379,380],{},"metadata","); the outer ",[38,383,384],{},"status"," is ",[38,387,388],{},"online",[38,390,391],{},"offline",", or ",[38,394,395],{},"waking"," and only appears for persistent agents that stay discoverable while disconnected.",[11,398,399,400,403,404,407],{},"The Handoff pattern uses presence as a gate. Before publishing a task, ",[38,401,402],{},"dispatch()"," looks at who is in the room and throws if no connected agent lists the required capability. It does not look at load or capacity, because presence does not carry them: the worker's own ",[38,405,406],{},"onTask"," filter and, for pools, the broker's load-balance group decide who acts on a task.",[18,409,411],{"id":410},"qos-levels-for-different-patterns","QoS Levels for Different Patterns",[11,413,414,415,418],{},"Not every agent message needs the same delivery guarantee. Just like in human real-time, the right QoS level depends on the consequence of a lost message, and it is worth being precise about what QoS covers on NoLag. The level you pick (0, 1 or 2, default 1) is applied to the broker's internal MQTT hop. The WebSocket leg between your process and the broker has an optional ",[38,416,417],{},"published"," acknowledgement, surfaced as the emit callback, and no resend. There is no exactly-once guarantee end to end, so the envelopes carry the ids you need to tolerate a duplicate.",[26,420,421],{},[29,422,427],{"className":423,"code":424,"filename":425,"language":426,"meta":36,"style":36},"language-typescript shiki shiki-themes github-light github-dark","import { NoLag } from \"@nolag/js-sdk\";\nimport { NoLagAgents, Handoff, createStateEnvelope } from \"@nolag/agents\";\n\nconst client = NoLag(TOKEN);\nawait client.connect();\n\n// QoS 0 (fire and forget): typing indicators, cursor positions.\n// Lost messages are harmless: the next update overwrites anyway.\nconst doc = client.setApp(COLLAB_APP_SLUG).setRoom(\"my-doc\");\ndoc.emit(\"cursors\", { x: 120, y: 48 }, { qos: 0 });\n\n// QoS 1 (at least once): the default for everything the wrappers publish.\n// Results carry a correlationId, so a pending dispatch resolves once and a\n// duplicate result is dropped. Tasks carry a taskId for your worker to do\n// the same on its side.\nconst agents = new NoLagAgents({ client, appName: AGENTS_APP_SLUG, agentId: \"orchestrator\" });\nawait agents.ready();\nconst room = agents.room(\"research-pipeline\");\nconst handoff = new Handoff(room);\nconst result = await handoff.dispatch(\"research\", { query }, { waitForResult: true });\n\n// QoS 2 on the broker hop: for a raw publish where you also want the\n// broker-side dedup. It adds nothing on the WebSocket leg.\nconst envelope = createStateEnvelope(\"run:42\", \"started\", 1, agents.agentId);\nroom.context.emit(\"state\", envelope, { qos: 2, retain: true });\n","QoS Choices","typescript",[38,428,429,447,461,467,491,505,509,515,520,552,586,590,596,602,608,614,644,657,679,697,728,733,739,745,776],{"__ignoreMap":36},[118,430,431,435,438,441,444],{"class":120,"line":121},[118,432,434],{"class":433},"szBVR","import",[118,436,437],{"class":124}," { NoLag } ",[118,439,440],{"class":433},"from",[118,442,443],{"class":138}," \"@nolag/js-sdk\"",[118,445,446],{"class":124},";\n",[118,448,449,451,454,456,459],{"class":120,"line":128},[118,450,434],{"class":433},[118,452,453],{"class":124}," { NoLagAgents, Handoff, createStateEnvelope } ",[118,455,440],{"class":433},[118,457,458],{"class":138}," \"@nolag/agents\"",[118,460,446],{"class":124},[118,462,463],{"class":120,"line":145},[118,464,466],{"emptyLinePlaceholder":465},true,"\n",[118,468,469,472,475,478,482,485,488],{"class":120,"line":154},[118,470,471],{"class":433},"const",[118,473,474],{"class":131}," client",[118,476,477],{"class":433}," =",[118,479,481],{"class":480},"sScJk"," NoLag",[118,483,484],{"class":124},"(",[118,486,487],{"class":131},"TOKEN",[118,489,490],{"class":124},");\n",[118,492,493,496,499,502],{"class":120,"line":167},[118,494,495],{"class":433},"await",[118,497,498],{"class":124}," client.",[118,500,501],{"class":480},"connect",[118,503,504],{"class":124},"();\n",[118,506,507],{"class":120,"line":180},[118,508,466],{"emptyLinePlaceholder":465},[118,510,511],{"class":120,"line":191},[118,512,514],{"class":513},"sJ8bj","// QoS 0 (fire and forget): typing indicators, cursor positions.\n",[118,516,517],{"class":120,"line":197},[118,518,519],{"class":513},"// Lost messages are harmless: the next update overwrites anyway.\n",[118,521,522,524,527,529,531,534,536,539,542,545,547,550],{"class":120,"line":208},[118,523,471],{"class":433},[118,525,526],{"class":131}," doc",[118,528,477],{"class":433},[118,530,498],{"class":124},[118,532,533],{"class":480},"setApp",[118,535,484],{"class":124},[118,537,538],{"class":131},"COLLAB_APP_SLUG",[118,540,541],{"class":124},").",[118,543,544],{"class":480},"setRoom",[118,546,484],{"class":124},[118,548,549],{"class":138},"\"my-doc\"",[118,551,490],{"class":124},[118,553,554,557,560,562,565,568,571,574,577,580,583],{"class":120,"line":329},[118,555,556],{"class":124},"doc.",[118,558,559],{"class":480},"emit",[118,561,484],{"class":124},[118,563,564],{"class":138},"\"cursors\"",[118,566,567],{"class":124},", { x: ",[118,569,570],{"class":131},"120",[118,572,573],{"class":124},", y: ",[118,575,576],{"class":131},"48",[118,578,579],{"class":124}," }, { qos: ",[118,581,582],{"class":131},"0",[118,584,585],{"class":124}," });\n",[118,587,588],{"class":120,"line":339},[118,589,466],{"emptyLinePlaceholder":465},[118,591,593],{"class":120,"line":592},12,[118,594,595],{"class":513},"// QoS 1 (at least once): the default for everything the wrappers publish.\n",[118,597,599],{"class":120,"line":598},13,[118,600,601],{"class":513},"// Results carry a correlationId, so a pending dispatch resolves once and a\n",[118,603,605],{"class":120,"line":604},14,[118,606,607],{"class":513},"// duplicate result is dropped. Tasks carry a taskId for your worker to do\n",[118,609,611],{"class":120,"line":610},15,[118,612,613],{"class":513},"// the same on its side.\n",[118,615,617,619,622,624,627,630,633,636,639,642],{"class":120,"line":616},16,[118,618,471],{"class":433},[118,620,621],{"class":131}," agents",[118,623,477],{"class":433},[118,625,626],{"class":433}," new",[118,628,629],{"class":480}," NoLagAgents",[118,631,632],{"class":124},"({ client, appName: ",[118,634,635],{"class":131},"AGENTS_APP_SLUG",[118,637,638],{"class":124},", agentId: ",[118,640,641],{"class":138},"\"orchestrator\"",[118,643,585],{"class":124},[118,645,647,649,652,655],{"class":120,"line":646},17,[118,648,495],{"class":433},[118,650,651],{"class":124}," agents.",[118,653,654],{"class":480},"ready",[118,656,504],{"class":124},[118,658,660,662,665,667,669,672,674,677],{"class":120,"line":659},18,[118,661,471],{"class":433},[118,663,664],{"class":131}," room",[118,666,477],{"class":433},[118,668,651],{"class":124},[118,670,671],{"class":480},"room",[118,673,484],{"class":124},[118,675,676],{"class":138},"\"research-pipeline\"",[118,678,490],{"class":124},[118,680,682,684,687,689,691,694],{"class":120,"line":681},19,[118,683,471],{"class":433},[118,685,686],{"class":131}," handoff",[118,688,477],{"class":433},[118,690,626],{"class":433},[118,692,693],{"class":480}," Handoff",[118,695,696],{"class":124},"(room);\n",[118,698,700,702,705,707,710,713,716,718,720,723,726],{"class":120,"line":699},20,[118,701,471],{"class":433},[118,703,704],{"class":131}," result",[118,706,477],{"class":433},[118,708,709],{"class":433}," await",[118,711,712],{"class":124}," handoff.",[118,714,715],{"class":480},"dispatch",[118,717,484],{"class":124},[118,719,273],{"class":138},[118,721,722],{"class":124},", { query }, { waitForResult: ",[118,724,725],{"class":131},"true",[118,727,585],{"class":124},[118,729,731],{"class":120,"line":730},21,[118,732,466],{"emptyLinePlaceholder":465},[118,734,736],{"class":120,"line":735},22,[118,737,738],{"class":513},"// QoS 2 on the broker hop: for a raw publish where you also want the\n",[118,740,742],{"class":120,"line":741},23,[118,743,744],{"class":513},"// broker-side dedup. It adds nothing on the WebSocket leg.\n",[118,746,748,750,753,755,758,760,763,765,768,770,773],{"class":120,"line":747},24,[118,749,471],{"class":433},[118,751,752],{"class":131}," envelope",[118,754,477],{"class":433},[118,756,757],{"class":480}," createStateEnvelope",[118,759,484],{"class":124},[118,761,762],{"class":138},"\"run:42\"",[118,764,276],{"class":124},[118,766,767],{"class":138},"\"started\"",[118,769,276],{"class":124},[118,771,772],{"class":131},"1",[118,774,775],{"class":124},", agents.agentId);\n",[118,777,779,782,784,786,789,792,795,798,800],{"class":120,"line":778},25,[118,780,781],{"class":124},"room.context.",[118,783,559],{"class":480},[118,785,484],{"class":124},[118,787,788],{"class":138},"\"state\"",[118,790,791],{"class":124},", envelope, { qos: ",[118,793,794],{"class":131},"2",[118,796,797],{"class":124},", retain: ",[118,799,725],{"class":131},[118,801,585],{"class":124},[11,803,804],{},"This is one of the advantages of building on real messaging infrastructure rather than a custom agent framework. Delivery levels are a solved problem in messaging. We don't need to reinvent them; we map each pattern to the level it needs and put the idempotency keys (task ids, correlation ids, state versions) in the envelopes so your handlers can be idempotent.",[18,806,808],{"id":807},"rooms-as-workflow-boundaries","Rooms as Workflow Boundaries",[11,810,811,812,815,816,819],{},"In chat, rooms group related conversations. In agent coordination, rooms group related workflows. A room called ",[38,813,814],{},"research-pipeline"," contains all the topics for that pipeline: task dispatch, results, shared state, and events. A separate room called ",[38,817,818],{},"content-review"," contains its own isolated set of topics.",[11,821,822,823,826],{},"This isolation is important. Just as you don't want messages from #general leaking into #engineering, you don't want tasks from one workflow accidentally being picked up by workers in another. Rooms provide that boundary for free. They are created on the control plane, never implicitly: subscribing to a room that does not exist returns ",[38,824,825],{},"unknown_topic",".",[18,828,830],{"id":829},"performance-characteristics","Performance Characteristics",[11,832,833],{},"Agent workloads have different performance profiles than human real-time:",[835,836,837,853],"table",{},[838,839,840],"thead",{},[841,842,843,847,850],"tr",{},[844,845,846],"th",{},"Metric",[844,848,849],{},"Human Realtime",[844,851,852],{},"Agent Realtime",[854,855,856,868,879,890,901,912],"tbody",{},[841,857,858,862,865],{},[859,860,861],"td",{},"Message size",[859,863,864],{},"Small (chat text, GPS coords)",[859,866,867],{},"Medium-large (task payloads, LLM outputs)",[841,869,870,873,876],{},[859,871,872],{},"Message rate",[859,874,875],{},"Bursty (typing, idle cycles)",[859,877,878],{},"Steady (continuous task dispatch)",[841,880,881,884,887],{},[859,882,883],{},"Latency sensitivity",[859,885,886],{},"High (users notice 200ms+)",[859,888,889],{},"Moderate (agents tolerate seconds)",[841,891,892,895,898],{},[859,893,894],{},"Delivery guarantee",[859,896,897],{},"Mixed (QoS 0-1)",[859,899,900],{},"QoS 1 with idempotent envelopes",[841,902,903,906,909],{},[859,904,905],{},"Connection count",[859,907,908],{},"Many (one per user/tab)",[859,910,911],{},"Few (one per agent process)",[841,913,914,917,920],{},[859,915,916],{},"Fan-out ratio",[859,918,919],{},"High (1:1000 in large rooms)",[859,921,922],{},"Low (1:1 task dispatch, 1:N observe)",[11,924,925],{},"Agent workloads typically involve fewer connections but larger payloads and stricter delivery requirements. NoLag's 900KB message size limit accommodates most LLM outputs. The binary MessagePack protocol keeps overhead low even for large payloads. And for worker pools, load-balanced groups with persistent sessions keep tasks from being lost while a worker restarts.",[18,927,929],{"id":928},"access-control-carries-over","Access Control Carries Over",[11,931,932],{},"In human systems, access control prevents unauthorized users from reading messages in rooms they haven't joined. In agent systems, the same ACL mechanism prevents agents from accessing workflows they shouldn't participate in.",[11,934,935],{},"Each agent connects with an actor token that grants access to specific apps and rooms. A research worker can only subscribe to topics in the research workflow. A monitoring dashboard can observe events but not dispatch tasks. The same per-topic ACL that protects chat messages protects agent coordination.",[18,937,939],{"id":938},"the-insight","The Insight",[11,941,942],{},"Agent coordination is a real-time messaging problem wearing a different hat. The primitives are the same: publish, subscribe, presence, retained state, and access control. The patterns change (task handoff instead of chat messages, blackboard instead of typing indicators, approval gates instead of read receipts), but the infrastructure doesn't.",[11,944,945,946,949],{},"That's why we built ",[38,947,948],{},"@nolag/agents"," as a high-level SDK on top of the same core infrastructure. No new servers, no new protocols, no new persistence layer. Just new patterns mapped onto proven primitives.",[11,951,952],{},[95,953,955],{"href":954},"/agents","Explore @nolag/agents →",[957,958,959],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":36,"searchDepth":128,"depth":128,"links":961},[962,963,964,965,966,967,968,969],{"id":20,"depth":128,"text":21},{"id":53,"depth":128,"text":54},{"id":102,"depth":128,"text":103},{"id":410,"depth":128,"text":411},{"id":807,"depth":128,"text":808},{"id":829,"depth":128,"text":830},{"id":928,"depth":128,"text":929},{"id":938,"depth":128,"text":939},"AI Agents","2026-05-19","How NoLag's real-time messaging infrastructure maps to agent coordination. The design decisions behind each pattern and performance characteristics for agent workloads.",null,"md",{},"/blog/human-to-agent-realtime","10 min read",{"title":5,"description":972},"blog/human-to-agent-realtime","K60z4xRGVLGopGq4aFAWYcpn051216CHYm9-bsqQoaQ",1789869417082]