Sakhanda Wire
NVDA $221.97 +2.54% MSFT $532.95 +0.20% GOOGL $334.76 -1.62% META $697.52 +0.47% AMZN $262.37 -0.10%
← До новин

Vercel відкрила вихідний код durable-harness для стійких до збоїв агентів програмування

Vercel випустила durable-harness — пакет із відкритим кодом, який підтримує роботу сесій агентів для програмування після збоїв і тайм-аутів. Vercel durable-harness обгортає наявні harness-системи, зокрема Pi, OpenCode, Claude Code і Codex, не змінюючи їх. Кожна сесія зберігається в надійному журналі. Завершення роботи функції більше не означає втрату виконаної роботи. Для команд, які переносять агентів із ноутбуків у хмару, це усуває реальну проблему.

Коротко

  • Розмір: npm-пакет, версія 0.0.x, Apache-2.0. Адаптери підтримують 5 harness-систем: Pi, OpenCode, fx, Claude Code, Codex.
  • Працює на: Vercel Functions разом із Vercel Queues, Node.js 22+ із Postgres або файлах на ноутбуці. Claude Code і Codex потребують Vercel Sandbox.
  • Продуктивність: опублікованих тестів затримки чи пропускної здатності немає. Усі заяви про відновлення базуються на даних, наведених самою Vercel.
  • Найкраще: завершені виклики моделей та інструментів зчитуються з журналу, тому їх не запускають повторно й не оплачують двічі.
  • Найгірше: експериментальний API версії 0.0.x. Claude Code і Codex працюють лише у Vercel Sandbox, навіть у разі самостійного розгортання.

Що таке durable-harness?

durable-harness — це набір адаптерів від Vercel, які зберігають сесію harness-системи у World Workflow SDK. World об’єднує сховище, чергу та потік в одному інтерфейсі. Пакет використовує ту саму інфраструктуру, що й Workflow SDK Vercel.

Чому агенти для програмування втрачають роботу в хмарі?

Такі harness-системи, як Pi і Claude Code, створювалися як довготривалі локальні процеси. Вони зберігають сесію в пам’яті. Локально робочий простір і історія розташовані на одному диску, тому для відновлення достатньо 1 запиту. У хмарі віртуальна машина зі сталим сховищем не відстежує, які виклики завершилися. Команда Vercel зазначає, що через це невдалий крок або мережеву помилку робота втрачається.

Як працює durable-harness?

Він записує кожен крок у журналі, що зберігається надійно. Перед запуском виклику моделі чи інструмента система записує намір. Після завершення виклику вона записує результат. Кожен крок підтримується повідомленням у Vercel Queues. Якщо функція завершує роботу, черга передає крок новій функції. Та функція читає журнал і продовжує виконання.

Після збою журнал показує, що завершилося, що виконувалося, а що так і не почалося:

  • Завершені виклики зчитуються з журналу, тому за вже згенеровані токени моделі не стягується плата повторно.
  • Інструменти replay: 'safe', наприклад пошукові запити, можна запустити повторно.
  • Інструменти replay: 'never', наприклад повернення коштів, ніколи не запускаються двічі. Модель отримує повідомлення, що виклик міг відбутися.

Файли сесій harness-систем також дублюються в журналі. Це охоплює транскрипт Claude Code, виконання Codex і сховище подій OpenCode.

Де виконуються файли та команди оболонки?

Команди, обрані моделлю, ніколи не виконуються на власному диску функції. У документації інструментів перелічено 3 варіанти робочого простору:

  • virtual() зберігає файли в журналі сесії, надаючи оболонку, сумісну з bash, без доступу до мережі. Вона підтримує близько 500 файлів.
  • virtual({ durable: false }) зберігає тимчасові файли в пам’яті й видаляє їх після кожного кроку.
  • sandbox() надає кожній сесії Vercel Sandbox, де /workspace розташований на Drive.

Типізовані JSON документи, як-от список завдань, також зберігаються в журналі. Розмір кожного не перевищує 64 КБ.

