eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 3.12 kB
JavaScript
import{createEveMessageStreamRoutePath}from"#protocol/routes.js";import{ClientError}from"#client/client-error.js";import{createClientUrl}from"#client/url.js";import{isStreamDisconnectError,readNdjsonStream}from"#client/ndjson.js";const DEFAULT_STREAM_RECONNECT_POLICY={retryableErrorStatuses:new Set([404,409,425,500,502,503,504]),streamIdleReconnectPolicy:{baseDelayMs:250,maxAttempts:5,maxDelayMs:4e3},streamOpenReconnectPolicy:{baseDelayMs:250,maxAttempts:12,maxDelayMs:5e3}},NO_STREAM_RECONNECT_POLICY={...DEFAULT_STREAM_RECONNECT_POLICY,streamIdleReconnectPolicy:{...DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy,maxAttempts:0},streamOpenReconnectPolicy:{...DEFAULT_STREAM_RECONNECT_POLICY.streamOpenReconnectPolicy,maxAttempts:1}};function resolveRetryPolicy(e,t){return{...t,...e}}function resolveStreamReconnectPolicy(e){if(e&&`reconnect`in e&&e.reconnect===!1)return NO_STREAM_RECONNECT_POLICY;let t=e;return{retryableErrorStatuses:t?.retryableErrorStatuses?new Set(t.retryableErrorStatuses):DEFAULT_STREAM_RECONNECT_POLICY.retryableErrorStatuses,streamIdleReconnectPolicy:resolveRetryPolicy(t?.streamIdleReconnectPolicy,DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy),streamOpenReconnectPolicy:resolveRetryPolicy(t?.streamOpenReconnectPolicy,DEFAULT_STREAM_RECONNECT_POLICY.streamOpenReconnectPolicy)}}async function*followStreamIterable(e){let t=resolveStreamReconnectPolicy(e.streamReconnectPolicy),n=t.streamIdleReconnectPolicy,a=e.startIndex,o=n.baseDelayMs,s=0,c=!0;for(;;){let l;try{l=await openStreamBody({...e,retryPolicy:t,startIndex:a})}catch(t){if(e.signal?.aborted)return;throw t}let u=!1;try{for await(let e of readNdjsonStream(l))a+=1,u=!0,o=n.baseDelayMs,s=0,yield e}catch(e){if(!isStreamDisconnectError(e))throw e}if(e.signal?.aborted||e.startIndex<0||n.maxAttempts===0||!u&&!c&&(s+=1)>=n.maxAttempts||(c=!1,await sleep(o,e.signal),e.signal?.aborted))return;o=Math.min(o*2,n.maxDelayMs)}}async function openStreamBody(i){let o=i.retryPolicy??DEFAULT_STREAM_RECONNECT_POLICY,s=o.streamOpenReconnectPolicy,c,l,u,d=s.baseDelayMs;for(let a=0;a<s.maxAttempts;a+=1){let f=createClientUrl(i.host,createEveMessageStreamRoutePath(i.sessionId),i.startIndex===0?void 0:{startIndex:String(i.startIndex)}),p=await i.resolveHeaders(),m;try{m=await fetch(f,{headers:p,redirect:i.redirect,signal:i.signal??null})}catch(e){if(i.signal?.aborted||!isStreamDisconnectError(e)||a===s.maxAttempts-1)throw e;await sleep(d,i.signal),d=Math.min(d*2,s.maxDelayMs);continue}if(m.ok){if(!m.body)throw new ClientError(m.status,`Response body is null.`,m.headers);return m.body}if(c=m.status,l=await m.text(),u=m.headers,!o.retryableErrorStatuses.has(m.status))throw new ClientError(m.status,l,m.headers);a<s.maxAttempts-1&&(await sleep(d,i.signal),d=Math.min(d*2,s.maxDelayMs))}throw new ClientError(c??0,l??`Failed to open message stream.`,u)}async function sleep(e,t){t?.aborted||await new Promise(n=>{let onAbort=()=>{clearTimeout(r),n()},r=setTimeout(()=>{t?.removeEventListener(`abort`,onAbort),n()},e);t?.addEventListener(`abort`,onAbort,{once:!0})})}export{followStreamIterable,openStreamBody};