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.
Къде се изпълняват файловете и shell командите?
Командите, избрани от модела, никога не се изпълняват на собствения диск на функцията. Документацията за инструментите посочва 3 опции за работно пространство:
virtual() съхранява файловете в лога на сесията, с shell, съвместим с bash, и без мрежа. Поддържа около 500 файла.
virtual({ durable: false }) съхранява временните файлове в паметта и ги изчиства при всеки ход.
sandbox() предоставя на всяка сесия Vercel Sandbox , с /workspace на Drive.
Типизираните JSON документи , като списък със задачи, също се съхраняват в лога. Всеки от тях е с максимален размер 64 KB.
Стартирай ход</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">Файлове в лога на сесията. Shell, съвместим с 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 + проследяване на изпълненията на агента</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]+' ok','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 KB всеки.</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-harness Temporal + OpenAI Agents SDK Inngest AgentKit Cloudflare Agents SDK Какво представлява Адаптери за устойчивост за съществуващи кодиращи harness-и Обвивка за устойчиво изпълнение на OpenAI Agents SDK TypeScript framework за множество агенти Агенти със състояние върху Durable Objects Обвива Claude Code / Codex Да, експериментално, само в Sandbox Не е оповестено Не е оповестено Не е оповестено Backend за устойчивост Workflow SDK World (Vercel, локално, Postgres) Temporal сървър или Temporal Cloud Механизъм за оркестрация Inngest Durable Objects, Cloudflare Workflows Език TypeScript Python TypeScript TypeScript Лиценз Apache-2.0 MIT (сървър) Apache-2.0 MIT Статус 0.0.x, експериментален GA от 23 март 2026 г. Не е оповестено Не е оповестено
Основни изводи
durable-harness записва всяка заявка към модела и инструментите, след което възобновява прекъснатите ходове в нова функция.
Завършените заявки никога не се повтарят, така че токените не се таксуват два пъти.
Pi и OpenCode работят във вашата функция; Claude Code и Codex изискват Vercel Sandbox.
Самостоятелното хостване работи с 2 променливи на средата и Postgres World.
Версията е 0.0.x и експериментална, без публикувани бенчмаркове.
Разгледайте хранилището в GitHub , документацията и съобщението на Vercel . Всички заслуги са за изследователя на този проект. Също така можете да ни последвате в Twitter и не забравяйте да се присъедините към нашия ML SubReddit с над 150 хил. членове и да се абонирате за нашия бюлетин . Чакайте! В Telegram ли сте? Вече можете да се присъедините към нас и в Telegram.
Преведено автоматично от английски. Оригиналната статия е на връзката по-долу.