Запустити крок</button> <button class="b red" id="kill" disabled>Завершити роботу функції</button> <button class="b ghost" id="rst">Скинути</button> </div> <div class="log" id="lg"><div>Натисніть «Запустити крок», а потім завершіть роботу функції під час виконання CI.</div></div> <p class="note">Сценарій із допису Vercel: агент додає сторінку з цінами, відкриває PR і чекає на CI. Ілюстративна симуляція, а не бенчмарк.</p> </div> <div class="pane" id="p2"> <p class="sub" style="margin-bottom:12px">Натисніть інструмент, а потім завершіть його роботу під час виклику.</p> <div class="rules"> <div class="box tool sel" data-r="safe"><h4><code>get_order</code><span class="pill">replay: 'safe'</span></h4><span class="note">Пошуковий запит. Його безпечно повторити після збою.</span></div> <div class="box tool" data-r="never"><h4><code>refund_order</code><span class="pill">replay: 'never'</span></h4><span class="note">Повернення коштів. Не можна виконувати двічі.</span></div> </div> <div class="btns"><button class="b red" id="crash">Завершити під час виклику</button></div> <div class="verdict" id="vd">Оберіть інструмент і натисніть «Завершити під час виклику».</div> <pre id="code">{ name: 'get_order', replay: 'safe', ... }</pre> </div> <div class="pane" id="p3"> <div class="ws"> <div class="box sel" data-w="0"><h4><code>virtual()</code></h4><span class="note">Файли в журналі сесії. Оболонка, сумісна з Bash, без мережі.</span></div> <div class="box" data-w="1"><h4><code>virtual({durable:false})</code></h4><span class="note">Тимчасові файли в пам’яті. Видаляються після кожного кроку.</span></div> <div class="box" data-w="2"><h4><code>sandbox()</code></h4><span class="note">Vercel Sandbox для кожної сесії, <code>/workspace</code> на Drive.</span></div> </div> <div class="box" style="margin-top:14px" id="wsd"></div> </div> <div class="pane" id="p4"> <div class="worlds"> <div class="box world sel" data-g="0"><h4>Vercel</h4><span class="note">Vercel World + трасування Agent Runs</span></div> <div class="box world" data-g="1"><h4>Ноутбук</h4><span class="note">Локальні файли, нульова конфігурація</span></div> <div class="box world" data-g="2"><h4>Власний сервер</h4><span class="note">Postgres World, Node.js 22+</span></div> </div> <pre id="wc"></pre> <p class="note" id="wn"></p> </div> <div class="pane" id="p5"> <table> <tr><th>Harness-система</th><th>Пакет</th><th>Працює в</th><th>Статус</th></tr> <tr><td>Pi</td><td><code>durable-harness/pi-durable</code></td><td>Вашій функції + віртуальному робочому просторі або Sandbox</td><td class="y">Підтримується</td></tr> <tr><td>OpenCode</td><td><code>durable-harness/opencode</code></td><td>Вашій функції + віртуальному робочому просторі або Sandbox</td><td class="y">Підтримується</td></tr> <tr><td>fx</td><td><code>libfx</code></td><td>Самостійно з надійним збереженням</td><td class="y">Підтримується</td></tr> <tr><td>Claude Code</td><td><code>durable-harness/claude-code</code></td><td>Лише Vercel Sandbox</td><td class="n">Експериментальний</td></tr> <tr><td>Codex</td><td><code>durable-harness/codex</code></td><td>Лише Vercel Sandbox</td><td class="n">Експериментальний</td></tr> </table> <p class="note">Claude Code і Codex — однокористувацькі CLI, які зберігають стан на диску, тому кожна сесія отримує власний Sandbox.</p> </div> <div class="ft"><span>Джерело: vercel.com/blog/making-every-harness-durable · документація Vercel · жовтень 2026</span><b>© Marktechpost</b></div> </div> <script> (function(){ var R=document.getElementById('mtp-dh'); function $(s){return R.querySelector(s)}function $$(s){return R.querySelectorAll(s)} function rz(){try{parent.postMessage({mtpEmbedHeight:R.offsetHeight+40,id:'mtp-dh'},'*')}catch(e){}} $$('.tab').forEach(function(t){t.onclick=function(){$$('.tab').forEach(function(x){x.classList.remove('on')});$$('.pane').forEach(function(x){x.classList.remove('on')});t.classList.add('on');$('#'+t.dataset.t).classList.add('on');if(t.dataset.t==='p3')ws(cur);setTimeout(rz,60)}}); var S=[['model','Спланувати зміну',1],['read','app/page.tsx',0],['write','app/pricing/page.tsx',0],['run','gh pr create',0],['wait','Перевірки CI для PR',0],['model','Відповісти результатом',1]]; function draw(id){var o=$(id);o.innerHTML='';S.forEach(function(s){var li=document.createElement('li');li.innerHTML='<span class="k">'+s[0]+'</span>'+s[1];o.appendChild(li)})} var i=0,tm=null,killed=false,ma=0,mb=0; function log(t,c){var l=$('#lg'),d=document.createElement('div');d.className=c||'';d.textContent=t;l.appendChild(d);while(l.children.length>6)l.removeChild(l.firstChild)} function reset(){clearTimeout(tm);i=0;killed=false;ma=mb=0;draw('#sA');draw('#sB');$('#aRe').textContent=0;$('#bRe').textContent=0;$('#aMc').textContent=0;$('#bMc').textContent=0;$('#go').disabled=false;$('#kill').disabled=true;$('#lg').innerHTML='<div>Натисніть «Запустити крок», а потім завершіть роботу функції під час виконання CI.</div>'} function li(id,n){return $(id).children[n]} function step(){if(i>=S.length){$('#kill').disabled=true;log('крок завершено','o');return} ['#sA','#sB'].forEach(function(id){var e=li(id,i);e.className='run'}); log('намір '+S[i][0]+' '+S[i][1],'i'); tm=setTimeout(function(){['#sA','#sB'].forEach(function(id){li(id,i).className='done'});if(S[i][2]){ma++;mb++;$('#aMc').textContent=ma;$('#bMc').textContent=mb}log('результат '+S[i][0]+' успішно','o');i++;step()},i===4?1800:700)} $('#go').onclick=function(){reset();$('#go').disabled=true;$('#kill').disabled=false;$('#lg').innerHTML='';step()}; $('#rst').onclick=reset; $('#kill').onclick=function(){if(i>=S.length)return;clearTimeout(tm);killed=true;$('#kill').disabled=true;var k=i; li('#sA',k).className='dead';li('#sB',k).className='dead';log('функція 1 завершилася на кроці '+(k+1),'x'); setTimeout(function(){log('без надійного виконання: ручний перезапуск, крок починається спочатку','x'); draw('#sA');var re=0,j=0;(function a(){if(j>=S.length){$('#aRe').textContent=re;return}var e=li('#sA',j);e.className='run';setTimeout(function(){e.className=j<k?'rerun':'done';if(j<k){re++;$('#aRe').textContent=re}if(S[j][2]){ma++;$('#aMc').textContent=ma}j++;a()},260)})(); log('із durable-harness: черга передає крок функції 2','o'); for(var q=0;q<k;q++)li('#sB',q).className='fromlog'; i=k;(function b(){if(i>=S.length){log('крок завершено, повторено 0 кроків','o');return}var e=li('#sB',i);e.className='run';setTimeout(function(){e.className='done';if(S[i][2]){mb++;$('#bMc').textContent=mb}i++;b()},450)})(); },600)}; reset(); var rule='safe'; $$('.tool').forEach(function(t){t.onclick=function(){$$('.tool').forEach(function(x){x.classList.remove('sel')});t.classList.add('sel');rule=t.dataset.r;$('#vd').textContent='Оберіть інструмент і натисніть «Завершити під час виклику».';$('#code').textContent=rule==='safe'?"{ name: 'get_order', replay: 'safe', ... }":"{ name: 'refund_order', replay: 'never', ... }"}}); $('#crash').onclick=function(){var v=$('#vd');v.style.opacity=0;setTimeout(function(){v.innerHTML=rule==='safe'?'<b style="color:#50e3c2">Відновлено:</b> перерваний пошуковий запит можна запустити знову. Pi запускає його повторно; Claude Code, Codex і OpenCode повідомляють моделі, що повторення безпечне.':'<b style="color:#f5a623">Не запускати повторно:</b> моделі повідомляють, що повернення коштів могло або не могло відбутися, тому спочатку можна виконати перевірку. Кожна harness-система очікує, поки журнал зафіксує виклик \'never\', перш ніж почати.';v.style.transition='opacity .3s';v.style.opacity=1;rz()},150)}; var W=[{t:'Короткі завдання та невеликі робочі простори',f:['Файли зберігаються','У журналі сесії'],m:[['Розмір робочого простору','близько 500 файлів',55]],x:'Збій під час виклику не залишає нічого після себе, і виклик запускається знову. Вартість: процесорний час функції, події журналу та сховище.'}, {t:'Тимчасова робота протягом одного кроку',f:['Файли зберігаються','Видаляються після кожного кроку'],m:[['Збереження','відсутнє між кроками',8]],x:'Нічого не записується в журнал. Модель отримує повідомлення, що файли видаляються. Вартість: лише процесорний час функції.'}, {t:'Реальні проєкти та довготривала робота',f:['Файли зберігаються','На Drive, який переживає кожен Sandbox'],m:[['Ізоляція','1 Sandbox на сесію',100]],x:'Команда, виконання якої перервав збій, могла частково виконатися, і модель отримує відповідне повідомлення. Вартість: використання Sandbox і Drive, а також запуск під час першого використання.'}]; var cur=0;function ws(n){cur=n;var w=W[n];$('#wsd').innerHTML='<h4>Найкраще для: '+w.t+'</h4><div class="note">'+w.f[0]+': <b style="color:#fff">'+w.f[1]+'</b></div>'+w.m.map(function(m){return '<div class="meter"><i></i></div><div class="ml"><span>'+m[0]+'</span><span>'+m[1]+'</span></div>'}).join('')+'<p class="note">'+w.x+' Типізовані JSON-документи також зберігаються в журналі — до 64 КБ кожен.</p>';setTimeout(function(){$$('#wsd .meter i').forEach(function(e){e.style.width=w.m[0][2]+'%'});rz()},40)} $$('.ws .box').forEach(function(b){b.onclick=function(){$$('.ws .box').forEach(function(x){x.classList.remove('sel')});b.classList.add('sel');ws(+b.dataset.w)}});ws(0); var G=[["// На Vercel: @workflow/world-vercel обирається автоматично\nimport { claudeCode } from 'durable-harness/claude-code'\nexport const agent = claudeCode({ model: 'anthropic/claude-sonnet-5.5' })",'Сесії відображаються в Agent Runs разом із кожним викликом моделі та інструмента. Відновлені кроки з’являються в тому самому трасуванні.'], ["# Локальна розробка: @workflow/world-local, без конфігурації\n# сесії за замовчуванням зберігаються в .workflow-data\nnpm install durable-harness",'Локальний World підходить для розробки та одного сервера зі сталим диском.'], ["# Власний сервер: 2 змінні переносять кожного агента до Postgres\nWORKFLOW_TARGET_WORLD=\"@workflow/world-postgres\"\nWORKFLOW_POSTGRES_URL=\"postgres://user:password@host:5432/database\"",'Потребує @workflow/world-postgres 5.0.4+ і Node.js 22+. Це еталонна реалізація: без автентифікації маршрутів, шифрування та оптимізації для масштабування.']]; function wd(n){$('#wc').textContent=G[n][0];$('#wn').textContent=G[n][1];rz()} $$('.world').forEach(function(b){b.onclick=function(){$$('.world').forEach(function(x){x.classList.remove('sel')});b.classList.add('sel');wd(+b.dataset.g)}});wd(0); window.addEventListener('load',rz);window.addEventListener('resize',rz);setTimeout(rz,300); })(); </script> </body></html> ">

