eve 0.79.1 → 0.80.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/src/channel/pending-authorization.d.ts +10 -0
- package/dist/src/channel/pending-authorization.js +1 -0
- package/dist/src/compiled/.vendor-stamp.json +7 -7
- package/dist/src/compiled/@chat-adapter/slack/api.d.ts +6 -0
- package/dist/src/compiled/@chat-adapter/slack/api.js +1 -1
- package/dist/src/compiled/@chat-adapter/slack/blocks.js +1 -1
- package/dist/src/compiled/@chat-adapter/slack/format.js +1 -1
- package/dist/src/compiled/@chat-adapter/slack/index.d.ts +14 -8
- package/dist/src/compiled/@chat-adapter/slack/index.js +33 -32
- package/dist/src/compiled/@chat-adapter/twilio/index.d.ts +37 -1
- package/dist/src/compiled/@chat-adapter/twilio/index.js +2 -2
- package/dist/src/compiled/@eve/tracing/index.js +1 -1
- package/dist/src/compiled/@eve/tracing/otel.js +1 -1
- package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.js +1 -1
- package/dist/src/compiled/@photon-ai/chat-adapter-imessage/index.js +1 -1
- package/dist/src/compiled/@vercel/connect/index.js +5 -5
- package/dist/src/compiled/@vercel/connect/token.d.ts +11 -1
- package/dist/src/compiled/_chunks/node/chunk-NBSLXVG3-Bt7pDfyn.js +12 -0
- package/dist/src/compiled/_chunks/node/dist-BKsV21Vu.js +6 -0
- package/dist/src/compiled/_chunks/node/dist-CO_n_hUa.js +98 -0
- package/dist/src/compiled/_chunks/workflow/{mcp-C01bDEX-.js → mcp-Bwx_LQ4q.js} +4 -4
- package/dist/src/compiled/chat/index.js +1 -1
- package/dist/src/compiler/extension-compatibility.d.ts +18 -18
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.d.ts +8 -4
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-connection.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/context/schedule-collection-tools.js +1 -1
- package/dist/src/execution/catalog/connection-auth.d.ts +4 -2
- package/dist/src/execution/catalog/connection-auth.js +1 -1
- package/dist/src/execution/catalog/connection-entry.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/proxied-deliver-step.js +1 -1
- package/dist/src/execution/publish-session-events.d.ts +13 -3
- package/dist/src/execution/publish-session-events.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
- package/dist/src/execution/session/active-turn.d.ts +2 -1
- package/dist/src/execution/session/active-turn.js +1 -1
- package/dist/src/execution/session/entry.js +1 -1
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session/turn.d.ts +1 -0
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/session-event-stream.js +1 -1
- package/dist/src/execution/stable-workflow-names.d.ts +2 -0
- package/dist/src/execution/stable-workflow-names.js +1 -1
- package/dist/src/execution/tasks/task-id-input.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/workflow/apply-run-messages-step.d.ts +6 -2
- package/dist/src/execution/tools/workflow/apply-run-messages-step.js +1 -1
- package/dist/src/execution/tools/workflow/body.d.ts +10 -1
- package/dist/src/execution/tools/workflow/body.js +1 -1
- package/dist/src/execution/tools/workflow/owner-inbox.js +1 -1
- package/dist/src/execution/tools/workflow/serve.js +1 -1
- package/dist/src/execution/web-fetch/execute.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +6 -0
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/extensions/git/extension/extension.d.ts +3 -1
- package/dist/src/extensions/git/extension/extension.js +1 -1
- package/dist/src/extensions/git/extension/lib/gh-tool.js +1 -1
- package/dist/src/extensions/git/extension/lib/github-shell.d.ts +14 -0
- package/dist/src/extensions/git/extension/lib/github-shell.js +1 -1
- package/dist/src/harness/action-result-helpers.js +1 -1
- package/dist/src/harness/attachment-staging.js +1 -1
- package/dist/src/harness/compaction/engine.js +3 -1
- package/dist/src/harness/compaction/prompt.d.ts +7 -0
- package/dist/src/harness/compaction/prompt.js +1 -1
- package/dist/src/harness/hitl/approvals.js +1 -1
- package/dist/src/harness/hitl/approved-calls.js +1 -1
- package/dist/src/harness/input-request-resolution.d.ts +2 -1
- package/dist/src/harness/input-request-resolution.js +1 -1
- package/dist/src/harness/model-call/call.js +1 -1
- package/dist/src/harness/model-call/errors.d.ts +2 -2
- package/dist/src/harness/model-call/recovery.d.ts +2 -3
- package/dist/src/instrumentation/native-events.js +1 -1
- package/dist/src/instrumentation/session-init.d.ts +2 -1
- package/dist/src/instrumentation/session-init.js +1 -1
- package/dist/src/internal/application/optional-package-import.d.ts +5 -0
- package/dist/src/internal/application/optional-package-import.js +1 -1
- package/dist/src/internal/application/stamped-package-version.js +1 -1
- package/dist/src/internal/authored-definition/connection.js +1 -1
- package/dist/src/internal/authored-definition/schedule-collection.js +1 -1
- package/dist/src/internal/nitro/host/application-route-registry.d.ts +7 -2
- package/dist/src/internal/nitro/host/application-route-registry.js +1 -1
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +1 -1
- package/dist/src/internal/nitro/host/start-production-server.js +2 -2
- package/dist/src/internal/nitro/routes/channel-request-instrumentation.d.ts +3 -1
- package/dist/src/internal/nitro/routes/channel-request-instrumentation.js +1 -1
- package/dist/src/internal/nitro/routes/connection-events.d.ts +5 -0
- package/dist/src/internal/nitro/routes/connection-events.js +1 -0
- package/dist/src/internal/workflow-bundle/builder.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.js +1 -1
- package/dist/src/protocol/message.d.ts +2 -0
- package/dist/src/protocol/message.js +1 -1
- package/dist/src/public/channels/slack/blocks.js +2 -2
- package/dist/src/public/channels/teams/authorization.d.ts +53 -0
- package/dist/src/public/channels/teams/authorization.js +1 -0
- package/dist/src/public/channels/teams/defaults.js +2 -2
- package/dist/src/public/channels/teams/hitl.d.ts +2 -1
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/telegram/authorization-callback.js +1 -1
- package/dist/src/public/connections/index.d.ts +1 -0
- package/dist/src/public/definitions/connections/events.d.ts +43 -0
- package/dist/src/public/definitions/connections/events.js +1 -0
- package/dist/src/public/definitions/connections/mcp.d.ts +3 -0
- package/dist/src/public/next/index.js +1 -1
- package/dist/src/public/next/server.d.ts +11 -2
- package/dist/src/public/next/server.js +1 -1
- package/dist/src/public/schedules/subscription.d.ts +4 -3
- package/dist/src/runtime/connections/events/actions.d.ts +17 -0
- package/dist/src/runtime/connections/events/actions.js +1 -0
- package/dist/src/runtime/connections/events/delivery.d.ts +10 -0
- package/dist/src/runtime/connections/events/delivery.js +1 -0
- package/dist/src/runtime/connections/events/dispatch-step.d.ts +20 -0
- package/dist/src/runtime/connections/events/dispatch-step.js +1 -0
- package/dist/src/runtime/connections/events/lifecycle-step.d.ts +42 -0
- package/dist/src/runtime/connections/events/lifecycle-step.js +1 -0
- package/dist/src/runtime/connections/events/owner.d.ts +38 -0
- package/dist/src/runtime/connections/events/owner.js +1 -0
- package/dist/src/runtime/connections/events/path.d.ts +4 -0
- package/dist/src/runtime/connections/events/path.js +1 -0
- package/dist/src/runtime/connections/events/state.d.ts +37 -0
- package/dist/src/runtime/connections/events/state.js +1 -0
- package/dist/src/runtime/connections/events/workflow.d.ts +28 -0
- package/dist/src/runtime/connections/events/workflow.js +1 -0
- package/dist/src/runtime/connections/mcp-client.d.ts +4 -2
- package/dist/src/runtime/connections/mcp-client.js +1 -1
- package/dist/src/runtime/connections/openapi-client.js +1 -1
- package/dist/src/runtime/connections/scoped-authorization.js +1 -1
- package/dist/src/runtime/resolve-connection.js +1 -1
- package/dist/src/runtime/schedules/collection-client.d.ts +0 -2
- package/dist/src/runtime/schedules/collection-client.js +1 -1
- package/dist/src/runtime/types.d.ts +11 -0
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +2 -2
- package/dist/src/setup/scaffold/update/channels.js +1 -1
- package/dist/src/setup/scaffold/update/connections.js +2 -2
- package/dist/src/setup/scaffold/version-tokens.d.ts +1 -1
- package/dist/src/setup/scaffold/version-tokens.js +1 -1
- package/dist/src/shared/action-types.d.ts +1 -0
- package/dist/src/shared/action-types.js +1 -1
- package/dist/src/shared/agent-definition.d.ts +12 -4
- package/dist/src/shared/connection-events.d.ts +84 -0
- package/dist/src/shared/connection-events.js +1 -0
- package/dist/src/shared/connection-types.d.ts +10 -0
- package/dist/src/shared/validate-authorization.js +1 -1
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/no-reply.d.ts +5 -0
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/dist/src/tools/signature.d.ts +4 -2
- package/dist/src/tools/signature.js +1 -1
- package/dist/src/tracing/eve/connection-events.d.ts +25 -0
- package/dist/src/tracing/eve/connection-events.js +1 -0
- package/dist/src/tracing/eve/install-instrumentation-runtime.js +1 -1
- package/dist/src/tracing/eve/mcp.d.ts +1 -0
- package/dist/src/tracing/eve/mcp.js +1 -1
- package/dist/src/tracing/eve/otel-declaration.d.ts +5 -0
- package/docs/agent-config.md +38 -13
- package/docs/channels/teams.mdx +6 -0
- package/docs/code-extension.mdx +28 -0
- package/docs/concepts/built-in-tools.md +3 -1
- package/docs/connections/mcp.mdx +105 -0
- package/docs/guides/hooks.md +4 -0
- package/docs/guides/instrumentation/instrumentation.mdx +2 -0
- package/docs/guides/instrumentation/otel.mdx +10 -0
- package/docs/sandbox/vercel.mdx +46 -0
- package/package.json +7 -7
- package/dist/src/compiled/_chunks/node/chunk-6QHBXN7B-gl4n6nmi.js +0 -12
- package/dist/src/compiled/_chunks/node/dist-DYDVZ-FS.js +0 -98
- package/dist/src/compiled/_chunks/node/dist-iEFkK9qw.js +0 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,formatError}from"#internal/logging.js";import{contextStorage}from"#context/container.js";import{ConversationIdKey}from"#context/keys.js";import{resolveInstrumentationEnvironment}from"#internal/application/dev-environment.js";import{readConversationId}from"#shared/conversation-identity.js";import{ContextAgentTraceStateStore}from"#tracing/eve/agent-trace-context-store.js";import{registerInstrumentationRuntime}from"#instrumentation/runtime.js";import{createInstrumentationHooks}from"#instrumentation/lifecycle.js";import{AgentSpanIdGenerator,otelTelemetry}from"#compiled/@eve/tracing/index.js";import{hasConversationRelease}from"#tracing/local/traces.js";import{
|
|
1
|
+
import{createLogger,formatError}from"#internal/logging.js";import{contextStorage}from"#context/container.js";import{ConversationIdKey}from"#context/keys.js";import{resolveInstrumentationEnvironment}from"#internal/application/dev-environment.js";import{readConversationId}from"#shared/conversation-identity.js";import{ContextAgentTraceStateStore}from"#tracing/eve/agent-trace-context-store.js";import{registerInstrumentationRuntime}from"#instrumentation/runtime.js";import{createInstrumentationHooks}from"#instrumentation/lifecycle.js";import{AgentSpanIdGenerator,otelTelemetry}from"#compiled/@eve/tracing/index.js";import{hasConversationRelease}from"#tracing/local/traces.js";import{eveOutputMapping}from"#tracing/eve/profile.js";import{createAgentOtelInstrumentation}from"#tracing/eve/agent-otel-provider.js";import{registerOtel}from"#tracing/eve/otel-registration.js";const log=createLogger(`tracing.install-instrumentation-runtime`);function installInstrumentationRuntime(e){let t=[],n=[],r,i,a,runInContext=(e,t)=>t(),o;if(e.collected.declared){r=registerOtel({serviceName:e.serviceName,otel:e.collected.configuration}),o=r.idGenerator;let s=createAgentOtelInstrumentation({environment:resolveInstrumentationEnvironment(),frameworkVersion:e.frameworkVersion,telemetry:otelTelemetry({provider:r.provider,tracerName:`eve.agent`,tracerVersion:e.frameworkVersion,idGenerator:o,samplesTrace:r.samplesTrace,mapping:eveOutputMapping()}),idGenerator:o,recordInputs:e.collected.settings.recordInputs,recordOutputs:e.collected.settings.recordOutputs,stateStore:new ContextAgentTraceStateStore,tracePolicy:e.collected.settings.tracePolicy});t.push({...s.hook,stateNamespace:`internal:otel`}),i=s.prepareSessionTrace,a=s.prepareTurnTrace,runInContext=s.runInContext;let c=e.collected.configuration.spanProcessors.filter(isSpanProcessor).filter(hasConversationRelease);c.length>0&&n.push(sessionReleaseProvider(c))}else o=new AgentSpanIdGenerator;let s=[...t,...e.providers,...n],c;return registerInstrumentationRuntime({forceFlush:async()=>{await settleAll(s.map(e=>()=>e.flush?.())),await settleAll(r===void 0?[]:[r.forceFlush])},hooks:createInstrumentationHooks({parallel:e.providers,serialAfter:n,serialBefore:t}),idGenerator:o,memoryOperations:r!==void 0||e.providers.some(hasMemoryOperationHandler),otelSettings:e.collected.declared?e.collected.settings:void 0,ownsAgentSpans:r!==void 0,prepareSessionTrace:i,prepareTurnTrace:a,runtimeContextResolvers:e.runtimeContextResolvers,runInContext,samplesTrace:r?.samplesTrace,shutdown:()=>(c??=(async()=>{await settleAll(s.map(e=>()=>e.shutdown?.())),await settleAll(r===void 0?[]:[r.shutdown])})(),c)})}function hasMemoryOperationHandler(e){return e.events?.[`memory.operation.started`]!==void 0||e.events?.[`memory.operation.completed`]!==void 0||e.events?.[`memory.operation.failed`]!==void 0}function isSpanProcessor(e){return e!==`auto`}function sessionReleaseProvider(e){let release=async t=>{let n=readConversationId(contextStorage.getStore()?.get(ConversationIdKey))??t.sessionId;n===t.sessionId&&await Promise.all(e.map(e=>e.releaseConversation(n)))};return{events:{"session.completed":release,"session.failed":release},name:`eve.conversation-release`,stateNamespace:`internal:conversation-release`}}async function settleAll(e){let t=await Promise.allSettled(e.map(async e=>e()));for(let e of t)e.status===`rejected`&&log.warn(`instrumentation drain failed`,{error:formatError(e.reason)})}export{installInstrumentationRuntime};
|
|
@@ -13,6 +13,7 @@ export declare function createMcpTraceFetch(input: {
|
|
|
13
13
|
export declare const MCP_SERIALIZER: ContentSerializer;
|
|
14
14
|
export declare function createMcpTracing(): {
|
|
15
15
|
list<T>(input: {
|
|
16
|
+
readonly method?: "tools/list" | "events/list";
|
|
16
17
|
readonly connectionName: string;
|
|
17
18
|
readonly execute: () => Promise<T>;
|
|
18
19
|
readonly protocolVersion?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{eveOutputMapping}from"./profile.js";import{context,propagation,trace}from"#compiled/@opentelemetry/api/index.js";import{activeTraceOperation,contentAttribute,mcpLifecycle,truncateTelemetryText}from"#compiled/@eve/tracing/otel.js";import{otelTelemetry}from"#compiled/@eve/tracing/index.js";function isObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const MAX_MCP_TRACE_REQUEST_BYTES=1048576,MAX_MCP_TRACE_CONTEXT_BYTES=8192,utf8Encoder=new TextEncoder,traceContextSetter={set(e,t,n){e[t]=n}};function createMcpTraceFetch(e){let t=e.fetcher??((e,t)=>globalThis.fetch(e,t)),n=e.getActiveContext??(()=>context.active()),r=e.injectContext??injectOpenTelemetryTraceContext;return async(i,a)=>{let o=readJsonRpcRequest(a?.body);if(o===void 0)return await t(i,a);let s=n(),c=injectMcpTraceContext(o,s,r,e.filterCarrier),l=o.method===`tools/call`||o.method===`tools/list
|
|
1
|
+
import{eveOutputMapping}from"./profile.js";import{context,propagation,trace}from"#compiled/@opentelemetry/api/index.js";import{activeTraceOperation,contentAttribute,mcpLifecycle,truncateTelemetryText}from"#compiled/@eve/tracing/otel.js";import{otelTelemetry}from"#compiled/@eve/tracing/index.js";function isObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const MAX_MCP_TRACE_REQUEST_BYTES=1048576,MAX_MCP_TRACE_CONTEXT_BYTES=8192,utf8Encoder=new TextEncoder,traceContextSetter={set(e,t,n){e[t]=n}};function createMcpTraceFetch(e){let t=e.fetcher??((e,t)=>globalThis.fetch(e,t)),n=e.getActiveContext??(()=>context.active()),r=e.injectContext??injectOpenTelemetryTraceContext;return async(i,a)=>{let o=readJsonRpcRequest(a?.body);if(o===void 0)return await t(i,a);let s=n(),c=injectMcpTraceContext(o,s,r,e.filterCarrier),l=o.method===`tools/call`||(o.method===`tools/list`||o.method===`events/list`)&&activeTraceOperation(s)?.type===`mcp`;l&&activeTraceOperation(s)?.mcp?.update(mcpRequestMetadata({connectionName:e.connectionName,message:o,params:isObject(o.params)?o.params:{},protocolVersion:headerValue(a?.headers,`mcp-protocol-version`)??e.getProtocolVersion()}));let u=await t(i,c===void 0?a:{...a,body:JSON.stringify(c)});if(l){let e=u.headers.get(`mcp-session-id`);e!==null&&activeTraceOperation(s)?.mcp?.update({sessionId:truncateTelemetryText(e,512)})}return u}}function injectMcpTraceContext(e,t,n=injectOpenTelemetryTraceContext,r){if(!withinTraceRequestLimit(JSON.stringify(e))||e.params!==void 0&&!isObject(e.params))return;let i={};if(n(t,i),!withinTraceContextLimit(i))return;r?.(i);let a=isObject(e.params)?e.params:{},o=isObject(a._meta)?a._meta:{};return{...e,params:{...a,_meta:{...o,...i}}}}const noContent=()=>void 0,MCP_SERIALIZER={json:contentAttribute,text:noContent,inputMessages:noContent,instructions:noContent,toolDefinitions:noContent,outputMessages:noContent,toolResults:noContent};function createMcpTracing(){let e=otelTelemetry({tracerName:`eve.mcp`,mapping:eveOutputMapping()});function start(t){let n=e.startSpan({type:`mcp`,operationId:`${t.connectionName}:${t.method}`,name:t.method===`tools/call`?`tools/call ${t.toolName??`unknown`}`:t.method,kind:`CLIENT`,parent:trace.getSpan(t.executionContext)?.spanContext(),attributes:{"agent.connection.name":t.connectionName,"mcp.method.name":t.method,"network.protocol.name":`http`,"network.transport":`tcp`,"mcp.protocol.version":t.protocolVersion,"gen_ai.operation.name":t.method===`tools/call`?`execute_tool`:void 0,"gen_ai.tool.name":t.toolName}},{context:t.executionContext}),r=mcpLifecycle({serializer:MCP_SERIALIZER,...t.capture,write(e){for(let[t,r]of Object.entries(e))r!==void 0&&n.setAttribute(t,r)},error:n.fail});return{...r,end:n.end,run(i){return e.run({type:`mcp`,reference:n.reference,capture:t.capture,mcp:r},i,t.executionContext)}}}return{async list(e){let t=context.active(),n=start({method:e.method??`tools/list`,connectionName:e.connectionName,protocolVersion:e.protocolVersion,executionContext:t,capture:activeTraceOperation()?.capture??{emit:!0,recordInputs:!1,recordOutputs:!1}});try{return await n.run(async()=>{try{return await e.execute()}catch(e){let t=jsonRpcErrorCode(e);throw t!==void 0&&n.update({statusCode:t}),n.error(e,errorType(e,t)),e}})}finally{n.end()}},async call(e){let t=context.active(),n=activeTraceOperation();if(n?.type===`tool`&&n.mcp!==void 0)return n.mcp.update({...e,method:`tools/call`}),await runMcpToolCall(e,void 0);let r=start({method:`tools/call`,connectionName:e.connectionName,toolName:truncateTelemetryText(e.toolName,128),protocolVersion:e.protocolVersion,executionContext:t,capture:n?.capture??{emit:!0,recordInputs:!1,recordOutputs:!1}});try{return await r.run(()=>runMcpToolCall(e,r))}finally{r.end()}}}}function runMcpToolCall(e,t){return t!==void 0&&t.arguments(e.arguments),e.execute().then(e=>(isToolErrorResult(e)&&activeTraceOperation()?.mcp?.error(void 0,`tool_error`),t!==void 0&&t.result(e),e)).catch(e=>{let n=jsonRpcErrorCode(e);throw n!==void 0&&activeTraceOperation()?.mcp?.update({statusCode:n}),t!==void 0&&activeTraceOperation()?.mcp?.error(e,errorType(e,n)),e})}function mcpRequestMetadata(e){let t=e.method??e.message?.method,n=e.params??(isObject(e.message?.params)?e.message.params:{}),r=e.toolName??(typeof n.name==`string`?n.name:void 0),i=e.message?.id,a=n._meta,o=e.protocolVersion??(isObject(a)&&typeof a[`io.modelcontextprotocol/protocolVersion`]==`string`?a[`io.modelcontextprotocol/protocolVersion`]:void 0);return{connectionName:e.connectionName,method:t??`unknown`,toolName:r,protocolVersion:o,requestId:typeof i==`number`||typeof i==`string`?String(i):void 0}}function injectOpenTelemetryTraceContext(e,t){propagation.inject(e,t,traceContextSetter)}function readJsonRpcRequest(e){if(typeof e==`string`&&withinTraceRequestLimit(e))try{let t=JSON.parse(e);return isObject(t)&&typeof t.method==`string`?t:void 0}catch{return}}function withinTraceRequestLimit(e){return e.length<=MAX_MCP_TRACE_REQUEST_BYTES&&utf8Encoder.encode(e).byteLength<=MAX_MCP_TRACE_REQUEST_BYTES}function withinTraceContextLimit(e){let t=0;for(let[n,r]of Object.entries(e))if(n.length+r.length>MAX_MCP_TRACE_CONTEXT_BYTES||(t+=utf8Encoder.encode(n).byteLength+utf8Encoder.encode(r).byteLength+2,t>MAX_MCP_TRACE_CONTEXT_BYTES))return!1;return t>0}function headerValue(e,t){if(e!==void 0)try{return new Headers(e).get(t)??void 0}catch{return}}function isToolErrorResult(e){return isObject(e)&&e.isError===!0}function jsonRpcErrorCode(e){if(!isObject(e))return;let t=e.code;return typeof t==`number`||typeof t==`string`?String(t):void 0}function errorType(e,t){return t===void 0?e instanceof Error?e.name||`Error`:void 0:t}export{MCP_SERIALIZER,createMcpTraceFetch,createMcpTracing};
|
|
@@ -44,6 +44,11 @@ export interface OtelOptions {
|
|
|
44
44
|
* lifecycle providers. The policy may be invoked more than once
|
|
45
45
|
* while a new session is being prepared, so it must be deterministic for
|
|
46
46
|
* consistent results.
|
|
47
|
+
* Unless `experimental.workflow.retention` is explicit, the session's
|
|
48
|
+
* resolved decision also selects Workflow retention: both content directions
|
|
49
|
+
* use the World's default; dropped traces or either excluded direction
|
|
50
|
+
* request deletion on completion. This also removes completed transcripts,
|
|
51
|
+
* but does not delete exported traces.
|
|
47
52
|
*/
|
|
48
53
|
readonly tracePolicy?: TraceCapturePolicy;
|
|
49
54
|
/**
|
package/docs/agent-config.md
CHANGED
|
@@ -263,7 +263,8 @@ duration. Process restarts, ordinary messages, compaction handoffs, and failed
|
|
|
263
263
|
or skipped handoffs keep the existing deadline. At the deadline, eve lets an active turn settle,
|
|
264
264
|
then emits `session.completed` and releases every continuation address; the next
|
|
265
265
|
qualifying channel message starts fresh. Set it to `false` to disable the
|
|
266
|
-
timeout.
|
|
266
|
+
timeout. Session expiration follows [run-data retention](#run-data-retention);
|
|
267
|
+
a zero-retention session loses its stored payloads when it ends.
|
|
267
268
|
|
|
268
269
|
Input tokens, output tokens, and model token cost are checked independently.
|
|
269
270
|
The model call that crosses a limit is allowed to finish because exact usage
|
|
@@ -409,11 +410,24 @@ for the retry behavior.
|
|
|
409
410
|
|
|
410
411
|
## Run data retention
|
|
411
412
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
413
|
+
By default, eve derives run-data retention from the session's resolved
|
|
414
|
+
[OpenTelemetry trace policy](./observability/otel#configure-opentelemetry):
|
|
415
|
+
|
|
416
|
+
- When the policy allows both inputs and outputs, eve uses the World's default
|
|
417
|
+
retention period.
|
|
418
|
+
- When the policy drops the trace or excludes either content direction, eve
|
|
419
|
+
requests deletion as soon as the run ends with Workflow's
|
|
420
|
+
`experimental_retention: 0`. Workflow cannot delete inputs and outputs separately.
|
|
421
|
+
|
|
422
|
+
Without a custom policy, public conversations and development sessions use the
|
|
423
|
+
World's default. Private and unknown-audience sessions outside development request
|
|
424
|
+
`0`, even when no OpenTelemetry destination is installed. This decision is made
|
|
425
|
+
when the session starts; destination export filters and lifecycle-provider
|
|
426
|
+
policies do not change it.
|
|
427
|
+
|
|
428
|
+
Set `experimental.workflow.retention` explicitly to override this behavior.
|
|
429
|
+
Use `0` to request deletion regardless of the tracing policy, or `"default"` to
|
|
430
|
+
keep run data for the World's default period regardless of the tracing policy:
|
|
417
431
|
|
|
418
432
|
```ts title="agent/agent.ts"
|
|
419
433
|
import { defineAgent } from "eve";
|
|
@@ -428,18 +442,29 @@ export default defineAgent({
|
|
|
428
442
|
});
|
|
429
443
|
```
|
|
430
444
|
|
|
431
|
-
|
|
445
|
+
The resolved value applies to every run that owns the session, including successor owners
|
|
432
446
|
started after a deployment handoff, and to the run that collects session
|
|
433
447
|
activity. Runs eve starts for other purposes keep the world's default: session
|
|
434
448
|
timeouts and [workflow tools](./tools/workflows).
|
|
435
449
|
|
|
436
450
|
The value applies per agent. A [subagent](./subagents) that runs its own session
|
|
437
|
-
uses its own value
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
451
|
+
uses its own explicit value or derives retention from its resolved trace decision,
|
|
452
|
+
including any inherited content ceiling. `experimental.workflow.world` is root-only.
|
|
453
|
+
|
|
454
|
+
At `0`, supporting Worlds delete run and step inputs, outputs, and errors;
|
|
455
|
+
event payloads; and stream contents when the run reaches a terminal state. The
|
|
456
|
+
data remains available while the session is active. Run, step, and event records
|
|
457
|
+
remain for the World's default period, including IDs, timestamps, statuses,
|
|
458
|
+
step names, and attributes. Attributes can contain content, including eve's
|
|
459
|
+
session title. This option does not delete local traces, exported telemetry, or
|
|
460
|
+
data stored by tools, channels, or model providers.
|
|
461
|
+
|
|
462
|
+
The Workflow World enforces deletion, not eve or the SDK. A World older than
|
|
463
|
+
spec version 4 rejects `0`; a spec version 4 World without retention support
|
|
464
|
+
keeps the data. Confirm support with your World provider. See
|
|
465
|
+
[Workflow data retention](https://workflow-sdk.dev/docs/observability/retention).
|
|
466
|
+
|
|
467
|
+
> ⚠️ **At `0`, completed session transcripts become unreadable.** Deletion races reads of finished runs. Depending on the World, reading deleted session history returns either an empty stream or `410` with `code: "session_expired"`. Persist anything you need to keep from inside a tool, or set `retention: "default"` to preserve completed-session reads independently of tracing.
|
|
443
468
|
|
|
444
469
|
## Other defineAgent fields
|
|
445
470
|
|
package/docs/channels/teams.mdx
CHANGED
|
@@ -87,6 +87,12 @@ By default, submissions use the Teams identity of the user who clicked the card.
|
|
|
87
87
|
|
|
88
88
|
When a tool approval settles, eve replaces its Adaptive Card with the outcome and responder name. A response rejected by an approval policy leaves the shared card unchanged.
|
|
89
89
|
|
|
90
|
+
### Connection sign-ins
|
|
91
|
+
|
|
92
|
+
When a connection needs the person to sign in, eve's `authorization.required` handler posts an Adaptive Card. In a personal chat, the card includes the sign-in link and any confirmation code. In group chats and channels, the shared card only says who has to sign in and has a **Sign in** button (`Action.Execute`). When someone presses it, eve resolves who they are the same way it does for HITL submissions (`onInputResponse`). If that's the person who needs to sign in, eve sends back a card with the link and code, and Teams shows that card only to them. Anyone else is told they can't open it. That way another member can't finish the sign-in with their own account and have it saved under the requester's identity.
|
|
93
|
+
|
|
94
|
+
If you customize `onMessage` without also setting `onInputResponse`, nobody can open a sign-in from a group chat or channel, because eve rejects every press.
|
|
95
|
+
|
|
90
96
|
For invokes that aren't HITL, handle them in `onInvoke(ctx, activity)`.
|
|
91
97
|
|
|
92
98
|
### Proactive sessions
|
package/docs/code-extension.mdx
CHANGED
|
@@ -103,9 +103,37 @@ Configure `github` to broker GitHub access through Connect instead. The extensio
|
|
|
103
103
|
| `github.connector` | With `github` | Connector that mints a GitHub token |
|
|
104
104
|
| `github.org` | With `github` | Organization whose repositories the `gh` tool can access |
|
|
105
105
|
| `github.broker` | With `github` | `broker(sandbox, rules)` callback that installs, then removes, the GitHub credential rules |
|
|
106
|
+
| `github.authorize` | No | `authorize({ auth, repository, token })` callback that allows or denies each `gh` tool invocation |
|
|
106
107
|
|
|
107
108
|
The `gh` tool requests a token scoped to exactly one repository in `github.org` for each invocation. The sandbox process receives a placeholder `GH_TOKEN`, and the firewall exchanges it on matching GitHub requests. Your `github.broker` callback receives the header-transform rules for the command, then `null` to remove the lease. The callback must preserve your other network rules. GitHub authentication has no command-delivery option.
|
|
108
109
|
|
|
110
|
+
`github.authorize` runs during each `gh` tool execution, not when the session starts. The order is: validate the command and repository, mint the repository-scoped app token, await `authorize({ auth, repository, token })`, install the credential lease, then run the command. `auth` is the session's current caller at tool invocation, or `null`. Returning `false` stops execution before the lease is installed or the command runs. The decision applies to that invocation only; it is neither cached for the session nor repeated for each GitHub API request.
|
|
111
|
+
|
|
112
|
+
For example, use the token to check collaborator status (allowed commands still use the app token's permissions, not the collaborator's):
|
|
113
|
+
|
|
114
|
+
```ts title="agent/extensions/git.ts"
|
|
115
|
+
import git from "eve/extensions/git";
|
|
116
|
+
|
|
117
|
+
import { brokerGitHubLease } from "../lib/github";
|
|
118
|
+
|
|
119
|
+
export default git({
|
|
120
|
+
github: {
|
|
121
|
+
connector: "github/my-agent",
|
|
122
|
+
org: "acme",
|
|
123
|
+
broker: brokerGitHubLease,
|
|
124
|
+
// GitHub channel sessions carry the commenter's login as `auth.subject`.
|
|
125
|
+
async authorize({ auth, repository, token }) {
|
|
126
|
+
if (auth?.authenticator !== "github-webhook" || !auth.subject) return false;
|
|
127
|
+
const response = await fetch(
|
|
128
|
+
`https://api.github.com/repos/${repository}/collaborators/${auth.subject}`,
|
|
129
|
+
{ headers: { authorization: `Bearer ${token}` } },
|
|
130
|
+
);
|
|
131
|
+
return response.status === 204;
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
109
137
|
### Migrate from `code({ github })`
|
|
110
138
|
|
|
111
139
|
`code({ github })` is deprecated. While it is set, the code extension still contributes `code__gh`, its GitHub instructions, and the signed-commit `code__pr` skill. Without it, the code extension contributes no GitHub tool, instructions, or pull request skill. Move the `github` option to `git({ github })`, and import `gh` and the GitHub sandbox helpers from `eve/extensions/git/tools` and `eve/extensions/git/sandbox`.
|
|
@@ -310,7 +310,7 @@ These tools let the model reach what isn't in its tool list. `eve__search` finds
|
|
|
310
310
|
|
|
311
311
|
Entries the agent declares count from the session's first step. An entry a dynamic resolver returns counts from the step where it first appears, so a resolver in `agent/tools/` that returns only tools without `deferred: true` adds no catalog tools. Once a session's tool list includes a catalog tool, the session keeps it, even after a resolver stops returning the entry that brought it. The catalog tools change only when the session first reaches a new kind of entry, such as its first deferred tool or its first connection.
|
|
312
312
|
|
|
313
|
-
- `eve__search({ query, limit? })` returns the best matches, up to `limit` (default 10, at most 50). `query` is required and must contain a word. A tool match has its exact `tool` name, its `description`, and a TypeScript `signature` rendered from its schemas. A deferred skill's match has its `skill` name, its `description`, and the `path` of its `SKILL.md` when it has supporting files. A result with `tool` is called with `eve__tool`, and one with `skill` is loaded with `eve__skill`. Next to `results`, `searched` counts the entries the query covered, the whole catalog or one namespace, and `remaining` counts the matches past `limit`. A connection behind sign-in counts as its one sign-in result until the user signs in, and an unavailable connection counts as none. Tools and skills rank together, in tiers: an entry whose name is exactly the query, then one whose name after its last `__` is the query, such as `linear__create_issue` or `sre__create_issue` for `create_issue`, then the tools of a connection named by the query, then entries whose names, or names after their last `__`, start with the query, then keyword matches in names, parameters, and descriptions. So `eve__search({ query: "linear" })` lists the `linear` connection's tools first. One-letter and filler words such as `a` and `the` don't count toward keyword matches unless the query has nothing else.
|
|
313
|
+
- `eve__search({ query, limit? })` returns the best matches, up to `limit` (default 10, at most 50). `query` is required and must contain a word. A tool match has its exact `tool` name, its `description`, and a TypeScript `signature` rendered from its schemas. A very long signature drops its property descriptions before any property name. A deferred skill's match has its `skill` name, its `description`, and the `path` of its `SKILL.md` when it has supporting files. A result with `tool` is called with `eve__tool`, and one with `skill` is loaded with `eve__skill`. Next to `results`, `searched` counts the entries the query covered, the whole catalog or one namespace, and `remaining` counts the matches past `limit`. A connection behind sign-in counts as its one sign-in result until the user signs in, and an unavailable connection counts as none. Tools and skills rank together, in tiers: an entry whose name is exactly the query, then one whose name after its last `__` is the query, such as `linear__create_issue` or `sre__create_issue` for `create_issue`, then the tools of a connection named by the query, then entries whose names, or names after their last `__`, start with the query, then keyword matches in names, parameters, and descriptions. So `eve__search({ query: "linear" })` lists the `linear` connection's tools first. One-letter and filler words such as `a` and `the` don't count toward keyword matches unless the query has nothing else.
|
|
314
314
|
- A query whose first word contains `__` searches one namespace: everything before its last `__`, without trailing underscores. The namespace only filters. `eve__search` keeps names under `<namespace>__` and anything named exactly the namespace, such as a connection's sign-in entry, then ranks them by the whole query, so `eve__search({ query: "linear__" })` returns only the `linear` connection's tools, or its sign-in result, and an exact name that contains `__` still ranks first. eve lists only the connections that can own names in that namespace, so other connections make no network call and don't appear in `unavailable`. A namespace that matches nothing fails with the closest connection names. Characters that can't appear in a name, such as a leading `^`, are ignored; `query` isn't a regular expression.
|
|
315
315
|
- `eve__search` never asks the user to sign in. A connection whose server won't list its tools until the user signs in appears as one result named after the connection, such as `linear`; a connection whose server lists its tools without a token is searched like any other. A connection whose tools fail to load, or don't load within 10 seconds, appears under `unavailable` with its `error`, such as `"crm" did not list its tools within 10s. Try again later.` Matches from everything else are still returned, so a slow server doesn't hold up the search. An `eve__tool` call on that connection's tools fails with the same error.
|
|
316
316
|
- `eve__tool({ name: "linear" })`, with a connection's own name, asks the user to sign in to that connection when its tools need it, and returns once they can be listed, so the next `eve__search` finds them. On a server that lists its tools without sign-in, it confirms the tools are available without asking.
|
|
@@ -422,6 +422,8 @@ export default noReply();
|
|
|
422
422
|
|
|
423
423
|
`no_reply` is a `defineTool` tool with [`endsTurn: true`](/docs/tools#end-the-turn-after-a-tool-call), so the turn ends only when no other tool runs in the same step. Only root sessions receive it. Slack clears the thread status when the turn completes. Remove the file to remove the tool.
|
|
424
424
|
|
|
425
|
+
A root session also accepts a successful model call that returns no text with `finishReason: "stop"`, without retrying or reporting a model-call failure. A turn that settles with no text completes without a final message. Use `no_reply` when the agent should record an explicit choice to stay quiet, including an optional reason. Delegated sessions still retry an empty reply once and report a failure if it remains empty, so the caller can act on the failure.
|
|
426
|
+
|
|
425
427
|
### `sleep`
|
|
426
428
|
|
|
427
429
|
`sleep` pauses and durably resumes the current turn. The model calls it with `{ seconds }`; the wait does not hold an application runtime open. Concurrent calls run in parallel, and the turn resumes after the longest wait. A steering message, the default for a new message, ends the wait early: `sleep` returns `{ interrupted: true }`, which the model reads as `Stopped early because a new message arrived.`, followed by the message. Add it:
|
package/docs/connections/mcp.mdx
CHANGED
|
@@ -205,6 +205,111 @@ An MCP tool call returns the tool's `structuredContent` when the server sends it
|
|
|
205
205
|
|
|
206
206
|
When a remote tool returns more data than the model needs, narrow the result at the MCP server. Prefer a purpose-built search or summary tool, or return a stable handle that another call can use to fetch a smaller slice. If you do not control the server and an equivalent upstream API is available, replace only that operation with an authored tool that stores the full payload outside model context and projects the needed fields through `toModelOutput`. Block the original MCP operation through [`tools.block`](#tool-filters) so the model does not see duplicate tools.
|
|
207
207
|
|
|
208
|
+
## Events (experimental)
|
|
209
|
+
|
|
210
|
+
An MCP connection can watch the server's events and run your code when one arrives. Vercel Connect holds the upstream subscription and forwards each event to your agent; eve runs your callback.
|
|
211
|
+
|
|
212
|
+
Requirements:
|
|
213
|
+
|
|
214
|
+
- A statically authored MCP connection with a static `connect()` auth provider. Dynamic connections and auth resolvers are not supported.
|
|
215
|
+
- `@vercel/connect@2.5.2` or later.
|
|
216
|
+
- An MCP server that supports events over Streamable HTTP.
|
|
217
|
+
|
|
218
|
+
### Handle events
|
|
219
|
+
|
|
220
|
+
Add `experimental_events` to the connection. In this example, a user asks the agent to "watch the support inbox and draft replies to new bug reports". The model subscribes to Bird's `email_mailbox.message_received` event for that mailbox. Each new email then starts a turn in the same conversation, with instructions to triage it:
|
|
221
|
+
|
|
222
|
+
```ts title="agent/connections/bird.ts"
|
|
223
|
+
import { connect } from "@vercel/connect/eve";
|
|
224
|
+
import { defineMcpClientConnection } from "eve/connections";
|
|
225
|
+
|
|
226
|
+
export default defineMcpClientConnection({
|
|
227
|
+
url: "https://mcp.bird.com/",
|
|
228
|
+
description: "Bird: email, SMS, and contacts. Can watch a mailbox for new mail.",
|
|
229
|
+
auth: connect("bird/bird"),
|
|
230
|
+
experimental_events: {
|
|
231
|
+
async onEvent({ event, origin, auth, attachSession }) {
|
|
232
|
+
if (event.name !== "email_mailbox.message_received") return;
|
|
233
|
+
await attachSession(origin.sessionId).send(
|
|
234
|
+
[
|
|
235
|
+
"A new email arrived in the mailbox you are watching:",
|
|
236
|
+
JSON.stringify(event.data),
|
|
237
|
+
"If it is a bug report, look up the sender's earlier threads, draft a reply " +
|
|
238
|
+
"that says what we know and what happens next, and ask me before sending it. " +
|
|
239
|
+
"Otherwise, summarize it in one line.",
|
|
240
|
+
].join("\n\n"),
|
|
241
|
+
{ auth, turnPolicy: "queue" },
|
|
242
|
+
);
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The model does the work with the connection's own tools: it reads the thread, drafts the reply, and waits for the user's approval in the conversation. `turnPolicy: "queue"` lets a burst of emails run one turn after another instead of interrupting the user.
|
|
249
|
+
|
|
250
|
+
`onEvent` is required. Defining it does not subscribe to anything: the model subscribes at runtime.
|
|
251
|
+
|
|
252
|
+
Callbacks run outside any conversation, as the user who subscribed (`auth`). Nothing enters a session unless you call `attachSession(sessionId).send(...)`, and `attachSession` never creates a session.
|
|
253
|
+
|
|
254
|
+
Each delivery runs in its own durable workflow, so callbacks can run concurrently, out of order, and more than once. Use `deliveryId` to deduplicate side effects:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
async onEvent({ event, deliveryId }) {
|
|
258
|
+
await fetch("https://crm.example/notes", {
|
|
259
|
+
method: "POST",
|
|
260
|
+
headers: { "Idempotency-Key": deliveryId },
|
|
261
|
+
body: JSON.stringify(event.data),
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Handle missed events and ended subscriptions
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
experimental_events: {
|
|
270
|
+
async onEvent({ event }) {
|
|
271
|
+
// ...
|
|
272
|
+
},
|
|
273
|
+
async onGap({ origin, auth, attachSession }) {
|
|
274
|
+
// The server could not deliver every event. Re-read the source.
|
|
275
|
+
await attachSession(origin.sessionId).send(
|
|
276
|
+
"Some Bird events were missed. Re-check the mailbox.",
|
|
277
|
+
{ auth },
|
|
278
|
+
);
|
|
279
|
+
},
|
|
280
|
+
async onTerminated({ origin, auth, error, attachSession }) {
|
|
281
|
+
// The upstream subscription ended. The watch ends when this returns.
|
|
282
|
+
await attachSession(origin.sessionId).send(
|
|
283
|
+
`The Bird watch ended: ${error.message}`,
|
|
284
|
+
{ auth },
|
|
285
|
+
);
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### What the model can call
|
|
291
|
+
|
|
292
|
+
`eve__search` lists three kinds of actions for the connection:
|
|
293
|
+
|
|
294
|
+
| Action | Input | Result |
|
|
295
|
+
| ------------------------- | ---------------------- | --------------------------------------- |
|
|
296
|
+
| `events_subscribe_<hash>` | `{ arguments, ttlMs }` | `{ id, status, expiresAt, ... }` |
|
|
297
|
+
| `events_get_subscription` | `{ id }` | The subscription, or unknown once ended |
|
|
298
|
+
| `events_unsubscribe` | `{ id }` | `{ id, status: "stopping" }` |
|
|
299
|
+
|
|
300
|
+
There is one subscribe action per event the server offers; its description names the event. `ttlMs` is required: an integer from `120000` (2 minutes) to `31536000000` (365 days), or `null` to watch until stopped. `expiresAt` is the resulting deadline, or `null`.
|
|
301
|
+
|
|
302
|
+
- **Pending.** If Connect has not confirmed in time, subscribe returns the `id` with `status: "pending"`. Call get with that `id` later.
|
|
303
|
+
- **Repeats.** Subscribing again to the same event with the same arguments from the same session returns the existing watch. Another session gets its own watch.
|
|
304
|
+
- **Stopping.** Get and stop accept the `id` from any of the creator's sessions. After stop, eve keeps retrying Connect's unsubscribe until cleanup completes; until then get still reports the watch and stop can be called again.
|
|
305
|
+
- **Lifetime.** A watch outlives the session that created it. It ends on stop, at `expiresAt`, or when the upstream subscription terminates.
|
|
306
|
+
|
|
307
|
+
`tools.allow` and `tools.block` apply to these actions. An allow list hides any event action it does not name, so copy the exact `events_subscribe_<hash>` names from `eve__search`. `toolCall.providedArguments` does not apply to event actions.
|
|
308
|
+
|
|
309
|
+
### Receiver
|
|
310
|
+
|
|
311
|
+
eve mounts `POST /eve/v1/hooks/:connectionName`, under any configured agent or public prefix. It accepts only Connect's delivery token and only deliveries for a live watch's subscription; it answers `410` once the watch has ended. The callback's identity always comes from the saved watch, never from the event payload.
|
|
312
|
+
|
|
208
313
|
## Troubleshooting
|
|
209
314
|
|
|
210
315
|
| Symptom | Check |
|
package/docs/guides/hooks.md
CHANGED
|
@@ -219,6 +219,10 @@ export default defineHook({
|
|
|
219
219
|
|
|
220
220
|
The remaining subscribers for the event still run. Then eve cancels the turn the same way [`session.cancel()`](./client/streaming) does: in-flight model and tool work is aborted, delegated child turns are cancelled, and the turn ends with `turn.cancelled` followed by `session.waiting`. No failure event is emitted. A cancel from `turn.started` or `step.started` takes effect before that model call. In a conversation, the next message starts a new turn. A delegated task reports the cancellation to its caller.
|
|
221
221
|
|
|
222
|
+
A plain-text message that answers a pending question, such as one from `ask_question`, is recorded as `message.received` before eve delivers it. Calling `ctx.cancel()` from that event's hook cancels the turn instead: the question resolves as `cancelled`, and the waiting tool call never receives the text.
|
|
223
|
+
|
|
224
|
+
The same goes for the `action.partial` a workflow tool reports while the turn waits on it: `ctx.cancel()` from its hook cancels the turn, and the run's result never reaches the model.
|
|
225
|
+
|
|
222
226
|
`ctx.cancel()` returns `void` rather than a promise. The turn stops after the hook returns, so there is nothing to await. Call it before the handler's promise settles: eve ignores a call from work the handler does not await and logs a warning.
|
|
223
227
|
|
|
224
228
|
`ctx.cancel()` only stops a running turn. eve logs a warning and ignores the call on `step.failed`, `turn.completed`, `turn.failed`, `turn.cancelled`, `turn.waiting`, `session.waiting`, `session.completed`, `session.failed`, `context.cleared`, `task.started`, `task.settled`, and `agent.started`, and during clear or compact requests.
|
|
@@ -170,6 +170,8 @@ Each call emits one `tool.call.*` lifecycle to authored providers. SDK execution
|
|
|
170
170
|
|
|
171
171
|
For local and remote subagents, `tool.call.completed` and `tool.call.failed` include the child turn's `usage` directly. Token counts are always present when the child reports usage; `usage.costUsd` is present only when the model provider reports a price.
|
|
172
172
|
|
|
173
|
+
When a tool throws and outputs are recorded, `tool.call.failed` carries an `Error` with the thrown error's `name` and `message`, so a provider can classify the failure by `error.name`. It is rebuilt from the durable session record rather than being the object the tool threw, so `instanceof` checks against your own error classes do not match.
|
|
174
|
+
|
|
173
175
|
When upgrading, replace `action.started`, `action.completed`, and `action.failed` handlers with their `tool.call.*` equivalents. Read `event.toolName` instead of `event.name` on start events. The OpenTelemetry trace schema remains version 4.
|
|
174
176
|
|
|
175
177
|
Handlers from different files run concurrently and are failure-isolated. Do
|
|
@@ -38,6 +38,16 @@ does not affect lifecycle instrumentation created with `defineInstrumentation()`
|
|
|
38
38
|
See [Audience](../channels/overview#audience) for how channels classify the
|
|
39
39
|
conversation passed to this policy.
|
|
40
40
|
|
|
41
|
+
The session's resolved capture decision also selects its default
|
|
42
|
+
[Workflow run-data retention](/docs/agent-config#run-data-retention). Allowing
|
|
43
|
+
both inputs and outputs uses the World's default; dropping the trace or excluding
|
|
44
|
+
either direction requests deletion of durable payloads and streams when the run
|
|
45
|
+
ends. This makes completed private and unknown-audience transcripts unreadable
|
|
46
|
+
under the default policy outside development. Set
|
|
47
|
+
`experimental.workflow.retention: "default"` on the agent to retain completed
|
|
48
|
+
sessions independently of tracing. Destination `exportPolicy` filters do not
|
|
49
|
+
change Workflow retention, and Workflow deletion does not delete exported traces.
|
|
50
|
+
|
|
41
51
|
## Instrument Node.js dependencies
|
|
42
52
|
|
|
43
53
|
Pass OpenTelemetry instrumentation instances to `otel({ instrumentations })`.
|
package/docs/sandbox/vercel.mdx
CHANGED
|
@@ -104,6 +104,52 @@ const sandbox = await ctx.getSandbox(environment);
|
|
|
104
104
|
const sandboxName = sandbox.name;
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
## Mount a Drive
|
|
108
|
+
|
|
109
|
+
A [Vercel Sandbox Drive](https://vercel.com/docs/sandbox/concepts/drives) stores files independently of a sandbox. Create or retrieve the Drive before calling `open()`, then pass it in `mounts` under an absolute path:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { defineSandbox } from "eve/sandbox";
|
|
113
|
+
import { Drive, VercelSandbox } from "eve/sandbox/vercel";
|
|
114
|
+
|
|
115
|
+
const REGION = "iad1";
|
|
116
|
+
|
|
117
|
+
export const environment = VercelSandbox.environment({ region: REGION });
|
|
118
|
+
|
|
119
|
+
export default defineSandbox(async () => {
|
|
120
|
+
const drive = await Drive.getOrCreate({
|
|
121
|
+
name: "agent-workspace",
|
|
122
|
+
region: REGION,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return environment.open({
|
|
126
|
+
mounts: {
|
|
127
|
+
"/data": drive,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This example mounts the Drive read-write at `/data`. Files written there remain on the Drive after the sandbox stops. Keep Drive mounts separate from eve's managed `/workspace` directory.
|
|
134
|
+
|
|
135
|
+
Set the same region on the environment and the Drive. The environment region places the prepared snapshot and each session sandbox together with the Drive.
|
|
136
|
+
|
|
137
|
+
A Drive supports one active read-write mount. Because each eve session gets its own sandbox, the fixed `agent-workspace` name works only when one eve session uses the Drive at a time. If sessions can overlap, derive an opaque, stable Drive name per owner or tenant. The [Vercel guide to using Drives with eve](https://vercel.com/kb/guide/vercel-drives-eve-agent) shows how to derive a Drive name from the session initiator.
|
|
138
|
+
|
|
139
|
+
To share a point-in-time view across concurrent sandboxes, mount a read-only snapshot instead:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
return environment.open({
|
|
143
|
+
mounts: {
|
|
144
|
+
"/data": drive.snapshot(),
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Before mounting `drive.snapshot()`, seed a new Drive by mounting it read-write and writing at least one file. An uninitialized Drive cannot be mounted as a snapshot.
|
|
150
|
+
|
|
151
|
+
Vercel allows up to four non-overlapping, absolute Drive mount paths per sandbox. See the Vercel documentation for [Drive lifecycle, limits, and pricing](https://vercel.com/docs/sandbox/concepts/drives).
|
|
152
|
+
|
|
107
153
|
## Live sandbox options
|
|
108
154
|
|
|
109
155
|
`open()` also accepts Vercel compute resources, timeout, and Drive mounts. Configure project credentials and custom fetch behavior on the environment, not in `open()`, because resume does not reconstruct start-only options.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.80.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
|
|
6
6
|
"keywords": [
|
|
@@ -569,9 +569,9 @@
|
|
|
569
569
|
"@ai-sdk/provider": "^4.0.26",
|
|
570
570
|
"@ai-sdk/provider-utils": "^5.0.58",
|
|
571
571
|
"@cfworker/json-schema": "4.1.1",
|
|
572
|
-
"@chat-adapter/slack": "4.
|
|
573
|
-
"@chat-adapter/state-memory": "4.
|
|
574
|
-
"@chat-adapter/twilio": "4.
|
|
572
|
+
"@chat-adapter/slack": "4.42.0",
|
|
573
|
+
"@chat-adapter/state-memory": "4.42.0",
|
|
574
|
+
"@chat-adapter/twilio": "4.42.0",
|
|
575
575
|
"@clack/core": "1.3.1",
|
|
576
576
|
"@eve/catalog": "0.0.1",
|
|
577
577
|
"@eve/tracing": "0.0.0",
|
|
@@ -592,7 +592,7 @@
|
|
|
592
592
|
"@types/react": "19.2.15",
|
|
593
593
|
"@types/react-test-renderer": "19.1.0",
|
|
594
594
|
"@vercel/blob": "2.8.0",
|
|
595
|
-
"@vercel/connect": "2.
|
|
595
|
+
"@vercel/connect": "2.5.2",
|
|
596
596
|
"@vercel/detect-agent": "1.2.3",
|
|
597
597
|
"@vercel/oidc": "3.8.0",
|
|
598
598
|
"@vercel/otel": "2.1.3",
|
|
@@ -607,7 +607,7 @@
|
|
|
607
607
|
"@workflow/world-local": "5.1.0",
|
|
608
608
|
"@workflow/world-vercel": "5.2.0",
|
|
609
609
|
"ai": "^7.0.137",
|
|
610
|
-
"chat": "4.
|
|
610
|
+
"chat": "4.42.0",
|
|
611
611
|
"chokidar": "5.0.0",
|
|
612
612
|
"commander": "14.0.3",
|
|
613
613
|
"dd-trace": "6.13.0",
|
|
@@ -640,7 +640,7 @@
|
|
|
640
640
|
"@opentelemetry/api": "^1.0.0",
|
|
641
641
|
"ai": "^7.0.137",
|
|
642
642
|
"braintrust": "^3.0.0",
|
|
643
|
-
"chat": "^4.
|
|
643
|
+
"chat": "^4.42.0",
|
|
644
644
|
"dd-trace": "^6.13.0",
|
|
645
645
|
"just-bash": "^3.1.0",
|
|
646
646
|
"microsandbox": "^0.5.0"
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
var e=/[<>|]/,t=/[\^|>]/,n=/^[A-Z0-9_]+$/,r=/(?<![<\w])@([A-Z][A-Z0-9_]+)/g,i=3e3,a=/^[ \t]+/,o=/^(?:>|<|#{1,6}(?=[ \t\n]|$)|[-+*](?=[ \t\n]|$)|`{3,}|~{3,}|(?:[-*_][ \t]*){3,}(?=\n|$))/,s=/^(\d{1,9})([.)])(?=[ \t\n]|$)/;function c(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`)}function l(e){return e.replace(/</g,`<`).replace(/>/g,`>`).replace(/&/g,`&`)}function u(e,t={}){return O(e),{...t.emoji===void 0?{}:{emoji:t.emoji},text:e,type:`plain_text`}}function d(e,t={}){return O(e),{text:e,type:`mrkdwn`,...t.verbatim===void 0?{}:{verbatim:t.verbatim}}}function f(e){return k(e,`userId`),`<@${e}>`}function p(e){return k(e,`channelId`),`<#${e}>`}function m(e){return k(e,`userGroupId`),`<!subteam^${e}>`}function h(e){return`<!${e}>`}function g(e,t){return A(e,`url`),t?`<${e}|${c(t)}>`:`<${e}>`}function _(e,t,n,r={}){j(t,`token`);let i=e instanceof Date?Math.floor(e.getTime()/1e3):e;if(!Number.isInteger(i))throw TypeError(`timestamp must be an integer unix timestamp or Date`);return`<!date^${i}^${t}${r.link?`^${M(r.link)}`:``}|${c(n)}>`}function v(e){return l(e.includes("```")?x(e):b(e))}function y(e){let t=e.replace(/<@([A-Z0-9_]+)\|([^<>]+)>/g,`@$2`);return t=t.replace(/<@([A-Z0-9_]+)>/g,`@$1`),t=t.replace(/<#([A-Z0-9_]+)\|([^<>]+)>/g,`#$2 ($1)`),t=t.replace(/<#([A-Z0-9_]+)>/g,`#$1`),t=t.replace(/<(?!https?:\/\/)([^<>|]+)\|(https?:\/\/[^|<>]+)>/g,`<$2|$1>`),t=t.replace(/<(https?:\/\/[^|<>]+)\|([^<>]+)>/g,`[$2]($1)`),t=t.replace(/<(https?:\/\/[^<>]+)>/g,`$1`),t}function b(e){let t=y(e);return t=t.replace(/(?<![_*\\])\*([^*\n]+)\*(?![_*])/g,`**$1**`),t=t.replace(/(?<!~)~([^~\n]+)~(?!~)/g,`~~$1~~`),t}function x(e){let t=``,n=0,r=0,i=!1,a=r=>{let a=e.slice(n,r);i&&=(a=T(a),!1),t+=b(a)};for(;r<e.length;){let o=e[r];if(o===`<`){let t=S(e,r);r=t===-1?r+1:t;continue}if(o!=="`"){r+=1;continue}if(!e.startsWith("```",r)){let t=C(e,r);r=t===-1?r+1:t;continue}let s=r+3,c=e.indexOf("```",s);if(c===-1||w(e,r)){r=s;continue}a(r),t.length>0&&!t.endsWith(`
|
|
2
|
-
`)&&(t+=`
|
|
3
|
-
`);let l=e.slice(s,c);t+="```",l.startsWith(`
|
|
4
|
-
`)||(t+=`
|
|
5
|
-
`),t+=y(l),l.endsWith(`
|
|
6
|
-
`)||(t+=`
|
|
7
|
-
`),t+="```",r=c+3,n=r,r<e.length&&e[r]!==`
|
|
8
|
-
`&&(t+=`
|
|
9
|
-
`,i=!0)}return a(e.length),t}function S(e,t){let n=t+1;for(;n<e.length&&e[n]!==`>`&&e[n]!==`
|
|
10
|
-
`&&e[n]!==`\r`;)n+=1;return e[n]===`>`?n+1:-1}function C(e,t){let n=e.indexOf("`",t+1);if(n===-1)return-1;let r=e.indexOf(`
|
|
11
|
-
`,t+1);return r!==-1&&r<n?-1:n+1}function w(e,t){let n=e.lastIndexOf(`
|
|
12
|
-
`,t-1)+1;return e.slice(n,t).trimStart().startsWith(`>`)}function T(e){let t=a.exec(e)?.[0]??``,n=t.length>0?` `:``,r=e.slice(t.length);return o.test(r)?`${n}\\${r}`:n+r.replace(s,`$1\\$2`)}function E(e){return e.replace(/\*\*(.+?)\*\*/g,`*$1*`)}function D(e){return e.replace(r,`<@$1>`)}function O(e){if(e.length<1||e.length>i)throw TypeError(`text must be between 1 and ${i} characters`)}function k(e,t){if(!n.test(e))throw TypeError(`${t} must be a Slack ID`)}function A(t,n){if(e.test(t))throw TypeError(`${n} cannot contain Slack control characters`)}function j(e,n){if(t.test(e))throw TypeError(`${n} cannot contain Slack date control characters`)}function M(e){return j(e,`link`),e}export{_ as a,f as c,E as d,v as f,p as i,m as l,u as n,g as o,l as p,c as r,h as s,d as t,D as u};
|