eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 6.3 kB
JavaScript
import{normalizeChannelAudience}from"#shared/channel-audience.js";import{AGENT_SPAN_NAMES,workflowInvocationSpanName}from"#tracing/agent-span-contract.js";import{isSampledTrace}from"#tracing/sampled-trace.js";import{ROOT_CONTEXT,SpanKind,trace}from"#compiled/@opentelemetry/api/index.js";import{actionIdempotencyKey,attemptIdempotencyKey}from"#instrumentation/lifecycle.js";import{agentSpanNamingAttributes}from"#tracing/agent-span-naming.js";import{agentTraceIdentityAttributes}from"#tracing/agent-otel-attributes.js";import{contentAttribute,textContentAttribute}from"#tracing/agent-otel-content.js";import{setAgentUsage}from"#tracing/agent-otel-usage.js";import{withChannelAudience}from"#tracing/channel-audience-context.js";import{recordAgentSpanError}from"#tracing/agent-span-error.js";function createAgentActionInstrumentation(e){let t=new Map,onStarted=async n=>{let r=await e.resolveTraceContext(n);if(r===void 0||!isSampledTrace(r))return;let i=await e.stateStore.getAction(n.idempotencyKey)??{attemptIndex:n.scope.attemptIndex,callId:n.callId,channelAudience:normalizeChannelAudience(n.scope.channelAudience),inputAttribute:e.recordInputs?contentAttribute(n.input):void 0,isWorkflowTool:n.isWorkflowTool===!0,kind:n.kind,name:n.name,parent:{spanId:e.idGenerator.deriveSpanId(attemptIdempotencyKey(n.scope)),traceFlags:r.traceFlags,traceId:r.traceId},rootSessionId:n.scope.rootSessionId??n.scope.sessionId,sessionId:n.scope.sessionId,spanId:e.idGenerator.deriveSpanId(`action:${n.idempotencyKey}`),startTimeMs:Date.now(),stepIndex:n.scope.stepIndex,turnId:n.scope.turnId};await e.stateStore.setAction(n.idempotencyKey,i),n.isWorkflowTool===!0&&await e.stateStore.setActionAnchor(n.idempotencyKey,i);let a=t.get(n.scope.attemptId)??new Set;a.add(n.idempotencyKey),t.set(n.scope.attemptId,a)},onTerminal=async t=>{let n=await e.stateStore.getAction(t.idempotencyKey);if(n!==void 0)try{finishActionSpan(n,t)}finally{await e.stateStore.deleteAction(t.idempotencyKey),forget(t.idempotencyKey)}},startSpan=t=>{let n=isAgentInvocation(t.kind),r=t.kind===`tool-call`?t.workflowName:void 0,i=r===void 0?AGENT_SPAN_NAMES.action:workflowInvocationSpanName(r),a=e.idGenerator.withSpanId(t.spanId,()=>e.tracer.startSpan(AGENT_SPAN_NAMES.action,{attributes:{"agent.action.call_id":t.callId,"agent.action.kind":t.kind,"agent.action.name":t.name,"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.step.attempt":t.attemptIndex,"agent.step.index":t.stepIndex,"agent.turn.id":t.turnId,...agentSpanNamingAttributes(i,r===void 0?void 0:`invoke_workflow`),...agentTraceIdentityAttributes({rootSessionId:t.rootSessionId,sessionId:t.sessionId}),...r===void 0?void 0:{"gen_ai.operation.name":`invoke_workflow`,"gen_ai.workflow.name":r},...n?{"gen_ai.agent.name":t.name,"agent.invocation.role":`caller`}:void 0},kind:t.kind===`remote-agent-call`?SpanKind.CLIENT:SpanKind.INTERNAL,startTime:t.startTimeMs},contextFromActionState(t)));return r!==void 0&&updateSpanName(a,i),!n&&t.inputAttribute!==void 0&&a.setAttribute(`gen_ai.tool.call.arguments`,t.inputAttribute),a};return{async contextFor(t,n,r){let i=actionIdempotencyKey(t,n,r),a=await e.stateStore.getAction(i);if(a!==void 0)return actionContext(a);let o=await e.stateStore.findAction(t,r);return o===void 0?void 0:actionContext(o)},async deleteForSession(t){await e.stateStore.deleteActions(t),await e.stateStore.deleteActionAnchors(t),await e.stateStore.deleteInvocations(t)},async failForAttempt(n,r){let i=t.get(n.attemptId);if(i!==void 0){t.delete(n.attemptId);for(let t of i){let n=await e.stateStore.getAction(t);if(n===void 0)continue;let i=startSpan(n);recordAgentSpanError(i,r),i.end(),await e.stateStore.deleteAction(t)}}},flushSettledInvocations:()=>flushInvocations(),async flushForSessionTransition(e){let t=e.type===`session.completed`?{outcome:`abandoned`}:e.type===`session.failed`?{error:e.error,outcome:`failed`}:void 0;await flushInvocations(e.sessionId,t)},events:{"action.completed":onTerminal,"action.failed":onTerminal,"action.started":onStarted}};async function flushInvocations(t,n){for(let r of await e.stateStore.findInvocations(t)){let t=r.terminal??n;t!==void 0&&(finishInvocationSpan(r,t),await e.stateStore.deleteInvocation(actionIdempotencyKey(r.sessionId,r.turnId,r.callId)))}}function forget(e){for(let[n,r]of t)r.delete(e),r.size===0&&t.delete(n)}function finishActionSpan(t,n){let r=startSpan(t);if(r.setAttribute(`agent.action.outcome`,n.outcome),n.type===`action.failed`)n.errorCode!==void 0&&r.setAttribute(`agent.action.error.code`,n.errorCode),recordActionError(r,n.error,n.errorCode);else if(n.output.type===`error`)recordActionError(r,n.output.error);else if(n.usage!==void 0&&setAgentUsage(r,n.usage),e.recordOutputs&&!isAgentInvocation(t.kind)){let e=contentAttribute(n.output.output);e!==void 0&&r.setAttribute(`gen_ai.tool.call.result`,e)}r.end(n.acceptedAtMs)}function finishInvocationSpan(t,n){let r=startSpan(t);r.setAttribute(`agent.action.outcome`,n.outcome),n.usage!==void 0&&setAgentUsage(r,n.usage),n.outcome===`failed`&&recordAgentSpanError(r,e.recordOutputs&&t.recordOutputs===!0?n.error:void 0),r.end(n.acceptedAtMs)}}function actionContext(e){let t={isRemote:!1,spanId:e.spanId,traceFlags:e.parent.traceFlags,traceId:e.parent.traceId};return{context:withChannelAudience(trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(t)),e.channelAudience),spanContext:t}}function contextFromActionState(e){return withChannelAudience(trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext({...e.parent,isRemote:!1})),e.channelAudience)}function isAgentInvocation(e){return e===`subagent-call`||e===`remote-agent-call`}function updateSpanName(e,t){let n=Reflect.get(e,`updateName`);typeof n==`function`&&Reflect.apply(n,e,[t])}function recordActionError(e,t,n){if(t instanceof Error||t===void 0){recordAgentSpanError(e,t,n);return}let r=serializedErrorDetail(t);if(r===void 0){recordAgentSpanError(e,void 0,n);return}let i=Error(r);n!==void 0&&(i.name=n),recordAgentSpanError(e,i,n)}function serializedErrorDetail(e){if(typeof e==`string`)return textContentAttribute(e);let t=contentAttribute(e);if(typeof e!=`object`||!e||Array.isArray(e))return t;let n=Reflect.get(e,`message`);return typeof n==`string`?textContentAttribute(t===void 0?n:`${n}\n${t}`):t}export{createAgentActionInstrumentation};