[{"data":1,"prerenderedAt":2128},["ShallowReactive",2],{"blog:/blog/connect-local-llm":3},{"id":4,"title":5,"author":6,"body":7,"category":2117,"date":2118,"description":2119,"excerpt":2120,"extension":2121,"meta":2122,"navigation":217,"path":2123,"readTime":2124,"seo":2125,"stem":2126,"__hash__":2127},"blog/blog/connect-local-llm.md","Connect Your Local LLM to NoLag in 5 Minutes","Henco Burger",{"type":8,"value":9,"toc":2102},"minimark",[10,14,17,22,25,41,44,48,111,115,118,149,152,700,713,717,720,1077,1084,1088,1091,1106,1490,1493,1665,1677,1681,1685,1688,1942,1945,1949,1961,1965,1968,2008,2011,2015,2022,2026,2029,2043,2046,2050,2084,2087,2098],[11,12,13],"p",{},"You have a local model running. Ollama, llama.cpp, vLLM, it 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 tasks reach the right worker. Zero changes to the dispatching code.",[18,45,47],{"id":46},"prerequisites","Prerequisites",[49,50,51,62,70,106],"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,79,80,85,86,89,90,93,94,97,98,101,102,105],{},[54,73,74],{},"A NoLag account",": create an app from the ",[59,77,78],{},"nolag-agents-sdk"," blueprint in the ",[81,82,84],"a",{"href":83},"/pricing","portal"," and create one actor of type ",[59,87,88],{},"agent"," per worker plus one of type ",[59,91,92],{},"orchestrator"," for the dispatcher. The app slug you get back has a random suffix (",[59,95,96],{},"my-agents-app-a3f9","); that suffixed slug is the ",[59,99,100],{},"appName"," below. The blueprint seeds a ",[59,103,104],{},"default-workflow"," room, which is the room this tutorial uses.",[29,107,108],{},[54,109,110],{},"Node.js 18+",[18,112,114],{"id":113},"step-1-create-the-worker","Step 1: Create the Worker",[11,116,117],{},"Install the dependencies:",[119,120,125],"pre",{"className":121,"code":122,"language":123,"meta":124,"style":124},"language-bash shiki shiki-themes github-light github-dark","npm install @nolag/agents @nolag/js-sdk ollama\n","bash","",[59,126,127],{"__ignoreMap":124},[128,129,132,136,140,143,146],"span",{"class":130,"line":131},"line",1,[128,133,135],{"class":134},"sScJk","npm",[128,137,139],{"class":138},"sZZnC"," install",[128,141,142],{"class":138}," @nolag/agents",[128,144,145],{"class":138}," @nolag/js-sdk",[128,147,148],{"class":138}," ollama\n",[11,150,151],{},"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.",[153,154,155],"code-tabs",{},[119,156,161],{"className":157,"code":158,"filename":159,"language":160,"meta":124,"style":124},"language-typescript shiki shiki-themes github-light github-dark","import { NoLag } from \"@nolag/js-sdk\";\nimport { NoLagAgents, Handoff } from \"@nolag/agents\";\nimport { Ollama } from \"ollama\";\n\nconst ollama = new Ollama({ host: \"http://localhost:11434\" });\n\nconst client = NoLag(WORKER_TOKEN);\nconst worker = new NoLagAgents({\n  client,\n  appName: APP_SLUG, // the suffixed slug returned when you created the 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 client.connect();\nawait worker.ready();\nconst room = worker.room(\"default-workflow\");\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.capability} agent.` },\n      { role: \"user\", content: String(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,162,163,182,197,212,219,247,252,274,292,298,314,326,332,342,353,370,388,394,400,405,420,433,455,473,478,523,545,555,561,589,605,611,617,622,636,642,651,669,674,679,684],{"__ignoreMap":124},[128,164,165,169,173,176,179],{"class":130,"line":131},[128,166,168],{"class":167},"szBVR","import",[128,170,172],{"class":171},"sVt8B"," { NoLag } ",[128,174,175],{"class":167},"from",[128,177,178],{"class":138}," \"@nolag/js-sdk\"",[128,180,181],{"class":171},";\n",[128,183,185,187,190,192,195],{"class":130,"line":184},2,[128,186,168],{"class":167},[128,188,189],{"class":171}," { NoLagAgents, Handoff } ",[128,191,175],{"class":167},[128,193,194],{"class":138}," \"@nolag/agents\"",[128,196,181],{"class":171},[128,198,200,202,205,207,210],{"class":130,"line":199},3,[128,201,168],{"class":167},[128,203,204],{"class":171}," { Ollama } ",[128,206,175],{"class":167},[128,208,209],{"class":138}," \"ollama\"",[128,211,181],{"class":171},[128,213,215],{"class":130,"line":214},4,[128,216,218],{"emptyLinePlaceholder":217},true,"\n",[128,220,222,225,229,232,235,238,241,244],{"class":130,"line":221},5,[128,223,224],{"class":167},"const",[128,226,228],{"class":227},"sj4cs"," ollama",[128,230,231],{"class":167}," =",[128,233,234],{"class":167}," new",[128,236,237],{"class":134}," Ollama",[128,239,240],{"class":171},"({ host: ",[128,242,243],{"class":138},"\"http://localhost:11434\"",[128,245,246],{"class":171}," });\n",[128,248,250],{"class":130,"line":249},6,[128,251,218],{"emptyLinePlaceholder":217},[128,253,255,257,260,262,265,268,271],{"class":130,"line":254},7,[128,256,224],{"class":167},[128,258,259],{"class":227}," client",[128,261,231],{"class":167},[128,263,264],{"class":134}," NoLag",[128,266,267],{"class":171},"(",[128,269,270],{"class":227},"WORKER_TOKEN",[128,272,273],{"class":171},");\n",[128,275,277,279,282,284,286,289],{"class":130,"line":276},8,[128,278,224],{"class":167},[128,280,281],{"class":227}," worker",[128,283,231],{"class":167},[128,285,234],{"class":167},[128,287,288],{"class":134}," NoLagAgents",[128,290,291],{"class":171},"({\n",[128,293,295],{"class":130,"line":294},9,[128,296,297],{"class":171},"  client,\n",[128,299,301,304,307,310],{"class":130,"line":300},10,[128,302,303],{"class":171},"  appName: ",[128,305,306],{"class":227},"APP_SLUG",[128,308,309],{"class":171},", ",[128,311,313],{"class":312},"sJ8bj","// the suffixed slug returned when you created the app\n",[128,315,317,320,323],{"class":130,"line":316},11,[128,318,319],{"class":171},"  agentId: ",[128,321,322],{"class":138},"\"llama-worker\"",[128,324,325],{"class":171},",\n",[128,327,329],{"class":130,"line":328},12,[128,330,331],{"class":171},"  presence: {\n",[128,333,335,338,340],{"class":130,"line":334},13,[128,336,337],{"class":171},"    name: ",[128,339,322],{"class":138},[128,341,325],{"class":171},[128,343,345,348,351],{"class":130,"line":344},14,[128,346,347],{"class":171},"    role: ",[128,349,350],{"class":138},"\"agent\"",[128,352,325],{"class":171},[128,354,356,359,362,364,367],{"class":130,"line":355},15,[128,357,358],{"class":171},"    capabilities: [",[128,360,361],{"class":138},"\"summarize\"",[128,363,309],{"class":171},[128,365,366],{"class":138},"\"classify\"",[128,368,369],{"class":171},"],\n",[128,371,373,376,379,382,385],{"class":130,"line":372},16,[128,374,375],{"class":171},"    metadata: { model: ",[128,377,378],{"class":138},"\"llama3.2\"",[128,380,381],{"class":171},", provider: ",[128,383,384],{"class":138},"\"local\"",[128,386,387],{"class":171}," },\n",[128,389,391],{"class":130,"line":390},17,[128,392,393],{"class":171},"  },\n",[128,395,397],{"class":130,"line":396},18,[128,398,399],{"class":171},"});\n",[128,401,403],{"class":130,"line":402},19,[128,404,218],{"emptyLinePlaceholder":217},[128,406,408,411,414,417],{"class":130,"line":407},20,[128,409,410],{"class":167},"await",[128,412,413],{"class":171}," client.",[128,415,416],{"class":134},"connect",[128,418,419],{"class":171},"();\n",[128,421,423,425,428,431],{"class":130,"line":422},21,[128,424,410],{"class":167},[128,426,427],{"class":171}," worker.",[128,429,430],{"class":134},"ready",[128,432,419],{"class":171},[128,434,436,438,441,443,445,448,450,453],{"class":130,"line":435},22,[128,437,224],{"class":167},[128,439,440],{"class":227}," room",[128,442,231],{"class":167},[128,444,427],{"class":171},[128,446,447],{"class":134},"room",[128,449,267],{"class":171},[128,451,452],{"class":138},"\"default-workflow\"",[128,454,273],{"class":171},[128,456,458,460,463,465,467,470],{"class":130,"line":457},23,[128,459,224],{"class":167},[128,461,462],{"class":227}," handoff",[128,464,231],{"class":167},[128,466,234],{"class":167},[128,468,469],{"class":134}," Handoff",[128,471,472],{"class":171},"(room);\n",[128,474,476],{"class":130,"line":475},24,[128,477,218],{"emptyLinePlaceholder":217},[128,479,481,484,487,490,492,494,496,499,502,505,509,511,514,517,520],{"class":130,"line":480},25,[128,482,483],{"class":171},"handoff.",[128,485,486],{"class":134},"onTask",[128,488,489],{"class":171},"([",[128,491,361],{"class":138},[128,493,309],{"class":171},[128,495,366],{"class":138},[128,497,498],{"class":171},"], ",[128,500,501],{"class":167},"async",[128,503,504],{"class":171}," (",[128,506,508],{"class":507},"s4XuR","task",[128,510,309],{"class":171},[128,512,513],{"class":507},"respond",[128,515,516],{"class":171},") ",[128,518,519],{"class":167},"=>",[128,521,522],{"class":171}," {\n",[128,524,526,529,532,534,537,540,543],{"class":130,"line":525},26,[128,527,528],{"class":167},"  const",[128,530,531],{"class":227}," response",[128,533,231],{"class":167},[128,535,536],{"class":167}," await",[128,538,539],{"class":171}," ollama.",[128,541,542],{"class":134},"chat",[128,544,291],{"class":171},[128,546,548,551,553],{"class":130,"line":547},27,[128,549,550],{"class":171},"    model: ",[128,552,378],{"class":138},[128,554,325],{"class":171},[128,556,558],{"class":130,"line":557},28,[128,559,560],{"class":171},"    messages: [\n",[128,562,564,567,570,573,576,578,581,584,587],{"class":130,"line":563},29,[128,565,566],{"class":171},"      { role: ",[128,568,569],{"class":138},"\"system\"",[128,571,572],{"class":171},", content: ",[128,574,575],{"class":138},"`You are a ${",[128,577,508],{"class":171},[128,579,580],{"class":138},".",[128,582,583],{"class":171},"capability",[128,585,586],{"class":138},"} agent.`",[128,588,387],{"class":171},[128,590,592,594,597,599,602],{"class":130,"line":591},30,[128,593,566],{"class":171},[128,595,596],{"class":138},"\"user\"",[128,598,572],{"class":171},[128,600,601],{"class":134},"String",[128,603,604],{"class":171},"(task.payload.text) },\n",[128,606,608],{"class":130,"line":607},31,[128,609,610],{"class":171},"    ],\n",[128,612,614],{"class":130,"line":613},32,[128,615,616],{"class":171},"  });\n",[128,618,620],{"class":130,"line":619},33,[128,621,218],{"emptyLinePlaceholder":217},[128,623,625,628,630,633],{"class":130,"line":624},34,[128,626,627],{"class":134},"  respond",[128,629,267],{"class":171},[128,631,632],{"class":138},"\"success\"",[128,634,635],{"class":171},", {\n",[128,637,639],{"class":130,"line":638},35,[128,640,641],{"class":171},"    result: response.message.content,\n",[128,643,645,647,649],{"class":130,"line":644},36,[128,646,550],{"class":171},[128,648,378],{"class":138},[128,650,325],{"class":171},[128,652,654,657,660,663,666],{"class":130,"line":653},37,[128,655,656],{"class":171},"    latencyMs: Date.",[128,658,659],{"class":134},"now",[128,661,662],{"class":171},"() ",[128,664,665],{"class":167},"-",[128,667,668],{"class":171}," task.createdAt,\n",[128,670,672],{"class":130,"line":671},38,[128,673,616],{"class":171},[128,675,677],{"class":130,"line":676},39,[128,678,399],{"class":171},[128,680,682],{"class":130,"line":681},40,[128,683,218],{"emptyLinePlaceholder":217},[128,685,687,690,693,695,698],{"class":130,"line":686},41,[128,688,689],{"class":171},"console.",[128,691,692],{"class":134},"log",[128,694,267],{"class":171},[128,696,697],{"class":138},"\"Worker online. Waiting for tasks...\"",[128,699,273],{"class":171},[11,701,702,703,706,707,709,710,712],{},"That's the entire worker. No routing table, no queue to operate. The ",[59,704,705],{},"presence"," block tells the system what this worker can do, and ",[59,708,486],{}," keeps only the tasks whose ",[59,711,583],{}," matches. Every task in the room reaches every worker; the capability filter decides which one acts on it.",[18,714,716],{"id":715},"step-2-dispatch-a-task","Step 2: Dispatch a Task",[11,718,719],{},"From any other process (a backend service, a CLI script, another agent) dispatch a task by capability:",[153,721,722],{},[119,723,726],{"className":157,"code":724,"filename":725,"language":160,"meta":124,"style":124},"import { NoLag } from \"@nolag/js-sdk\";\nimport { NoLagAgents, Handoff } from \"@nolag/agents\";\n\nconst client = NoLag(ORCHESTRATOR_TOKEN);\nconst orchestrator = new NoLagAgents({\n  client,\n  appName: APP_SLUG,\n  agentId: \"orchestrator\",\n  presence: { name: \"orchestrator\", role: \"orchestrator\" },\n});\n\nawait client.connect();\nawait orchestrator.ready();\nconst room = orchestrator.room(\"default-workflow\");\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. dispatch() checks presence first and throws if no\n// connected worker advertises the capability.\nconst result = await handoff.dispatch(\"summarize\", {\n  text: \"NoLag is a real-time messaging infrastructure...\"\n}, {\n  waitForResult: true,\n  timeout: 30000,\n});\n\nif (result) {\n  console.log(\"Result:\", result.payload.result);\n  console.log(\"Model:\", result.payload.model);\n  console.log(\"Latency:\", result.payload.latencyMs, \"ms\");\n}\n","dispatch.ts",[59,727,728,740,752,756,773,788,792,800,809,823,827,831,841,852,870,884,888,893,914,938,942,947,952,975,983,988,998,1008,1012,1016,1024,1039,1053,1072],{"__ignoreMap":124},[128,729,730,732,734,736,738],{"class":130,"line":131},[128,731,168],{"class":167},[128,733,172],{"class":171},[128,735,175],{"class":167},[128,737,178],{"class":138},[128,739,181],{"class":171},[128,741,742,744,746,748,750],{"class":130,"line":184},[128,743,168],{"class":167},[128,745,189],{"class":171},[128,747,175],{"class":167},[128,749,194],{"class":138},[128,751,181],{"class":171},[128,753,754],{"class":130,"line":199},[128,755,218],{"emptyLinePlaceholder":217},[128,757,758,760,762,764,766,768,771],{"class":130,"line":214},[128,759,224],{"class":167},[128,761,259],{"class":227},[128,763,231],{"class":167},[128,765,264],{"class":134},[128,767,267],{"class":171},[128,769,770],{"class":227},"ORCHESTRATOR_TOKEN",[128,772,273],{"class":171},[128,774,775,777,780,782,784,786],{"class":130,"line":221},[128,776,224],{"class":167},[128,778,779],{"class":227}," orchestrator",[128,781,231],{"class":167},[128,783,234],{"class":167},[128,785,288],{"class":134},[128,787,291],{"class":171},[128,789,790],{"class":130,"line":249},[128,791,297],{"class":171},[128,793,794,796,798],{"class":130,"line":254},[128,795,303],{"class":171},[128,797,306],{"class":227},[128,799,325],{"class":171},[128,801,802,804,807],{"class":130,"line":276},[128,803,319],{"class":171},[128,805,806],{"class":138},"\"orchestrator\"",[128,808,325],{"class":171},[128,810,811,814,816,819,821],{"class":130,"line":294},[128,812,813],{"class":171},"  presence: { name: ",[128,815,806],{"class":138},[128,817,818],{"class":171},", role: ",[128,820,806],{"class":138},[128,822,387],{"class":171},[128,824,825],{"class":130,"line":300},[128,826,399],{"class":171},[128,828,829],{"class":130,"line":316},[128,830,218],{"emptyLinePlaceholder":217},[128,832,833,835,837,839],{"class":130,"line":328},[128,834,410],{"class":167},[128,836,413],{"class":171},[128,838,416],{"class":134},[128,840,419],{"class":171},[128,842,843,845,848,850],{"class":130,"line":334},[128,844,410],{"class":167},[128,846,847],{"class":171}," orchestrator.",[128,849,430],{"class":134},[128,851,419],{"class":171},[128,853,854,856,858,860,862,864,866,868],{"class":130,"line":344},[128,855,224],{"class":167},[128,857,440],{"class":227},[128,859,231],{"class":167},[128,861,847],{"class":171},[128,863,447],{"class":134},[128,865,267],{"class":171},[128,867,452],{"class":138},[128,869,273],{"class":171},[128,871,872,874,876,878,880,882],{"class":130,"line":355},[128,873,224],{"class":167},[128,875,462],{"class":227},[128,877,231],{"class":167},[128,879,234],{"class":167},[128,881,469],{"class":134},[128,883,472],{"class":171},[128,885,886],{"class":130,"line":372},[128,887,218],{"emptyLinePlaceholder":217},[128,889,890],{"class":130,"line":390},[128,891,892],{"class":312},"// Check who's online\n",[128,894,895,897,900,902,905,908,910,912],{"class":130,"line":396},[128,896,224],{"class":167},[128,898,899],{"class":227}," workers",[128,901,231],{"class":167},[128,903,904],{"class":171}," room.",[128,906,907],{"class":134},"findAgents",[128,909,267],{"class":171},[128,911,361],{"class":138},[128,913,273],{"class":171},[128,915,916,918,920,922,925,928,930,933,936],{"class":130,"line":402},[128,917,689],{"class":171},[128,919,692],{"class":134},[128,921,267],{"class":171},[128,923,924],{"class":138},"`${",[128,926,927],{"class":171},"workers",[128,929,580],{"class":138},[128,931,932],{"class":227},"length",[128,934,935],{"class":138},"} summarize worker(s) online`",[128,937,273],{"class":171},[128,939,940],{"class":130,"line":407},[128,941,218],{"emptyLinePlaceholder":217},[128,943,944],{"class":130,"line":422},[128,945,946],{"class":312},"// Dispatch a task. dispatch() checks presence first and throws if no\n",[128,948,949],{"class":130,"line":435},[128,950,951],{"class":312},"// connected worker advertises the capability.\n",[128,953,954,956,959,961,963,966,969,971,973],{"class":130,"line":457},[128,955,224],{"class":167},[128,957,958],{"class":227}," result",[128,960,231],{"class":167},[128,962,536],{"class":167},[128,964,965],{"class":171}," handoff.",[128,967,968],{"class":134},"dispatch",[128,970,267],{"class":171},[128,972,361],{"class":138},[128,974,635],{"class":171},[128,976,977,980],{"class":130,"line":475},[128,978,979],{"class":171},"  text: ",[128,981,982],{"class":138},"\"NoLag is a real-time messaging infrastructure...\"\n",[128,984,985],{"class":130,"line":480},[128,986,987],{"class":171},"}, {\n",[128,989,990,993,996],{"class":130,"line":525},[128,991,992],{"class":171},"  waitForResult: ",[128,994,995],{"class":227},"true",[128,997,325],{"class":171},[128,999,1000,1003,1006],{"class":130,"line":547},[128,1001,1002],{"class":171},"  timeout: ",[128,1004,1005],{"class":227},"30000",[128,1007,325],{"class":171},[128,1009,1010],{"class":130,"line":557},[128,1011,399],{"class":171},[128,1013,1014],{"class":130,"line":563},[128,1015,218],{"emptyLinePlaceholder":217},[128,1017,1018,1021],{"class":130,"line":591},[128,1019,1020],{"class":167},"if",[128,1022,1023],{"class":171}," (result) {\n",[128,1025,1026,1029,1031,1033,1036],{"class":130,"line":607},[128,1027,1028],{"class":171},"  console.",[128,1030,692],{"class":134},[128,1032,267],{"class":171},[128,1034,1035],{"class":138},"\"Result:\"",[128,1037,1038],{"class":171},", result.payload.result);\n",[128,1040,1041,1043,1045,1047,1050],{"class":130,"line":613},[128,1042,1028],{"class":171},[128,1044,692],{"class":134},[128,1046,267],{"class":171},[128,1048,1049],{"class":138},"\"Model:\"",[128,1051,1052],{"class":171},", result.payload.model);\n",[128,1054,1055,1057,1059,1061,1064,1067,1070],{"class":130,"line":619},[128,1056,1028],{"class":171},[128,1058,692],{"class":134},[128,1060,267],{"class":171},[128,1062,1063],{"class":138},"\"Latency:\"",[128,1065,1066],{"class":171},", result.payload.latencyMs, ",[128,1068,1069],{"class":138},"\"ms\"",[128,1071,273],{"class":171},[128,1073,1074],{"class":130,"line":624},[128,1075,1076],{"class":171},"}\n",[11,1078,1079,1080,1083],{},"The orchestrator doesn't import ",[59,1081,1082],{},"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. The dispatcher and the worker are different actors, which matters: a publishing actor never receives its own messages, so one token shared by both would never see the result.",[18,1085,1087],{"id":1086},"step-3-add-a-second-model","Step 3: Add a Second Model",[11,1089,1090],{},"Pull another model and spin up a second worker with different capabilities:",[119,1092,1094],{"className":121,"code":1093,"language":123,"meta":124,"style":124},"ollama pull mistral\n",[59,1095,1096],{"__ignoreMap":124},[128,1097,1098,1100,1103],{"class":130,"line":131},[128,1099,1082],{"class":134},[128,1101,1102],{"class":138}," pull",[128,1104,1105],{"class":138}," mistral\n",[153,1107,1108],{},[119,1109,1112],{"className":157,"code":1110,"filename":1111,"language":160,"meta":124,"style":124},"import { NoLag } from \"@nolag/js-sdk\";\nimport { NoLagAgents, Handoff } from \"@nolag/agents\";\nimport { Ollama } from \"ollama\";\n\nconst ollama = new Ollama({ host: \"http://localhost:11434\" });\n\nconst client = NoLag(MISTRAL_WORKER_TOKEN);\nconst worker = new NoLagAgents({\n  client,\n  appName: APP_SLUG,\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 client.connect();\nawait worker.ready();\nconst room = worker.room(\"default-workflow\");\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.capability} agent.` },\n      { role: \"user\", content: String(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,1113,1114,1126,1138,1150,1154,1172,1176,1193,1207,1211,1219,1228,1232,1240,1248,1262,1275,1279,1283,1287,1297,1307,1325,1339,1343,1375,1391,1399,1403,1424,1436,1440,1444,1448,1458,1462,1470,1482,1486],{"__ignoreMap":124},[128,1115,1116,1118,1120,1122,1124],{"class":130,"line":131},[128,1117,168],{"class":167},[128,1119,172],{"class":171},[128,1121,175],{"class":167},[128,1123,178],{"class":138},[128,1125,181],{"class":171},[128,1127,1128,1130,1132,1134,1136],{"class":130,"line":184},[128,1129,168],{"class":167},[128,1131,189],{"class":171},[128,1133,175],{"class":167},[128,1135,194],{"class":138},[128,1137,181],{"class":171},[128,1139,1140,1142,1144,1146,1148],{"class":130,"line":199},[128,1141,168],{"class":167},[128,1143,204],{"class":171},[128,1145,175],{"class":167},[128,1147,209],{"class":138},[128,1149,181],{"class":171},[128,1151,1152],{"class":130,"line":214},[128,1153,218],{"emptyLinePlaceholder":217},[128,1155,1156,1158,1160,1162,1164,1166,1168,1170],{"class":130,"line":221},[128,1157,224],{"class":167},[128,1159,228],{"class":227},[128,1161,231],{"class":167},[128,1163,234],{"class":167},[128,1165,237],{"class":134},[128,1167,240],{"class":171},[128,1169,243],{"class":138},[128,1171,246],{"class":171},[128,1173,1174],{"class":130,"line":249},[128,1175,218],{"emptyLinePlaceholder":217},[128,1177,1178,1180,1182,1184,1186,1188,1191],{"class":130,"line":254},[128,1179,224],{"class":167},[128,1181,259],{"class":227},[128,1183,231],{"class":167},[128,1185,264],{"class":134},[128,1187,267],{"class":171},[128,1189,1190],{"class":227},"MISTRAL_WORKER_TOKEN",[128,1192,273],{"class":171},[128,1194,1195,1197,1199,1201,1203,1205],{"class":130,"line":276},[128,1196,224],{"class":167},[128,1198,281],{"class":227},[128,1200,231],{"class":167},[128,1202,234],{"class":167},[128,1204,288],{"class":134},[128,1206,291],{"class":171},[128,1208,1209],{"class":130,"line":294},[128,1210,297],{"class":171},[128,1212,1213,1215,1217],{"class":130,"line":300},[128,1214,303],{"class":171},[128,1216,306],{"class":227},[128,1218,325],{"class":171},[128,1220,1221,1223,1226],{"class":130,"line":316},[128,1222,319],{"class":171},[128,1224,1225],{"class":138},"\"mistral-worker\"",[128,1227,325],{"class":171},[128,1229,1230],{"class":130,"line":328},[128,1231,331],{"class":171},[128,1233,1234,1236,1238],{"class":130,"line":334},[128,1235,337],{"class":171},[128,1237,1225],{"class":138},[128,1239,325],{"class":171},[128,1241,1242,1244,1246],{"class":130,"line":344},[128,1243,347],{"class":171},[128,1245,350],{"class":138},[128,1247,325],{"class":171},[128,1249,1250,1252,1255,1257,1260],{"class":130,"line":355},[128,1251,358],{"class":171},[128,1253,1254],{"class":138},"\"extract-entities\"",[128,1256,309],{"class":171},[128,1258,1259],{"class":138},"\"translate\"",[128,1261,369],{"class":171},[128,1263,1264,1266,1269,1271,1273],{"class":130,"line":372},[128,1265,375],{"class":171},[128,1267,1268],{"class":138},"\"mistral\"",[128,1270,381],{"class":171},[128,1272,384],{"class":138},[128,1274,387],{"class":171},[128,1276,1277],{"class":130,"line":390},[128,1278,393],{"class":171},[128,1280,1281],{"class":130,"line":396},[128,1282,399],{"class":171},[128,1284,1285],{"class":130,"line":402},[128,1286,218],{"emptyLinePlaceholder":217},[128,1288,1289,1291,1293,1295],{"class":130,"line":407},[128,1290,410],{"class":167},[128,1292,413],{"class":171},[128,1294,416],{"class":134},[128,1296,419],{"class":171},[128,1298,1299,1301,1303,1305],{"class":130,"line":422},[128,1300,410],{"class":167},[128,1302,427],{"class":171},[128,1304,430],{"class":134},[128,1306,419],{"class":171},[128,1308,1309,1311,1313,1315,1317,1319,1321,1323],{"class":130,"line":435},[128,1310,224],{"class":167},[128,1312,440],{"class":227},[128,1314,231],{"class":167},[128,1316,427],{"class":171},[128,1318,447],{"class":134},[128,1320,267],{"class":171},[128,1322,452],{"class":138},[128,1324,273],{"class":171},[128,1326,1327,1329,1331,1333,1335,1337],{"class":130,"line":457},[128,1328,224],{"class":167},[128,1330,462],{"class":227},[128,1332,231],{"class":167},[128,1334,234],{"class":167},[128,1336,469],{"class":134},[128,1338,472],{"class":171},[128,1340,1341],{"class":130,"line":475},[128,1342,218],{"emptyLinePlaceholder":217},[128,1344,1345,1347,1349,1351,1353,1355,1357,1359,1361,1363,1365,1367,1369,1371,1373],{"class":130,"line":480},[128,1346,483],{"class":171},[128,1348,486],{"class":134},[128,1350,489],{"class":171},[128,1352,1254],{"class":138},[128,1354,309],{"class":171},[128,1356,1259],{"class":138},[128,1358,498],{"class":171},[128,1360,501],{"class":167},[128,1362,504],{"class":171},[128,1364,508],{"class":507},[128,1366,309],{"class":171},[128,1368,513],{"class":507},[128,1370,516],{"class":171},[128,1372,519],{"class":167},[128,1374,522],{"class":171},[128,1376,1377,1379,1381,1383,1385,1387,1389],{"class":130,"line":525},[128,1378,528],{"class":167},[128,1380,531],{"class":227},[128,1382,231],{"class":167},[128,1384,536],{"class":167},[128,1386,539],{"class":171},[128,1388,542],{"class":134},[128,1390,291],{"class":171},[128,1392,1393,1395,1397],{"class":130,"line":547},[128,1394,550],{"class":171},[128,1396,1268],{"class":138},[128,1398,325],{"class":171},[128,1400,1401],{"class":130,"line":557},[128,1402,560],{"class":171},[128,1404,1405,1407,1409,1411,1414,1416,1418,1420,1422],{"class":130,"line":563},[128,1406,566],{"class":171},[128,1408,569],{"class":138},[128,1410,572],{"class":171},[128,1412,1413],{"class":138},"`You are an ${",[128,1415,508],{"class":171},[128,1417,580],{"class":138},[128,1419,583],{"class":171},[128,1421,586],{"class":138},[128,1423,387],{"class":171},[128,1425,1426,1428,1430,1432,1434],{"class":130,"line":591},[128,1427,566],{"class":171},[128,1429,596],{"class":138},[128,1431,572],{"class":171},[128,1433,601],{"class":134},[128,1435,604],{"class":171},[128,1437,1438],{"class":130,"line":607},[128,1439,610],{"class":171},[128,1441,1442],{"class":130,"line":613},[128,1443,616],{"class":171},[128,1445,1446],{"class":130,"line":619},[128,1447,218],{"emptyLinePlaceholder":217},[128,1449,1450,1452,1454,1456],{"class":130,"line":624},[128,1451,627],{"class":134},[128,1453,267],{"class":171},[128,1455,632],{"class":138},[128,1457,635],{"class":171},[128,1459,1460],{"class":130,"line":638},[128,1461,641],{"class":171},[128,1463,1464,1466,1468],{"class":130,"line":644},[128,1465,550],{"class":171},[128,1467,1268],{"class":138},[128,1469,325],{"class":171},[128,1471,1472,1474,1476,1478,1480],{"class":130,"line":653},[128,1473,656],{"class":171},[128,1475,659],{"class":134},[128,1477,662],{"class":171},[128,1479,665],{"class":167},[128,1481,668],{"class":171},[128,1483,1484],{"class":130,"line":671},[128,1485,616],{"class":171},[128,1487,1488],{"class":130,"line":676},[128,1489,399],{"class":171},[11,1491,1492],{},"Now dispatch tasks and each one is acted on by the worker that registered its capability:",[153,1494,1495],{},[119,1496,1499],{"className":157,"code":1497,"filename":1498,"language":160,"meta":124,"style":124},"// The orchestrator doesn't change.\n// Dispatch by capability; the matching worker picks it up.\n\nconst summary = await handoff.dispatch(\"summarize\", {\n  text: document\n}, { waitForResult: true });\n// -> handled by llama-worker\n\nconst entities = await handoff.dispatch(\"extract-entities\", {\n  text: document\n}, { waitForResult: true });\n// -> handled by mistral-worker\n\nconst translation = await handoff.dispatch(\"translate\", {\n  text: summary ? summary.payload.result : document\n}, { waitForResult: true });\n// -> handled by 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,1500,1501,1506,1511,1515,1536,1541,1550,1555,1559,1580,1584,1592,1597,1601,1622,1639,1647,1651,1655,1660],{"__ignoreMap":124},[128,1502,1503],{"class":130,"line":131},[128,1504,1505],{"class":312},"// The orchestrator doesn't change.\n",[128,1507,1508],{"class":130,"line":184},[128,1509,1510],{"class":312},"// Dispatch by capability; the matching worker picks it up.\n",[128,1512,1513],{"class":130,"line":199},[128,1514,218],{"emptyLinePlaceholder":217},[128,1516,1517,1519,1522,1524,1526,1528,1530,1532,1534],{"class":130,"line":214},[128,1518,224],{"class":167},[128,1520,1521],{"class":227}," summary",[128,1523,231],{"class":167},[128,1525,536],{"class":167},[128,1527,965],{"class":171},[128,1529,968],{"class":134},[128,1531,267],{"class":171},[128,1533,361],{"class":138},[128,1535,635],{"class":171},[128,1537,1538],{"class":130,"line":221},[128,1539,1540],{"class":171},"  text: document\n",[128,1542,1543,1546,1548],{"class":130,"line":249},[128,1544,1545],{"class":171},"}, { waitForResult: ",[128,1547,995],{"class":227},[128,1549,246],{"class":171},[128,1551,1552],{"class":130,"line":254},[128,1553,1554],{"class":312},"// -> handled by llama-worker\n",[128,1556,1557],{"class":130,"line":276},[128,1558,218],{"emptyLinePlaceholder":217},[128,1560,1561,1563,1566,1568,1570,1572,1574,1576,1578],{"class":130,"line":294},[128,1562,224],{"class":167},[128,1564,1565],{"class":227}," entities",[128,1567,231],{"class":167},[128,1569,536],{"class":167},[128,1571,965],{"class":171},[128,1573,968],{"class":134},[128,1575,267],{"class":171},[128,1577,1254],{"class":138},[128,1579,635],{"class":171},[128,1581,1582],{"class":130,"line":300},[128,1583,1540],{"class":171},[128,1585,1586,1588,1590],{"class":130,"line":316},[128,1587,1545],{"class":171},[128,1589,995],{"class":227},[128,1591,246],{"class":171},[128,1593,1594],{"class":130,"line":328},[128,1595,1596],{"class":312},"// -> handled by mistral-worker\n",[128,1598,1599],{"class":130,"line":334},[128,1600,218],{"emptyLinePlaceholder":217},[128,1602,1603,1605,1608,1610,1612,1614,1616,1618,1620],{"class":130,"line":344},[128,1604,224],{"class":167},[128,1606,1607],{"class":227}," translation",[128,1609,231],{"class":167},[128,1611,536],{"class":167},[128,1613,965],{"class":171},[128,1615,968],{"class":134},[128,1617,267],{"class":171},[128,1619,1259],{"class":138},[128,1621,635],{"class":171},[128,1623,1624,1627,1630,1633,1636],{"class":130,"line":355},[128,1625,1626],{"class":171},"  text: summary ",[128,1628,1629],{"class":167},"?",[128,1631,1632],{"class":171}," summary.payload.result ",[128,1634,1635],{"class":167},":",[128,1637,1638],{"class":171}," document\n",[128,1640,1641,1643,1645],{"class":130,"line":372},[128,1642,1545],{"class":171},[128,1644,995],{"class":227},[128,1646,246],{"class":171},[128,1648,1649],{"class":130,"line":390},[128,1650,1596],{"class":312},[128,1652,1653],{"class":130,"line":396},[128,1654,218],{"emptyLinePlaceholder":217},[128,1656,1657],{"class":130,"line":402},[128,1658,1659],{"class":312},"// All three tasks ran on local models.\n",[128,1661,1662],{"class":130,"line":407},[128,1663,1664],{"class":312},"// No API keys. No egress. No per-token billing.\n",[11,1666,1667,1668,1672,1673,1676],{},"The orchestrator dispatches by ",[1669,1670,1671],"em",{},"what needs doing",", not by ",[1669,1674,1675],{},"which model does it",". Add a third model, remove one, restart a worker: the system adapts because discovery is based on presence, not hardcoded addresses.",[18,1678,1680],{"id":1679},"what-you-get-for-free","What You Get for Free",[1682,1683,1684],"h3",{"id":705},"Presence",[11,1686,1687],{},"Every connected worker shows up in real time. You always know which models are online and what they can do.",[153,1689,1690],{},[119,1691,1694],{"className":157,"code":1692,"filename":1693,"language":160,"meta":124,"style":124},"// See every connected agent, and react as they come and go\nfunction printAgents() {\n  for (const agent of room.getConnectedAgents()) {\n    console.log(`${agent.name} [${agent.status ?? \"online\"}]`);\n    console.log(`  capabilities: ${agent.capabilities.join(\", \") || \"(none)\"}`);\n    console.log(`  model: ${agent.metadata?.model}`);\n  }\n}\n\nroom.on(\"presenceJoin\", printAgents);\nroom.on(\"presenceUpdate\", printAgents);\nroom.on(\"presenceLeave\", printAgents);\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,1695,1696,1701,1712,1735,1771,1809,1838,1843,1847,1851,1867,1880,1893,1897,1902,1907,1912,1917,1922,1927,1932,1937],{"__ignoreMap":124},[128,1697,1698],{"class":130,"line":131},[128,1699,1700],{"class":312},"// See every connected agent, and react as they come and go\n",[128,1702,1703,1706,1709],{"class":130,"line":184},[128,1704,1705],{"class":167},"function",[128,1707,1708],{"class":134}," printAgents",[128,1710,1711],{"class":171},"() {\n",[128,1713,1714,1717,1719,1721,1724,1727,1729,1732],{"class":130,"line":199},[128,1715,1716],{"class":167},"  for",[128,1718,504],{"class":171},[128,1720,224],{"class":167},[128,1722,1723],{"class":227}," agent",[128,1725,1726],{"class":167}," of",[128,1728,904],{"class":171},[128,1730,1731],{"class":134},"getConnectedAgents",[128,1733,1734],{"class":171},"()) {\n",[128,1736,1737,1740,1742,1744,1746,1748,1750,1753,1756,1758,1760,1763,1766,1769],{"class":130,"line":214},[128,1738,1739],{"class":171},"    console.",[128,1741,692],{"class":134},[128,1743,267],{"class":171},[128,1745,924],{"class":138},[128,1747,88],{"class":171},[128,1749,580],{"class":138},[128,1751,1752],{"class":171},"name",[128,1754,1755],{"class":138},"} [${",[128,1757,88],{"class":171},[128,1759,580],{"class":138},[128,1761,1762],{"class":171},"status",[128,1764,1765],{"class":167}," ??",[128,1767,1768],{"class":138}," \"online\"}]`",[128,1770,273],{"class":171},[128,1772,1773,1775,1777,1779,1782,1784,1786,1789,1791,1794,1796,1799,1801,1804,1807],{"class":130,"line":221},[128,1774,1739],{"class":171},[128,1776,692],{"class":134},[128,1778,267],{"class":171},[128,1780,1781],{"class":138},"`  capabilities: ${",[128,1783,88],{"class":171},[128,1785,580],{"class":138},[128,1787,1788],{"class":171},"capabilities",[128,1790,580],{"class":138},[128,1792,1793],{"class":134},"join",[128,1795,267],{"class":138},[128,1797,1798],{"class":138},"\", \"",[128,1800,516],{"class":138},[128,1802,1803],{"class":167},"||",[128,1805,1806],{"class":138}," \"(none)\"}`",[128,1808,273],{"class":171},[128,1810,1811,1813,1815,1817,1820,1822,1824,1827,1830,1833,1836],{"class":130,"line":249},[128,1812,1739],{"class":171},[128,1814,692],{"class":134},[128,1816,267],{"class":171},[128,1818,1819],{"class":138},"`  model: ${",[128,1821,88],{"class":171},[128,1823,580],{"class":138},[128,1825,1826],{"class":171},"metadata",[128,1828,1829],{"class":138},"?.",[128,1831,1832],{"class":171},"model",[128,1834,1835],{"class":138},"}`",[128,1837,273],{"class":171},[128,1839,1840],{"class":130,"line":254},[128,1841,1842],{"class":171},"  }\n",[128,1844,1845],{"class":130,"line":276},[128,1846,1076],{"class":171},[128,1848,1849],{"class":130,"line":294},[128,1850,218],{"emptyLinePlaceholder":217},[128,1852,1853,1856,1859,1861,1864],{"class":130,"line":300},[128,1854,1855],{"class":171},"room.",[128,1857,1858],{"class":134},"on",[128,1860,267],{"class":171},[128,1862,1863],{"class":138},"\"presenceJoin\"",[128,1865,1866],{"class":171},", printAgents);\n",[128,1868,1869,1871,1873,1875,1878],{"class":130,"line":316},[128,1870,1855],{"class":171},[128,1872,1858],{"class":134},[128,1874,267],{"class":171},[128,1876,1877],{"class":138},"\"presenceUpdate\"",[128,1879,1866],{"class":171},[128,1881,1882,1884,1886,1888,1891],{"class":130,"line":328},[128,1883,1855],{"class":171},[128,1885,1858],{"class":134},[128,1887,267],{"class":171},[128,1889,1890],{"class":138},"\"presenceLeave\"",[128,1892,1866],{"class":171},[128,1894,1895],{"class":130,"line":334},[128,1896,218],{"emptyLinePlaceholder":217},[128,1898,1899],{"class":130,"line":344},[128,1900,1901],{"class":312},"// Output:\n",[128,1903,1904],{"class":130,"line":355},[128,1905,1906],{"class":312},"// llama-worker [online]\n",[128,1908,1909],{"class":130,"line":372},[128,1910,1911],{"class":312},"//   capabilities: summarize, classify\n",[128,1913,1914],{"class":130,"line":390},[128,1915,1916],{"class":312},"//   model: llama3.2\n",[128,1918,1919],{"class":130,"line":396},[128,1920,1921],{"class":312},"// mistral-worker [online]\n",[128,1923,1924],{"class":130,"line":402},[128,1925,1926],{"class":312},"//   capabilities: extract-entities, translate\n",[128,1928,1929],{"class":130,"line":407},[128,1930,1931],{"class":312},"//   model: mistral\n",[128,1933,1934],{"class":130,"line":422},[128,1935,1936],{"class":312},"// orchestrator [online]\n",[128,1938,1939],{"class":130,"line":435},[128,1940,1941],{"class":312},"//   capabilities: (none)\n",[11,1943,1944],{},"The NoLag portal's Agents view shows this same list graphically, no custom monitoring needed.",[1682,1946,1948],{"id":1947},"reconnection","Reconnection",[11,1950,1951,1952,1956,1957,1960],{},"If a worker disconnects (machine reboots, network blip, Ollama restart), the core client reconnects automatically and the wrapper restores its room and presence. Whether tasks dispatched in the meantime are waiting for it depends on how it subscribed: NoLag holds and replays missed tasks only for load-balanced worker groups with persistent sessions on the hosted platform (see ",[81,1953,1955],{"href":1954},"/docs/concepts/replay","replay","). A single worker subscribed without load balancing misses whatever was dispatched while it was away, and the dispatcher's ",[59,1958,1959],{},"waitForResult"," timeout is what tells you.",[1682,1962,1964],{"id":1963},"load-balancing","Load Balancing",[11,1966,1967],{},"Run two instances of the same worker on two machines and turn load balancing on for both:",[153,1969,1970],{},[119,1971,1974],{"className":157,"code":1972,"filename":1973,"language":160,"meta":124,"style":124},"// Each task goes to ONE member of the \"llama-workers\" group\nconst client = NoLag(WORKER_TOKEN, { loadBalance: true, loadBalanceGroup: \"llama-workers\" });\n","pool.ts",[59,1975,1976,1981],{"__ignoreMap":124},[128,1977,1978],{"class":130,"line":131},[128,1979,1980],{"class":312},"// Each task goes to ONE member of the \"llama-workers\" group\n",[128,1982,1983,1985,1987,1989,1991,1993,1995,1998,2000,2003,2006],{"class":130,"line":184},[128,1984,224],{"class":167},[128,1986,259],{"class":227},[128,1988,231],{"class":167},[128,1990,264],{"class":134},[128,1992,267],{"class":171},[128,1994,270],{"class":227},[128,1996,1997],{"class":171},", { loadBalance: ",[128,1999,995],{"class":227},[128,2001,2002],{"class":171},", loadBalanceGroup: ",[128,2004,2005],{"class":138},"\"llama-workers\"",[128,2007,246],{"class":171},[11,2009,2010],{},"Load balancing is opt-in. Without it every instance receives, and answers, every task.",[1682,2012,2014],{"id":2013},"observability","Observability",[11,2016,2017,2018,2021],{},"The portal's Agents tab shows which agents are connected and what they advertise. Results carry ",[59,2019,2020],{},"completedBy"," and whatever metadata the worker adds (model, latency), and workers can emit structured events with the Observe pattern for an observer agent to log to your own system.",[18,2023,2025],{"id":2024},"why-not-a-framework","Why Not a Framework?",[11,2027,2028],{},"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,2030,2031,2034,2037,2040],{},[29,2032,2033],{},"Agents can't run on different machines",[29,2035,2036],{},"You can't scale workers independently",[29,2038,2039],{},"If the coordinator crashes, everything stops",[29,2041,2042],{},"Adding a human approval step means hacking the framework's internals",[11,2044,2045],{},"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,2047,2049],{"id":2048},"next-steps","Next Steps",[26,2051,2052,2063,2069,2075],{},[29,2053,2054,2057,2058,2062],{},[54,2055,2056],{},"Add a cloud model",": see ",[81,2059,2061],{"href":2060},"/blog/hybrid-llm-orchestration","Hybrid LLM Coordination"," for mixing local and proprietary models",[29,2064,2065,2068],{},[54,2066,2067],{},"Add human approval",": gate sensitive actions with the Approve pattern before they execute",[29,2070,2071,2074],{},[54,2072,2073],{},"Share state",": use the Blackboard pattern to track model performance metrics across all workers",[29,2076,2077,57,2080],{},[54,2078,2079],{},"Read the docs",[81,2081,2083],{"href":2082},"/docs/agents/getting-started","@nolag/agents getting started guide",[11,2085,2086],{},"Your local model is the smart part. NoLag is the dumb pipe that makes it reachable. That's the whole idea.",[26,2088,2089,2093],{},[29,2090,2091],{},[81,2092,2061],{"href":2060},[29,2094,2095],{},[81,2096,2097],{"href":2082},"Agents Docs",[2099,2100,2101],"style",{},"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 .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 .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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":124,"searchDepth":184,"depth":184,"links":2103},[2104,2105,2106,2107,2108,2109,2115,2116],{"id":20,"depth":184,"text":21},{"id":46,"depth":184,"text":47},{"id":113,"depth":184,"text":114},{"id":715,"depth":184,"text":716},{"id":1086,"depth":184,"text":1087},{"id":1679,"depth":184,"text":1680,"children":2110},[2111,2112,2113,2114],{"id":705,"depth":199,"text":1684},{"id":1947,"depth":199,"text":1948},{"id":1963,"depth":199,"text":1964},{"id":2013,"depth":199,"text":2014},{"id":2024,"depth":184,"text":2025},{"id":2048,"depth":184,"text":2049},"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":2119},"blog/connect-local-llm","0YrORIdR01Y8sZpUYq7G9lqkAcN9g2GKi_6_FQGfVic",1789870597464]