[{"data":1,"prerenderedAt":1803},["ShallowReactive",2],{"blog:/blog/connect-local-llm":3},{"id":4,"title":5,"author":6,"body":7,"category":1792,"date":1793,"description":1794,"excerpt":1795,"extension":1796,"meta":1797,"navigation":161,"path":1798,"readTime":1799,"seo":1800,"stem":1801,"__hash__":1802},"blog/blog/connect-local-llm.md","Connect Your Local LLM to NoLag in 5 Minutes","Henco Burger",{"type":8,"value":9,"toc":1777},"minimark",[10,14,17,22,25,41,44,48,87,91,94,104,107,602,612,616,619,919,926,930,933,939,1280,1283,1443,1455,1459,1463,1466,1673,1676,1680,1683,1687,1690,1694,1697,1701,1704,1718,1721,1725,1759,1762,1773],[11,12,13],"p",{},"You have a local model running. Ollama, llama.cpp, vLLM -- doesn't matter. It answers prompts on localhost. Now you want other parts of your system to send it work and get results back. The usual next step is to reach for a framework: LangChain, CrewAI, AutoGen. That's a lot of machinery for what is fundamentally a messaging problem.",[11,15,16],{},"This tutorial skips the framework. You'll wire up your local model as a NoLag worker agent in under 5 minutes. The model handles inference. NoLag handles the transport -- getting tasks to the model and results back to whoever asked.",[18,19,21],"h2",{"id":20},"what-youll-build","What You'll Build",[11,23,24],{},"A local Ollama worker that:",[26,27,28,32,35,38],"ul",{},[29,30,31],"li",{},"Connects to NoLag and advertises its capabilities via presence",[29,33,34],{},"Picks up tasks dispatched by any other agent in the system",[29,36,37],{},"Calls your local model and sends results back",[29,39,40],{},"Shows up in the NoLag portal dashboard so you can see it's alive",[11,42,43],{},"Then you'll add a second model with different capabilities and watch NoLag route tasks to the right worker automatically. Zero changes to the dispatching code.",[18,45,47],{"id":46},"prerequisites","Prerequisites",[49,50,51,62,70,82],"ol",{},[29,52,53,57,58],{},[54,55,56],"strong",{},"Ollama installed"," -- ",[59,60,61],"code",{},"curl -fsSL https://ollama.com/install.sh | sh",[29,63,64,57,67],{},[54,65,66],{},"A model pulled",[59,68,69],{},"ollama pull llama3.2",[29,71,72,75,76,81],{},[54,73,74],{},"A NoLag account"," -- create an app in the ",[77,78,80],"a",{"href":79},"/pricing","portal"," and grab an actor token",[29,83,84],{},[54,85,86],{},"Node.js 18+",[18,88,90],{"id":89},"step-1-create-the-worker","Step 1: Create the Worker",[11,92,93],{},"Install the dependencies:",[95,96,102],"pre",{"className":97,"code":99,"language":100,"meta":101},[98],"language-text","npm install @nolag/agents ollama\n","text","",[59,103,99],{"__ignoreMap":101},[11,105,106],{},"The worker connects to NoLag, declares what it can do, and listens for matching tasks. When a task arrives, it calls Ollama and sends the result back.",[108,109,110],"code-tabs",{},[95,111,116],{"className":112,"code":113,"filename":114,"language":115,"meta":101,"style":101},"language-typescript shiki shiki-themes github-light github-dark","import { NoLagAgents, Handoff } from \"@nolag/agents\";\nimport { Ollama } from \"ollama\";\n\nconst ollama = new Ollama({ host: \"http://localhost:11434\" });\n\nconst worker = new NoLagAgents(TOKEN, {\n  appName: \"my-agents-app\",\n  agentId: \"llama-worker\",\n  presence: {\n    name: \"llama-worker\",\n    role: \"agent\",\n    capabilities: [\"summarize\", \"classify\"],\n    metadata: { model: \"llama3.2\", provider: \"local\" },\n  },\n});\n\nawait worker.connect();\nconst room = worker.room(\"tasks\");\nconst handoff = new Handoff(room);\n\nhandoff.onTask([\"summarize\", \"classify\"], async (task, respond) => {\n  const response = await ollama.chat({\n    model: \"llama3.2\",\n    messages: [\n      { role: \"system\", content: `You are a ${task.type} agent.` },\n      { role: \"user\", content: task.payload.text },\n    ],\n  });\n\n  respond(\"success\", {\n    result: response.message.content,\n    model: \"llama3.2\",\n    latencyMs: Date.now() - task.createdAt,\n  });\n});\n\nconsole.log(\"Worker online. Waiting for tasks...\");\n","worker.ts","typescript",[59,117,118,141,156,163,192,197,221,233,244,250,260,271,289,307,313,319,324,339,362,380,385,430,453,463,469,497,508,514,520,525,538,544,553,571,576,581,586],{"__ignoreMap":101},[119,120,123,127,131,134,138],"span",{"class":121,"line":122},"line",1,[119,124,126],{"class":125},"szBVR","import",[119,128,130],{"class":129},"sVt8B"," { NoLagAgents, Handoff } ",[119,132,133],{"class":125},"from",[119,135,137],{"class":136},"sZZnC"," \"@nolag/agents\"",[119,139,140],{"class":129},";\n",[119,142,144,146,149,151,154],{"class":121,"line":143},2,[119,145,126],{"class":125},[119,147,148],{"class":129}," { Ollama } ",[119,150,133],{"class":125},[119,152,153],{"class":136}," \"ollama\"",[119,155,140],{"class":129},[119,157,159],{"class":121,"line":158},3,[119,160,162],{"emptyLinePlaceholder":161},true,"\n",[119,164,166,169,173,176,179,183,186,189],{"class":121,"line":165},4,[119,167,168],{"class":125},"const",[119,170,172],{"class":171},"sj4cs"," ollama",[119,174,175],{"class":125}," =",[119,177,178],{"class":125}," new",[119,180,182],{"class":181},"sScJk"," Ollama",[119,184,185],{"class":129},"({ host: ",[119,187,188],{"class":136},"\"http://localhost:11434\"",[119,190,191],{"class":129}," });\n",[119,193,195],{"class":121,"line":194},5,[119,196,162],{"emptyLinePlaceholder":161},[119,198,200,202,205,207,209,212,215,218],{"class":121,"line":199},6,[119,201,168],{"class":125},[119,203,204],{"class":171}," worker",[119,206,175],{"class":125},[119,208,178],{"class":125},[119,210,211],{"class":181}," NoLagAgents",[119,213,214],{"class":129},"(",[119,216,217],{"class":171},"TOKEN",[119,219,220],{"class":129},", {\n",[119,222,224,227,230],{"class":121,"line":223},7,[119,225,226],{"class":129},"  appName: ",[119,228,229],{"class":136},"\"my-agents-app\"",[119,231,232],{"class":129},",\n",[119,234,236,239,242],{"class":121,"line":235},8,[119,237,238],{"class":129},"  agentId: ",[119,240,241],{"class":136},"\"llama-worker\"",[119,243,232],{"class":129},[119,245,247],{"class":121,"line":246},9,[119,248,249],{"class":129},"  presence: {\n",[119,251,253,256,258],{"class":121,"line":252},10,[119,254,255],{"class":129},"    name: ",[119,257,241],{"class":136},[119,259,232],{"class":129},[119,261,263,266,269],{"class":121,"line":262},11,[119,264,265],{"class":129},"    role: ",[119,267,268],{"class":136},"\"agent\"",[119,270,232],{"class":129},[119,272,274,277,280,283,286],{"class":121,"line":273},12,[119,275,276],{"class":129},"    capabilities: [",[119,278,279],{"class":136},"\"summarize\"",[119,281,282],{"class":129},", ",[119,284,285],{"class":136},"\"classify\"",[119,287,288],{"class":129},"],\n",[119,290,292,295,298,301,304],{"class":121,"line":291},13,[119,293,294],{"class":129},"    metadata: { model: ",[119,296,297],{"class":136},"\"llama3.2\"",[119,299,300],{"class":129},", provider: ",[119,302,303],{"class":136},"\"local\"",[119,305,306],{"class":129}," },\n",[119,308,310],{"class":121,"line":309},14,[119,311,312],{"class":129},"  },\n",[119,314,316],{"class":121,"line":315},15,[119,317,318],{"class":129},"});\n",[119,320,322],{"class":121,"line":321},16,[119,323,162],{"emptyLinePlaceholder":161},[119,325,327,330,333,336],{"class":121,"line":326},17,[119,328,329],{"class":125},"await",[119,331,332],{"class":129}," worker.",[119,334,335],{"class":181},"connect",[119,337,338],{"class":129},"();\n",[119,340,342,344,347,349,351,354,356,359],{"class":121,"line":341},18,[119,343,168],{"class":125},[119,345,346],{"class":171}," room",[119,348,175],{"class":125},[119,350,332],{"class":129},[119,352,353],{"class":181},"room",[119,355,214],{"class":129},[119,357,358],{"class":136},"\"tasks\"",[119,360,361],{"class":129},");\n",[119,363,365,367,370,372,374,377],{"class":121,"line":364},19,[119,366,168],{"class":125},[119,368,369],{"class":171}," handoff",[119,371,175],{"class":125},[119,373,178],{"class":125},[119,375,376],{"class":181}," Handoff",[119,378,379],{"class":129},"(room);\n",[119,381,383],{"class":121,"line":382},20,[119,384,162],{"emptyLinePlaceholder":161},[119,386,388,391,394,397,399,401,403,406,409,412,416,418,421,424,427],{"class":121,"line":387},21,[119,389,390],{"class":129},"handoff.",[119,392,393],{"class":181},"onTask",[119,395,396],{"class":129},"([",[119,398,279],{"class":136},[119,400,282],{"class":129},[119,402,285],{"class":136},[119,404,405],{"class":129},"], ",[119,407,408],{"class":125},"async",[119,410,411],{"class":129}," (",[119,413,415],{"class":414},"s4XuR","task",[119,417,282],{"class":129},[119,419,420],{"class":414},"respond",[119,422,423],{"class":129},") ",[119,425,426],{"class":125},"=>",[119,428,429],{"class":129}," {\n",[119,431,433,436,439,441,444,447,450],{"class":121,"line":432},22,[119,434,435],{"class":125},"  const",[119,437,438],{"class":171}," response",[119,440,175],{"class":125},[119,442,443],{"class":125}," await",[119,445,446],{"class":129}," ollama.",[119,448,449],{"class":181},"chat",[119,451,452],{"class":129},"({\n",[119,454,456,459,461],{"class":121,"line":455},23,[119,457,458],{"class":129},"    model: ",[119,460,297],{"class":136},[119,462,232],{"class":129},[119,464,466],{"class":121,"line":465},24,[119,467,468],{"class":129},"    messages: [\n",[119,470,472,475,478,481,484,486,489,492,495],{"class":121,"line":471},25,[119,473,474],{"class":129},"      { role: ",[119,476,477],{"class":136},"\"system\"",[119,479,480],{"class":129},", content: ",[119,482,483],{"class":136},"`You are a ${",[119,485,415],{"class":129},[119,487,488],{"class":136},".",[119,490,491],{"class":129},"type",[119,493,494],{"class":136},"} agent.`",[119,496,306],{"class":129},[119,498,500,502,505],{"class":121,"line":499},26,[119,501,474],{"class":129},[119,503,504],{"class":136},"\"user\"",[119,506,507],{"class":129},", content: task.payload.text },\n",[119,509,511],{"class":121,"line":510},27,[119,512,513],{"class":129},"    ],\n",[119,515,517],{"class":121,"line":516},28,[119,518,519],{"class":129},"  });\n",[119,521,523],{"class":121,"line":522},29,[119,524,162],{"emptyLinePlaceholder":161},[119,526,528,531,533,536],{"class":121,"line":527},30,[119,529,530],{"class":181},"  respond",[119,532,214],{"class":129},[119,534,535],{"class":136},"\"success\"",[119,537,220],{"class":129},[119,539,541],{"class":121,"line":540},31,[119,542,543],{"class":129},"    result: response.message.content,\n",[119,545,547,549,551],{"class":121,"line":546},32,[119,548,458],{"class":129},[119,550,297],{"class":136},[119,552,232],{"class":129},[119,554,556,559,562,565,568],{"class":121,"line":555},33,[119,557,558],{"class":129},"    latencyMs: Date.",[119,560,561],{"class":181},"now",[119,563,564],{"class":129},"() ",[119,566,567],{"class":125},"-",[119,569,570],{"class":129}," task.createdAt,\n",[119,572,574],{"class":121,"line":573},34,[119,575,519],{"class":129},[119,577,579],{"class":121,"line":578},35,[119,580,318],{"class":129},[119,582,584],{"class":121,"line":583},36,[119,585,162],{"emptyLinePlaceholder":161},[119,587,589,592,595,597,600],{"class":121,"line":588},37,[119,590,591],{"class":129},"console.",[119,593,594],{"class":181},"log",[119,596,214],{"class":129},[119,598,599],{"class":136},"\"Worker online. Waiting for tasks...\"",[119,601,361],{"class":129},[11,603,604,605,608,609,611],{},"That's the entire worker. No routing logic, no queue management, no health checks. The ",[59,606,607],{},"presence"," block tells the system what this worker can do. The ",[59,610,393],{}," callback handles incoming work. NoLag manages everything in between.",[18,613,615],{"id":614},"step-2-dispatch-a-task","Step 2: Dispatch a Task",[11,617,618],{},"From any other process -- a backend service, a CLI script, another agent -- dispatch a task by capability:",[108,620,621],{},[95,622,625],{"className":112,"code":623,"filename":624,"language":115,"meta":101,"style":101},"import { NoLagAgents, Handoff } from \"@nolag/agents\";\n\nconst orchestrator = new NoLagAgents(TOKEN, {\n  appName: \"my-agents-app\",\n  agentId: \"orchestrator\",\n  presence: { name: \"orchestrator\", role: \"orchestrator\" },\n});\n\nawait orchestrator.connect();\nconst room = orchestrator.room(\"tasks\");\nconst handoff = new Handoff(room);\n\n// Check who's online\nconst workers = room.findAgents(\"summarize\");\nconsole.log(`${workers.length} summarize worker(s) online`);\n\n// Dispatch a task -- NoLag routes it to a capable worker\nconst result = await handoff.dispatch(\"summarize\", {\n  text: \"NoLag is a real-time messaging infrastructure...\"\n}, {\n  waitForResult: true,\n  timeout: 30000,\n});\n\nconsole.log(\"Result:\", result.payload.result);\nconsole.log(\"Model:\", result.payload.model);\nconsole.log(\"Latency:\", result.payload.latencyMs, \"ms\");\n","dispatch.ts",[59,626,627,639,643,662,670,679,693,697,701,712,730,744,748,754,775,799,803,808,831,839,844,854,864,868,872,886,900],{"__ignoreMap":101},[119,628,629,631,633,635,637],{"class":121,"line":122},[119,630,126],{"class":125},[119,632,130],{"class":129},[119,634,133],{"class":125},[119,636,137],{"class":136},[119,638,140],{"class":129},[119,640,641],{"class":121,"line":143},[119,642,162],{"emptyLinePlaceholder":161},[119,644,645,647,650,652,654,656,658,660],{"class":121,"line":158},[119,646,168],{"class":125},[119,648,649],{"class":171}," orchestrator",[119,651,175],{"class":125},[119,653,178],{"class":125},[119,655,211],{"class":181},[119,657,214],{"class":129},[119,659,217],{"class":171},[119,661,220],{"class":129},[119,663,664,666,668],{"class":121,"line":165},[119,665,226],{"class":129},[119,667,229],{"class":136},[119,669,232],{"class":129},[119,671,672,674,677],{"class":121,"line":194},[119,673,238],{"class":129},[119,675,676],{"class":136},"\"orchestrator\"",[119,678,232],{"class":129},[119,680,681,684,686,689,691],{"class":121,"line":199},[119,682,683],{"class":129},"  presence: { name: ",[119,685,676],{"class":136},[119,687,688],{"class":129},", role: ",[119,690,676],{"class":136},[119,692,306],{"class":129},[119,694,695],{"class":121,"line":223},[119,696,318],{"class":129},[119,698,699],{"class":121,"line":235},[119,700,162],{"emptyLinePlaceholder":161},[119,702,703,705,708,710],{"class":121,"line":246},[119,704,329],{"class":125},[119,706,707],{"class":129}," orchestrator.",[119,709,335],{"class":181},[119,711,338],{"class":129},[119,713,714,716,718,720,722,724,726,728],{"class":121,"line":252},[119,715,168],{"class":125},[119,717,346],{"class":171},[119,719,175],{"class":125},[119,721,707],{"class":129},[119,723,353],{"class":181},[119,725,214],{"class":129},[119,727,358],{"class":136},[119,729,361],{"class":129},[119,731,732,734,736,738,740,742],{"class":121,"line":262},[119,733,168],{"class":125},[119,735,369],{"class":171},[119,737,175],{"class":125},[119,739,178],{"class":125},[119,741,376],{"class":181},[119,743,379],{"class":129},[119,745,746],{"class":121,"line":273},[119,747,162],{"emptyLinePlaceholder":161},[119,749,750],{"class":121,"line":291},[119,751,753],{"class":752},"sJ8bj","// Check who's online\n",[119,755,756,758,761,763,766,769,771,773],{"class":121,"line":309},[119,757,168],{"class":125},[119,759,760],{"class":171}," workers",[119,762,175],{"class":125},[119,764,765],{"class":129}," room.",[119,767,768],{"class":181},"findAgents",[119,770,214],{"class":129},[119,772,279],{"class":136},[119,774,361],{"class":129},[119,776,777,779,781,783,786,789,791,794,797],{"class":121,"line":315},[119,778,591],{"class":129},[119,780,594],{"class":181},[119,782,214],{"class":129},[119,784,785],{"class":136},"`${",[119,787,788],{"class":129},"workers",[119,790,488],{"class":136},[119,792,793],{"class":171},"length",[119,795,796],{"class":136},"} summarize worker(s) online`",[119,798,361],{"class":129},[119,800,801],{"class":121,"line":321},[119,802,162],{"emptyLinePlaceholder":161},[119,804,805],{"class":121,"line":326},[119,806,807],{"class":752},"// Dispatch a task -- NoLag routes it to a capable worker\n",[119,809,810,812,815,817,819,822,825,827,829],{"class":121,"line":341},[119,811,168],{"class":125},[119,813,814],{"class":171}," result",[119,816,175],{"class":125},[119,818,443],{"class":125},[119,820,821],{"class":129}," handoff.",[119,823,824],{"class":181},"dispatch",[119,826,214],{"class":129},[119,828,279],{"class":136},[119,830,220],{"class":129},[119,832,833,836],{"class":121,"line":364},[119,834,835],{"class":129},"  text: ",[119,837,838],{"class":136},"\"NoLag is a real-time messaging infrastructure...\"\n",[119,840,841],{"class":121,"line":382},[119,842,843],{"class":129},"}, {\n",[119,845,846,849,852],{"class":121,"line":387},[119,847,848],{"class":129},"  waitForResult: ",[119,850,851],{"class":171},"true",[119,853,232],{"class":129},[119,855,856,859,862],{"class":121,"line":432},[119,857,858],{"class":129},"  timeout: ",[119,860,861],{"class":171},"30000",[119,863,232],{"class":129},[119,865,866],{"class":121,"line":455},[119,867,318],{"class":129},[119,869,870],{"class":121,"line":465},[119,871,162],{"emptyLinePlaceholder":161},[119,873,874,876,878,880,883],{"class":121,"line":471},[119,875,591],{"class":129},[119,877,594],{"class":181},[119,879,214],{"class":129},[119,881,882],{"class":136},"\"Result:\"",[119,884,885],{"class":129},", result.payload.result);\n",[119,887,888,890,892,894,897],{"class":121,"line":499},[119,889,591],{"class":129},[119,891,594],{"class":181},[119,893,214],{"class":129},[119,895,896],{"class":136},"\"Model:\"",[119,898,899],{"class":129},", result.payload.model);\n",[119,901,902,904,906,908,911,914,917],{"class":121,"line":510},[119,903,591],{"class":129},[119,905,594],{"class":181},[119,907,214],{"class":129},[119,909,910],{"class":136},"\"Latency:\"",[119,912,913],{"class":129},", result.payload.latencyMs, ",[119,915,916],{"class":136},"\"ms\"",[119,918,361],{"class":129},[11,920,921,922,925],{},"The orchestrator doesn't import ",[59,923,924],{},"ollama",". It doesn't know the worker runs Llama. It dispatches a \"summarize\" task and gets a result. If you later swap the worker to use Mistral, or move it to a GPU server across the network, the dispatching code doesn't change.",[18,927,929],{"id":928},"step-3-add-a-second-model","Step 3: Add a Second Model",[11,931,932],{},"Pull another model and spin up a second worker with different capabilities:",[95,934,937],{"className":935,"code":936,"language":100,"meta":101},[98],"ollama pull mistral\n",[59,938,936],{"__ignoreMap":101},[108,940,941],{},[95,942,945],{"className":112,"code":943,"filename":944,"language":115,"meta":101,"style":101},"import { NoLagAgents, Handoff } from \"@nolag/agents\";\nimport { Ollama } from \"ollama\";\n\nconst ollama = new Ollama({ host: \"http://localhost:11434\" });\n\nconst worker = new NoLagAgents(TOKEN, {\n  appName: \"my-agents-app\",\n  agentId: \"mistral-worker\",\n  presence: {\n    name: \"mistral-worker\",\n    role: \"agent\",\n    capabilities: [\"extract-entities\", \"translate\"],\n    metadata: { model: \"mistral\", provider: \"local\" },\n  },\n});\n\nawait worker.connect();\nconst room = worker.room(\"tasks\");\nconst handoff = new Handoff(room);\n\nhandoff.onTask([\"extract-entities\", \"translate\"], async (task, respond) => {\n  const response = await ollama.chat({\n    model: \"mistral\",\n    messages: [\n      { role: \"system\", content: `You are an ${task.type} agent.` },\n      { role: \"user\", content: task.payload.text },\n    ],\n  });\n\n  respond(\"success\", {\n    result: response.message.content,\n    model: \"mistral\",\n    latencyMs: Date.now() - task.createdAt,\n  });\n});\n","mistral-worker.ts",[59,946,947,959,971,975,993,997,1015,1023,1032,1036,1044,1052,1066,1079,1083,1087,1091,1101,1119,1133,1137,1169,1185,1193,1197,1218,1226,1230,1234,1238,1248,1252,1260,1272,1276],{"__ignoreMap":101},[119,948,949,951,953,955,957],{"class":121,"line":122},[119,950,126],{"class":125},[119,952,130],{"class":129},[119,954,133],{"class":125},[119,956,137],{"class":136},[119,958,140],{"class":129},[119,960,961,963,965,967,969],{"class":121,"line":143},[119,962,126],{"class":125},[119,964,148],{"class":129},[119,966,133],{"class":125},[119,968,153],{"class":136},[119,970,140],{"class":129},[119,972,973],{"class":121,"line":158},[119,974,162],{"emptyLinePlaceholder":161},[119,976,977,979,981,983,985,987,989,991],{"class":121,"line":165},[119,978,168],{"class":125},[119,980,172],{"class":171},[119,982,175],{"class":125},[119,984,178],{"class":125},[119,986,182],{"class":181},[119,988,185],{"class":129},[119,990,188],{"class":136},[119,992,191],{"class":129},[119,994,995],{"class":121,"line":194},[119,996,162],{"emptyLinePlaceholder":161},[119,998,999,1001,1003,1005,1007,1009,1011,1013],{"class":121,"line":199},[119,1000,168],{"class":125},[119,1002,204],{"class":171},[119,1004,175],{"class":125},[119,1006,178],{"class":125},[119,1008,211],{"class":181},[119,1010,214],{"class":129},[119,1012,217],{"class":171},[119,1014,220],{"class":129},[119,1016,1017,1019,1021],{"class":121,"line":223},[119,1018,226],{"class":129},[119,1020,229],{"class":136},[119,1022,232],{"class":129},[119,1024,1025,1027,1030],{"class":121,"line":235},[119,1026,238],{"class":129},[119,1028,1029],{"class":136},"\"mistral-worker\"",[119,1031,232],{"class":129},[119,1033,1034],{"class":121,"line":246},[119,1035,249],{"class":129},[119,1037,1038,1040,1042],{"class":121,"line":252},[119,1039,255],{"class":129},[119,1041,1029],{"class":136},[119,1043,232],{"class":129},[119,1045,1046,1048,1050],{"class":121,"line":262},[119,1047,265],{"class":129},[119,1049,268],{"class":136},[119,1051,232],{"class":129},[119,1053,1054,1056,1059,1061,1064],{"class":121,"line":273},[119,1055,276],{"class":129},[119,1057,1058],{"class":136},"\"extract-entities\"",[119,1060,282],{"class":129},[119,1062,1063],{"class":136},"\"translate\"",[119,1065,288],{"class":129},[119,1067,1068,1070,1073,1075,1077],{"class":121,"line":291},[119,1069,294],{"class":129},[119,1071,1072],{"class":136},"\"mistral\"",[119,1074,300],{"class":129},[119,1076,303],{"class":136},[119,1078,306],{"class":129},[119,1080,1081],{"class":121,"line":309},[119,1082,312],{"class":129},[119,1084,1085],{"class":121,"line":315},[119,1086,318],{"class":129},[119,1088,1089],{"class":121,"line":321},[119,1090,162],{"emptyLinePlaceholder":161},[119,1092,1093,1095,1097,1099],{"class":121,"line":326},[119,1094,329],{"class":125},[119,1096,332],{"class":129},[119,1098,335],{"class":181},[119,1100,338],{"class":129},[119,1102,1103,1105,1107,1109,1111,1113,1115,1117],{"class":121,"line":341},[119,1104,168],{"class":125},[119,1106,346],{"class":171},[119,1108,175],{"class":125},[119,1110,332],{"class":129},[119,1112,353],{"class":181},[119,1114,214],{"class":129},[119,1116,358],{"class":136},[119,1118,361],{"class":129},[119,1120,1121,1123,1125,1127,1129,1131],{"class":121,"line":364},[119,1122,168],{"class":125},[119,1124,369],{"class":171},[119,1126,175],{"class":125},[119,1128,178],{"class":125},[119,1130,376],{"class":181},[119,1132,379],{"class":129},[119,1134,1135],{"class":121,"line":382},[119,1136,162],{"emptyLinePlaceholder":161},[119,1138,1139,1141,1143,1145,1147,1149,1151,1153,1155,1157,1159,1161,1163,1165,1167],{"class":121,"line":387},[119,1140,390],{"class":129},[119,1142,393],{"class":181},[119,1144,396],{"class":129},[119,1146,1058],{"class":136},[119,1148,282],{"class":129},[119,1150,1063],{"class":136},[119,1152,405],{"class":129},[119,1154,408],{"class":125},[119,1156,411],{"class":129},[119,1158,415],{"class":414},[119,1160,282],{"class":129},[119,1162,420],{"class":414},[119,1164,423],{"class":129},[119,1166,426],{"class":125},[119,1168,429],{"class":129},[119,1170,1171,1173,1175,1177,1179,1181,1183],{"class":121,"line":432},[119,1172,435],{"class":125},[119,1174,438],{"class":171},[119,1176,175],{"class":125},[119,1178,443],{"class":125},[119,1180,446],{"class":129},[119,1182,449],{"class":181},[119,1184,452],{"class":129},[119,1186,1187,1189,1191],{"class":121,"line":455},[119,1188,458],{"class":129},[119,1190,1072],{"class":136},[119,1192,232],{"class":129},[119,1194,1195],{"class":121,"line":465},[119,1196,468],{"class":129},[119,1198,1199,1201,1203,1205,1208,1210,1212,1214,1216],{"class":121,"line":471},[119,1200,474],{"class":129},[119,1202,477],{"class":136},[119,1204,480],{"class":129},[119,1206,1207],{"class":136},"`You are an ${",[119,1209,415],{"class":129},[119,1211,488],{"class":136},[119,1213,491],{"class":129},[119,1215,494],{"class":136},[119,1217,306],{"class":129},[119,1219,1220,1222,1224],{"class":121,"line":499},[119,1221,474],{"class":129},[119,1223,504],{"class":136},[119,1225,507],{"class":129},[119,1227,1228],{"class":121,"line":510},[119,1229,513],{"class":129},[119,1231,1232],{"class":121,"line":516},[119,1233,519],{"class":129},[119,1235,1236],{"class":121,"line":522},[119,1237,162],{"emptyLinePlaceholder":161},[119,1239,1240,1242,1244,1246],{"class":121,"line":527},[119,1241,530],{"class":181},[119,1243,214],{"class":129},[119,1245,535],{"class":136},[119,1247,220],{"class":129},[119,1249,1250],{"class":121,"line":540},[119,1251,543],{"class":129},[119,1253,1254,1256,1258],{"class":121,"line":546},[119,1255,458],{"class":129},[119,1257,1072],{"class":136},[119,1259,232],{"class":129},[119,1261,1262,1264,1266,1268,1270],{"class":121,"line":555},[119,1263,558],{"class":129},[119,1265,561],{"class":181},[119,1267,564],{"class":129},[119,1269,567],{"class":125},[119,1271,570],{"class":129},[119,1273,1274],{"class":121,"line":573},[119,1275,519],{"class":129},[119,1277,1278],{"class":121,"line":578},[119,1279,318],{"class":129},[11,1281,1282],{},"Now dispatch tasks that route to each model automatically:",[108,1284,1285],{},[95,1286,1289],{"className":112,"code":1287,"filename":1288,"language":115,"meta":101,"style":101},"// The orchestrator doesn't change.\n// Dispatch by capability -- NoLag routes to the right worker.\n\nconst summary = await handoff.dispatch(\"summarize\", {\n  text: document\n}, { waitForResult: true });\n// -> routed to llama-worker\n\nconst entities = await handoff.dispatch(\"extract-entities\", {\n  text: document\n}, { waitForResult: true });\n// -> routed to mistral-worker\n\nconst translation = await handoff.dispatch(\"translate\", {\n  text: summary.payload.result\n}, { waitForResult: true });\n// -> routed to mistral-worker\n\n// All three tasks ran on local models.\n// No API keys. No egress. No per-token billing.\n","dispatch-multi.ts",[59,1290,1291,1296,1301,1305,1326,1331,1340,1345,1349,1370,1374,1382,1387,1391,1412,1417,1425,1429,1433,1438],{"__ignoreMap":101},[119,1292,1293],{"class":121,"line":122},[119,1294,1295],{"class":752},"// The orchestrator doesn't change.\n",[119,1297,1298],{"class":121,"line":143},[119,1299,1300],{"class":752},"// Dispatch by capability -- NoLag routes to the right worker.\n",[119,1302,1303],{"class":121,"line":158},[119,1304,162],{"emptyLinePlaceholder":161},[119,1306,1307,1309,1312,1314,1316,1318,1320,1322,1324],{"class":121,"line":165},[119,1308,168],{"class":125},[119,1310,1311],{"class":171}," summary",[119,1313,175],{"class":125},[119,1315,443],{"class":125},[119,1317,821],{"class":129},[119,1319,824],{"class":181},[119,1321,214],{"class":129},[119,1323,279],{"class":136},[119,1325,220],{"class":129},[119,1327,1328],{"class":121,"line":194},[119,1329,1330],{"class":129},"  text: document\n",[119,1332,1333,1336,1338],{"class":121,"line":199},[119,1334,1335],{"class":129},"}, { waitForResult: ",[119,1337,851],{"class":171},[119,1339,191],{"class":129},[119,1341,1342],{"class":121,"line":223},[119,1343,1344],{"class":752},"// -> routed to llama-worker\n",[119,1346,1347],{"class":121,"line":235},[119,1348,162],{"emptyLinePlaceholder":161},[119,1350,1351,1353,1356,1358,1360,1362,1364,1366,1368],{"class":121,"line":246},[119,1352,168],{"class":125},[119,1354,1355],{"class":171}," entities",[119,1357,175],{"class":125},[119,1359,443],{"class":125},[119,1361,821],{"class":129},[119,1363,824],{"class":181},[119,1365,214],{"class":129},[119,1367,1058],{"class":136},[119,1369,220],{"class":129},[119,1371,1372],{"class":121,"line":252},[119,1373,1330],{"class":129},[119,1375,1376,1378,1380],{"class":121,"line":262},[119,1377,1335],{"class":129},[119,1379,851],{"class":171},[119,1381,191],{"class":129},[119,1383,1384],{"class":121,"line":273},[119,1385,1386],{"class":752},"// -> routed to mistral-worker\n",[119,1388,1389],{"class":121,"line":291},[119,1390,162],{"emptyLinePlaceholder":161},[119,1392,1393,1395,1398,1400,1402,1404,1406,1408,1410],{"class":121,"line":309},[119,1394,168],{"class":125},[119,1396,1397],{"class":171}," translation",[119,1399,175],{"class":125},[119,1401,443],{"class":125},[119,1403,821],{"class":129},[119,1405,824],{"class":181},[119,1407,214],{"class":129},[119,1409,1063],{"class":136},[119,1411,220],{"class":129},[119,1413,1414],{"class":121,"line":315},[119,1415,1416],{"class":129},"  text: summary.payload.result\n",[119,1418,1419,1421,1423],{"class":121,"line":321},[119,1420,1335],{"class":129},[119,1422,851],{"class":171},[119,1424,191],{"class":129},[119,1426,1427],{"class":121,"line":326},[119,1428,1386],{"class":752},[119,1430,1431],{"class":121,"line":341},[119,1432,162],{"emptyLinePlaceholder":161},[119,1434,1435],{"class":121,"line":364},[119,1436,1437],{"class":752},"// All three tasks ran on local models.\n",[119,1439,1440],{"class":121,"line":382},[119,1441,1442],{"class":752},"// No API keys. No egress. No per-token billing.\n",[11,1444,1445,1446,1450,1451,1454],{},"The orchestrator dispatches by ",[1447,1448,1449],"em",{},"what needs doing",", not by ",[1447,1452,1453],{},"which model does it",". Add a third model, remove one, restart a worker mid-task -- the system adapts because routing is based on presence, not hardcoded addresses.",[18,1456,1458],{"id":1457},"what-you-get-for-free","What You Get for Free",[1460,1461,1462],"h3",{"id":607},"Presence",[11,1464,1465],{},"Every connected worker shows up in real time. You always know which models are online and what they can do.",[108,1467,1468],{},[95,1469,1472],{"className":112,"code":1470,"filename":1471,"language":115,"meta":101,"style":101},"// See every connected agent in real time\nroom.onPresenceChange((agents) => {\n  for (const agent of agents) {\n    console.log(`${agent.name} [${agent.status}]`);\n    console.log(`  capabilities: ${agent.capabilities.join(\", \")}`);\n    console.log(`  model: ${agent.metadata?.model}`);\n  }\n});\n\n// Output:\n// llama-worker [online]\n//   capabilities: summarize, classify\n//   model: llama3.2\n// mistral-worker [online]\n//   capabilities: extract-entities, translate\n//   model: mistral\n// orchestrator [online]\n//   capabilities: (none)\n","presence.ts",[59,1473,1474,1479,1499,1517,1551,1587,1615,1620,1624,1628,1633,1638,1643,1648,1653,1658,1663,1668],{"__ignoreMap":101},[119,1475,1476],{"class":121,"line":122},[119,1477,1478],{"class":752},"// See every connected agent in real time\n",[119,1480,1481,1484,1487,1490,1493,1495,1497],{"class":121,"line":143},[119,1482,1483],{"class":129},"room.",[119,1485,1486],{"class":181},"onPresenceChange",[119,1488,1489],{"class":129},"((",[119,1491,1492],{"class":414},"agents",[119,1494,423],{"class":129},[119,1496,426],{"class":125},[119,1498,429],{"class":129},[119,1500,1501,1504,1506,1508,1511,1514],{"class":121,"line":158},[119,1502,1503],{"class":125},"  for",[119,1505,411],{"class":129},[119,1507,168],{"class":125},[119,1509,1510],{"class":171}," agent",[119,1512,1513],{"class":125}," of",[119,1515,1516],{"class":129}," agents) {\n",[119,1518,1519,1522,1524,1526,1528,1531,1533,1536,1539,1541,1543,1546,1549],{"class":121,"line":165},[119,1520,1521],{"class":129},"    console.",[119,1523,594],{"class":181},[119,1525,214],{"class":129},[119,1527,785],{"class":136},[119,1529,1530],{"class":129},"agent",[119,1532,488],{"class":136},[119,1534,1535],{"class":129},"name",[119,1537,1538],{"class":136},"} [${",[119,1540,1530],{"class":129},[119,1542,488],{"class":136},[119,1544,1545],{"class":129},"status",[119,1547,1548],{"class":136},"}]`",[119,1550,361],{"class":129},[119,1552,1553,1555,1557,1559,1562,1564,1566,1569,1571,1574,1576,1579,1582,1585],{"class":121,"line":194},[119,1554,1521],{"class":129},[119,1556,594],{"class":181},[119,1558,214],{"class":129},[119,1560,1561],{"class":136},"`  capabilities: ${",[119,1563,1530],{"class":129},[119,1565,488],{"class":136},[119,1567,1568],{"class":129},"capabilities",[119,1570,488],{"class":136},[119,1572,1573],{"class":181},"join",[119,1575,214],{"class":136},[119,1577,1578],{"class":136},"\", \"",[119,1580,1581],{"class":136},")",[119,1583,1584],{"class":136},"}`",[119,1586,361],{"class":129},[119,1588,1589,1591,1593,1595,1598,1600,1602,1605,1608,1611,1613],{"class":121,"line":199},[119,1590,1521],{"class":129},[119,1592,594],{"class":181},[119,1594,214],{"class":129},[119,1596,1597],{"class":136},"`  model: ${",[119,1599,1530],{"class":129},[119,1601,488],{"class":136},[119,1603,1604],{"class":129},"metadata",[119,1606,1607],{"class":136},"?.",[119,1609,1610],{"class":129},"model",[119,1612,1584],{"class":136},[119,1614,361],{"class":129},[119,1616,1617],{"class":121,"line":223},[119,1618,1619],{"class":129},"  }\n",[119,1621,1622],{"class":121,"line":235},[119,1623,318],{"class":129},[119,1625,1626],{"class":121,"line":246},[119,1627,162],{"emptyLinePlaceholder":161},[119,1629,1630],{"class":121,"line":252},[119,1631,1632],{"class":752},"// Output:\n",[119,1634,1635],{"class":121,"line":262},[119,1636,1637],{"class":752},"// llama-worker [online]\n",[119,1639,1640],{"class":121,"line":273},[119,1641,1642],{"class":752},"//   capabilities: summarize, classify\n",[119,1644,1645],{"class":121,"line":291},[119,1646,1647],{"class":752},"//   model: llama3.2\n",[119,1649,1650],{"class":121,"line":309},[119,1651,1652],{"class":752},"// mistral-worker [online]\n",[119,1654,1655],{"class":121,"line":315},[119,1656,1657],{"class":752},"//   capabilities: extract-entities, translate\n",[119,1659,1660],{"class":121,"line":321},[119,1661,1662],{"class":752},"//   model: mistral\n",[119,1664,1665],{"class":121,"line":326},[119,1666,1667],{"class":752},"// orchestrator [online]\n",[119,1669,1670],{"class":121,"line":341},[119,1671,1672],{"class":752},"//   capabilities: (none)\n",[11,1674,1675],{},"The NoLag portal dashboard shows this same view graphically -- no custom monitoring needed.",[1460,1677,1679],{"id":1678},"reconnection","Reconnection",[11,1681,1682],{},"If a worker disconnects (machine reboots, network blip, Ollama restart), the SDK reconnects automatically. Tasks dispatched while the worker was offline are held in the queue and delivered when it comes back. No messages lost.",[1460,1684,1686],{"id":1685},"load-balancing","Load Balancing",[11,1688,1689],{},"Run two instances of the same worker on two machines. NoLag distributes tasks across them with load-balanced subscriptions. Scale by adding processes, not by changing code.",[1460,1691,1693],{"id":1692},"observability","Observability",[11,1695,1696],{},"Every task dispatch and result flows through NoLag's event system. The portal's Agents tab shows the topology: which agents are connected, task flow between them, and aggregate metrics. Attach an observer agent to log everything to your own system if you need it.",[18,1698,1700],{"id":1699},"why-not-a-framework","Why Not a Framework?",[11,1702,1703],{},"Frameworks like LangChain and CrewAI solve a real problem: making it easy to build agent logic. But they also own the transport. Your agents communicate through function calls inside a single process. That means:",[26,1705,1706,1709,1712,1715],{},[29,1707,1708],{},"Agents can't run on different machines",[29,1710,1711],{},"You can't scale workers independently",[29,1713,1714],{},"If the coordinator crashes, everything stops",[29,1716,1717],{},"Adding a human approval step means hacking the framework's internals",[11,1719,1720],{},"NoLag doesn't replace your agent logic. It replaces the wiring between agents. Use whatever prompt engineering, RAG pipeline, or chain-of-thought approach you want inside your worker. NoLag just makes sure tasks get to the right worker and results get back.",[18,1722,1724],{"id":1723},"next-steps","Next Steps",[26,1726,1727,1738,1744,1750],{},[29,1728,1729,1732,1733,1737],{},[54,1730,1731],{},"Add a cloud model"," -- see ",[77,1734,1736],{"href":1735},"/blog/hybrid-llm-orchestration","Hybrid LLM Coordination"," for mixing local and proprietary models",[29,1739,1740,1743],{},[54,1741,1742],{},"Add human approval"," -- gate sensitive actions with the Approve pattern before they execute",[29,1745,1746,1749],{},[54,1747,1748],{},"Share state"," -- use the Blackboard pattern to track model performance metrics across all workers",[29,1751,1752,57,1755],{},[54,1753,1754],{},"Read the docs",[77,1756,1758],{"href":1757},"/docs/agents/getting-started","@nolag/agents getting started guide",[11,1760,1761],{},"Your local model is the smart part. NoLag is the dumb pipe that makes it reachable. That's the whole idea.",[26,1763,1764,1768],{},[29,1765,1766],{},[77,1767,1736],{"href":1735},[29,1769,1770],{},[77,1771,1772],{"href":1757},"Agents Docs",[1774,1775,1776],"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 .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);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":101,"searchDepth":143,"depth":143,"links":1778},[1779,1780,1781,1782,1783,1784,1790,1791],{"id":20,"depth":143,"text":21},{"id":46,"depth":143,"text":47},{"id":89,"depth":143,"text":90},{"id":614,"depth":143,"text":615},{"id":928,"depth":143,"text":929},{"id":1457,"depth":143,"text":1458,"children":1785},[1786,1787,1788,1789],{"id":607,"depth":158,"text":1462},{"id":1678,"depth":158,"text":1679},{"id":1685,"depth":158,"text":1686},{"id":1692,"depth":158,"text":1693},{"id":1699,"depth":143,"text":1700},{"id":1723,"depth":143,"text":1724},"Tutorial","2026-05-25","Wire up Ollama as a NoLag worker agent in under 5 minutes. No framework, no boilerplate -- just a transport layer between your model and the rest of your system.",null,"md",{},"/blog/connect-local-llm","8 min read",{"title":5,"description":1794},"blog/connect-local-llm","9yUuHuux27hjwowssSH1Ne9bEL8aaChoNwQ15exzBE4",1788160339717]