Де можна запустити durable-harness?

Код агента залишається однаковим у різних Worlds:

  • Vercel: Vercel World, де кожна сесія відстежується в Agent Runs.
  • Локально: файли на вашому комп’ютері, без конфігурації.
  • На власному сервері: Postgres World версії 5.0.4 або новішої на Node.js 22+. У блозі Vercel також згадуються MongoDB, Redis і Turso.

2 змінні середовища — WORKFLOW_TARGET_WORLD і WORKFLOW_POSTGRES_URL — переносять агента до Postgres.

Як durable-harness порівнюється з іншими рішеннями?

Функціяdurable-harnessTemporal + OpenAI Agents SDKInngest AgentKitCloudflare Agents SDK
Що цеАдаптери надійного виконання для наявних harness-систем програмуванняОбгортка надійного виконання для OpenAI Agents SDKTypeScript-фреймворк для мультиагентних системАгенти зі збереженням стану на Durable Objects
Обгортає Claude Code / CodexТак, експериментально, лише SandboxНе розкритоНе розкритоНе розкрито
Бекенд надійного виконанняWorkflow SDK World (Vercel, локальний, Postgres)Сервер Temporal або Temporal CloudОркестраційний рушій InngestDurable Objects, Cloudflare Workflows
МоваTypeScriptPythonTypeScriptTypeScript
ЛіцензіяApache-2.0MIT (сервер)Apache-2.0MIT
Статус0.0.x, експериментальнийGA з 23 березня 2026 рокуНе розкритоНе розкрито

Ключові висновки

  • durable-harness записує кожен виклик моделі та інструмента, а потім відновлює перервані кроки на новій функції.
  • Завершені виклики ніколи не повторюються, тому за токени не стягується плата двічі.
  • Pi і OpenCode працюють у вашій функції; Claude Code і Codex потребують Vercel Sandbox.
  • Самостійне розгортання працює з 2 змінними середовища та Postgres World.
  • Це експериментальна версія 0.0.x без опублікованих бенчмарків.

Перегляньте репозиторій GitHub, документацію та анонс Vercel. Усі заслуги належать досліднику цього проєкту. Також підписуйтеся на нас у Twitter і не забудьте приєднатися до нашого сабреддіту про машинне навчання з понад 150 тисячами учасників та підписатися на нашу розсилку. Стривайте! Ви користуєтеся Telegram? тепер ви також можете приєднатися до нас у Telegram.

Перекладено автоматично з англійської. Оригінал статті — за посиланням нижче.

Вперше опубліковано виданням MarkTechPost

Читати оригінал на MarkTechPost ↗

Текст і зображення належать MarkTechPost і наводяться тут із зазначенням авторства та посиланням на оригінальну публікацію.

← До новин

Ще новини

Усі останні новини