eve 0.76.3 → 0.77.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 +27 -0
- package/dist/src/channel/adapter.d.ts +13 -4
- package/dist/src/channel/channel-address.js +1 -1
- package/dist/src/channel/send-input.d.ts +6 -2
- package/dist/src/channel/send-input.js +1 -1
- package/dist/src/channel/session.js +1 -1
- package/dist/src/chunks/{use-eve-agent-BtKWTEpm.js → use-eve-agent-B8brxCk-.js} +46 -28
- package/dist/src/chunks/{use-eve-agent-jI6EsYAu.js → use-eve-agent-BSYe_Re7.js} +46 -28
- package/dist/src/cli/commands/vercel-non-interactive.d.ts +5 -3
- package/dist/src/cli/commands/vercel-non-interactive.js +1 -1
- package/dist/src/client/eve-agent-store.d.ts +2 -2
- package/dist/src/client/message-response.d.ts +2 -0
- package/dist/src/client/message-response.js +1 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +9 -9
- package/dist/src/compiled/@ai-sdk/anthropic/index.d.ts +6 -1
- package/dist/src/compiled/@ai-sdk/anthropic/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/google/index.d.ts +16 -3
- package/dist/src/compiled/@ai-sdk/google/index.js +6 -6
- package/dist/src/compiled/@ai-sdk/mcp/index.d.ts +681 -348
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/openai/index.d.ts +56 -42
- package/dist/src/compiled/@ai-sdk/openai/index.js +5 -3
- package/dist/src/compiled/@ai-sdk/otel/index.js +3 -3
- package/dist/src/compiled/@ai-sdk/provider/index.d.ts +49 -15
- package/dist/src/compiled/@ai-sdk/provider/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/provider-utils/index.d.ts +4 -1
- package/dist/src/compiled/_chunks/workflow/{dist-DXLdlucM.js → dist-C8k3N3BQ.js} +2 -4
- package/dist/src/compiled/_chunks/workflow/dist-DsNhwdzf.js +1 -0
- package/dist/src/compiled/_chunks/workflow/experimental-decision-DlvnsBD-.js +3 -0
- package/dist/src/compiler/extension-compatibility.d.ts +18 -18
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/context/dynamic-model-lifecycle.js +1 -1
- package/dist/src/evals/judge.js +1 -1
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/eve-channel/types.d.ts +14 -1
- package/dist/src/execution/cancelled-model-call-batch.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/publish-session-events.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.d.ts +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
- package/dist/src/execution/sandbox/read-file.d.ts +5 -5
- package/dist/src/execution/sandbox/read-file.js +2 -2
- package/dist/src/execution/session/end-sandbox-step.js +1 -1
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/web-fetch/request.js +1 -1
- package/dist/src/harness/attachment-staging.d.ts +13 -12
- package/dist/src/harness/attachment-staging.js +1 -1
- package/dist/src/harness/compaction/step.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/model-call/call.js +1 -1
- package/dist/src/harness/model-call/errors.d.ts +10 -0
- package/dist/src/harness/model-call/errors.js +1 -1
- package/dist/src/harness/session-machine/transitions.js +1 -1
- package/dist/src/harness/token-estimate.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/application/stamped-package-version.js +1 -1
- package/dist/src/internal/attachments/data.d.ts +29 -10
- package/dist/src/internal/attachments/data.js +1 -1
- package/dist/src/internal/attachments/errors.d.ts +2 -2
- package/dist/src/internal/attachments/media-metadata.d.ts +15 -0
- package/dist/src/internal/attachments/media-metadata.js +1 -1
- package/dist/src/internal/attachments/public-link.d.ts +5 -0
- package/dist/src/internal/attachments/public-link.js +1 -0
- package/dist/src/internal/attachments/sandbox-refs.d.ts +7 -6
- package/dist/src/internal/attachments/sandbox-refs.js +1 -1
- package/dist/src/internal/attachments/url-refs.js +1 -1
- package/dist/src/protocol/message.d.ts +7 -0
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/public/channels/attachment-error.d.ts +14 -0
- package/dist/src/public/channels/attachment-error.js +1 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +1 -1
- package/dist/src/public/channels/discord/defaults.js +1 -1
- package/dist/src/public/channels/github/defaults.js +1 -1
- package/dist/src/public/channels/index.d.ts +2 -0
- package/dist/src/public/channels/index.js +1 -1
- package/dist/src/public/channels/linear/defaults.js +1 -1
- package/dist/src/public/channels/slack/api.d.ts +10 -0
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/slack/approval-cards.js +1 -1
- package/dist/src/public/channels/slack/attachments.d.ts +29 -19
- package/dist/src/public/channels/slack/attachments.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +1 -1
- package/dist/src/public/channels/slack/inbound.d.ts +6 -0
- package/dist/src/public/channels/slack/inbound.js +1 -1
- package/dist/src/public/channels/slack/interaction-cards.d.ts +6 -0
- package/dist/src/public/channels/slack/interaction-cards.js +1 -1
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/defaults.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/telegram/defaults.js +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/defaults.js +1 -1
- package/dist/src/public/definitions/channel.js +1 -1
- package/dist/src/runtime/channels/registry.js +1 -1
- 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/web-options.js +1 -1
- package/dist/src/shared/agent-definition.d.ts +2 -1
- package/dist/src/shared/channel-definition.d.ts +16 -4
- package/dist/src/svelte/index.d.ts +0 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/read-file.d.ts +3 -2
- package/dist/src/tools/provided/read-file.js +2 -2
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/dist/src/vue/index.d.ts +0 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/chat-sdk.mdx +1 -1
- package/docs/channels/custom.mdx +30 -3
- package/docs/channels/eve.mdx +34 -0
- package/docs/channels/slack.mdx +5 -1
- package/docs/concepts/built-in-tools.md +1 -1
- package/docs/concepts/sessions-runs-and-streaming.md +2 -2
- package/docs/evals/overview.mdx +1 -1
- package/docs/guides/client/streaming.mdx +1 -1
- package/docs/memory/custom-provider.md +3 -1
- package/docs/sandbox/index.mdx +8 -4
- package/docs/tools/overview.mdx +1 -1
- package/package.json +11 -11
- package/dist/src/compiled/_chunks/workflow/experimental-decision-BrfWf6-n.js +0 -3
- package/dist/src/internal/attachments/refs.d.ts +0 -55
- package/dist/src/internal/attachments/refs.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{isCompiledChannel}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{formatTelegramContextBlock,parseTelegramUpdate}from"#public/channels/telegram/inbound.js";import{answerTelegramCallbackQuery,callTelegramApi,editTelegramMessageReplyMarkup,editTelegramMessageText,sendTelegramChatAction,sendTelegramMessage,splitTelegramMessageText,telegramContinuationToken}from"#public/channels/telegram/api.js";import{TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX}from"#public/channels/telegram/authorization.js";import{TELEGRAM_HITL_CALLBACK_PREFIX,isTelegramSyntheticResponse,resolveTelegramInputResponses,telegramCallbackInputResponse,telegramReplyInputResponses}from"#public/channels/telegram/hitl.js";import{buildTelegramTurnMessage,collectTelegramFileParts,createTelegramFetchFile}from"#public/channels/telegram/attachments.js";import{defaultEvents,defaultOnMessage,defaultTelegramAuth,isTelegramBotMentioned}from"#public/channels/telegram/defaults.js";import{verifyTelegramRequest}from"#public/channels/telegram/verify.js";import{dispatchTelegramAuthorizationCallback}from"#public/channels/telegram/authorization-callback.js";import{initialTelegramState,stateFromTelegramCallbackQuery,stateFromTelegramMessage,telegramContinuationTokenFromState}from"#public/channels/telegram/state.js";import{telegramInstrumentation}from"#public/channels/telegram/audience.js";const log=createLogger(`telegram.channel`);function telegramChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=e.onMessage??defaultOnMessage,r={...defaultEvents,...e.events},i=defineChannel({kindHint:`telegram`,turnPolicy:e.turnPolicy,state:initialTelegramState(e.botUsername),...telegramInstrumentation,fetchFile:createTelegramFetchFile({api:e.api,credentials:e.credentials,policy:t}),context(t,n){return rebuildTelegramContext(t,n,e)},routes:[POST(e.route??`/eve/v1/telegram`,async(r,{from:i,resolveSession:a,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Telegram body is not valid JSON`,{error:e}),new Response(`ok`)}let l=parseTelegramUpdate(c);return l===null?new Response(`ok`):l.kind===`message`?(o(dispatchMessage({config:e,message:l.message,onMessage:n,uploadPolicy:t,from:i})),new Response(`ok`)):(o(dispatchCallbackQuery({config:e,query:l.callbackQuery,from:i,resolveSession:a})),new Response(`ok`))})],async receive(t,{from:n}){let r=t.target,i=readChatId(r.chatId);if(i===void 0)throw Error(`telegramChannel().receive requires target.chatId.`);let a=typeof r.messageThreadId==`number`?r.messageThreadId:void 0,o=readChatId(r.conversationId),s=r.initialMessage;if(s!==void 0&&o!==void 0)throw Error("telegramChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c={...initialTelegramState(e.botUsername),chatId:i,conversationId:o??null,messageThreadId:a??null};return s!==void 0&&await buildTelegramHandle({config:e,state:c}).sendMessage(s),n(telegramContinuationTokenFromState(c)).send(t.message,{auth:t.auth,state:c})},events:r});return attachTelegramDeliver(i),i}function rebuildTelegramContext(e,t,n){return{state:e,telegram:buildTelegramHandle({config:n,session:t,state:e})}}function buildTelegramHandle(e){let t=e.config.api,n=e.state,r=e.config.credentials;function anchor(t){let r=n.chatType??t.chatType??null;n.chatType===null&&t.chatType!==void 0&&(n.chatType=t.chatType),t.id&&shouldAnchorTelegramConversation(r)&&(n.conversationId=t.id,n.chatId&&e.session?.continuation?.alias(telegramContinuationToken({chatId:n.chatId,conversationId:t.id,messageThreadId:n.messageThreadId??void 0})))}async function sendOne(e){let t=await sendMessage(e);return anchor(t),t}async function sendMessage(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for outbound message.`);return sendTelegramMessage({apiBaseUrl:t?.apiBaseUrl,body:{...e,message_thread_id:e.message_thread_id??n.messageThreadId??void 0},credentials:r,fetch:t?.fetch,fileBaseUrl:t?.fileBaseUrl,chatId:i})}return{botUsername:n.botUsername??e.config.botUsername,chatId:n.chatId??``,chatType:n.chatType??void 0,conversationId:n.conversationId??void 0,messageThreadId:n.messageThreadId??void 0,answerCallbackQuery(e){return answerTelegramCallbackQuery({apiBaseUrl:t?.apiBaseUrl,callbackQueryId:e.callbackQueryId,credentials:r,fetch:t?.fetch,showAlert:e.showAlert,text:e.text})},editMessageReplyMarkup(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for reply-markup edit.`);return editTelegramMessageReplyMarkup({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup})},editMessageText(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for text edit.`);return editTelegramMessageText({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup,text:e.text})},post(e){return postTelegramMessage(e,sendOne)},postEphemeral(e,t,n){return postTelegramMessage({...typeof t==`string`?{text:t}:t,ephemeral_message_parameters:{...n?.callbackQueryId===void 0?{}:{callback_query_id:n.callbackQueryId},receiver_user_id:e}},sendMessage)},request(e,n){return callTelegramApi({apiBaseUrl:t?.apiBaseUrl,body:n,botToken:r?.botToken,fetch:t?.fetch,method:e})},sendMessage(e){return postTelegramMessage(e,sendOne)},async startTyping(e=`typing`){let i=n.chatId??``;if(i)try{await sendTelegramChatAction({action:e,apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageThreadId:n.messageThreadId??void 0})}catch(e){logError(log,`Telegram typing indicator failed — swallowed`,e,{chatId:i})}}}}function shouldAnchorTelegramConversation(e){return e===`group`||e===`supergroup`}async function postTelegramMessage(e,t){let n=typeof e==`string`?{text:e}:e,r=splitTelegramMessageText(n.text),i;for(let[e,a]of r.entries()){let r=await t(e===0?{...n,text:a}:{...n.ephemeral_message_parameters===void 0?{}:{ephemeral_message_parameters:n.ephemeral_message_parameters},text:a});i===void 0&&(i=r)}return i??{id:``,raw:null}}async function verifyInbound(e,t){try{return await verifyTelegramRequest(e,{secretToken:t?.webhookVerifier?void 0:t?.webhookSecretToken,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`telegram inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){if(e.message.from?.isBot===!0)return;let t=stateFromTelegramMessage(e.message,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})},r;try{r=await e.onMessage(n,e.message)}catch(e){log.error(`message handler failed`,{error:e});return}if(r==null)return;let i=collectTelegramFileParts(e.message.attachments,e.uploadPolicy),a=buildTelegramTurnMessage(e.message,i),o=formatTelegramContextBlock({botUsername:e.config.botUsername,chatId:e.message.chat.id,chatTitle:e.message.chat.title,chatType:e.message.chat.type,isMentioned:isTelegramBotMentioned(e.message,e.config.botUsername),messageId:e.message.messageId,messageThreadId:e.message.messageThreadId,userId:e.message.from?.id,username:e.message.from?.username}),s=r.context??[];try{await e.from(telegramContinuationTokenFromState(t)).send(a,{auth:r.auth,context:[o,...s],state:t,title:r.title})}catch(e){log.error(`message delivery failed`,{error:e})}}async function dispatchCallbackQuery(e){let t=stateFromTelegramCallbackQuery(e.query,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})};if(e.query.data?.startsWith(TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX)===!0){await dispatchTelegramAuthorizationCallback({continuationToken:telegramContinuationTokenFromState(t),query:e.query,resolveSession:e.resolveSession,state:t,telegram:n});return}if(e.query.data?.startsWith(TELEGRAM_HITL_CALLBACK_PREFIX)===!0){try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Answer received.`})}catch(e){log.warn(`Telegram callback-query acknowledgement failed`,{error:e})}if(!e.query.message||!t.chatId)return;try{await e.from(telegramContinuationTokenFromState(t)).respond([telegramCallbackInputResponse(e.query.data)],{auth:defaultTelegramAuth({...e.query.message,from:e.query.from})})}catch(e){log.error(`callback query delivery failed`,{error:e})}return}if(e.config.onCallbackQuery!==void 0){try{await e.config.onCallbackQuery(n,e.query)}catch(e){log.error(`custom callback-query handler failed`,{error:e})}return}try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Unsupported action.`})}catch(e){log.warn(`Telegram unsupported callback-query acknowledgement failed`,{error:e})}}function attachTelegramDeliver(e){if(!isCompiledChannel(e))return;let t=e.adapter;t.deliver=(e,t)=>{let n=e.state,r=[...e.inputResponses??[],...telegramReplyInputResponses(n?.replyToBotMessageId,e.message)];if(r.some(isTelegramSyntheticResponse)){let n=resolveTelegramInputResponses(t.state,r);return n.length>0?{inputResponses:n,context:e.context}:e.message===void 0?void 0:{message:e.message,context:e.context}}return defaultDeliverResult(e)}}function readChatId(e){if(typeof e==`string`&&e.length>0)return e;if(typeof e==`number`&&Number.isFinite(e))return String(e)}export{telegramChannel};
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{isCompiledChannel}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{formatTelegramContextBlock,parseTelegramUpdate}from"#public/channels/telegram/inbound.js";import{answerTelegramCallbackQuery,callTelegramApi,editTelegramMessageReplyMarkup,editTelegramMessageText,sendTelegramChatAction,sendTelegramMessage,splitTelegramMessageText,telegramContinuationToken}from"#public/channels/telegram/api.js";import{TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX}from"#public/channels/telegram/authorization.js";import{TELEGRAM_HITL_CALLBACK_PREFIX,isTelegramSyntheticResponse,resolveTelegramInputResponses,telegramCallbackInputResponse,telegramReplyInputResponses}from"#public/channels/telegram/hitl.js";import{buildTelegramTurnMessage,collectTelegramFileParts,createTelegramFetchFile}from"#public/channels/telegram/attachments.js";import{defaultEvents,defaultOnMessage,defaultTelegramAuth,isTelegramBotMentioned}from"#public/channels/telegram/defaults.js";import{verifyTelegramRequest}from"#public/channels/telegram/verify.js";import{dispatchTelegramAuthorizationCallback}from"#public/channels/telegram/authorization-callback.js";import{initialTelegramState,stateFromTelegramCallbackQuery,stateFromTelegramMessage,telegramContinuationTokenFromState}from"#public/channels/telegram/state.js";import{telegramInstrumentation}from"#public/channels/telegram/audience.js";const log=createLogger(`telegram.channel`);function telegramChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=e.onMessage??defaultOnMessage,r={...defaultEvents,...e.events},i=defineChannel({kindHint:`telegram`,turnPolicy:e.turnPolicy,uploadPolicy:e.uploadPolicy,state:initialTelegramState(e.botUsername),...telegramInstrumentation,fetchFile:createTelegramFetchFile({api:e.api,credentials:e.credentials,policy:t}),context(t,n){return rebuildTelegramContext(t,n,e)},routes:[POST(e.route??`/eve/v1/telegram`,async(r,{from:i,resolveSession:a,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Telegram body is not valid JSON`,{error:e}),new Response(`ok`)}let l=parseTelegramUpdate(c);return l===null?new Response(`ok`):l.kind===`message`?(o(dispatchMessage({config:e,message:l.message,onMessage:n,uploadPolicy:t,from:i})),new Response(`ok`)):(o(dispatchCallbackQuery({config:e,query:l.callbackQuery,from:i,resolveSession:a})),new Response(`ok`))})],async receive(t,{from:n}){let r=t.target,i=readChatId(r.chatId);if(i===void 0)throw Error(`telegramChannel().receive requires target.chatId.`);let a=typeof r.messageThreadId==`number`?r.messageThreadId:void 0,o=readChatId(r.conversationId),s=r.initialMessage;if(s!==void 0&&o!==void 0)throw Error("telegramChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c={...initialTelegramState(e.botUsername),chatId:i,conversationId:o??null,messageThreadId:a??null};return s!==void 0&&await buildTelegramHandle({config:e,state:c}).sendMessage(s),n(telegramContinuationTokenFromState(c)).send(t.message,{auth:t.auth,state:c})},events:r});return attachTelegramDeliver(i),i}function rebuildTelegramContext(e,t,n){return{state:e,telegram:buildTelegramHandle({config:n,session:t,state:e})}}function buildTelegramHandle(e){let t=e.config.api,n=e.state,r=e.config.credentials;function anchor(t){let r=n.chatType??t.chatType??null;n.chatType===null&&t.chatType!==void 0&&(n.chatType=t.chatType),t.id&&shouldAnchorTelegramConversation(r)&&(n.conversationId=t.id,n.chatId&&e.session?.continuation?.alias(telegramContinuationToken({chatId:n.chatId,conversationId:t.id,messageThreadId:n.messageThreadId??void 0})))}async function sendOne(e){let t=await sendMessage(e);return anchor(t),t}async function sendMessage(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for outbound message.`);return sendTelegramMessage({apiBaseUrl:t?.apiBaseUrl,body:{...e,message_thread_id:e.message_thread_id??n.messageThreadId??void 0},credentials:r,fetch:t?.fetch,fileBaseUrl:t?.fileBaseUrl,chatId:i})}return{botUsername:n.botUsername??e.config.botUsername,chatId:n.chatId??``,chatType:n.chatType??void 0,conversationId:n.conversationId??void 0,messageThreadId:n.messageThreadId??void 0,answerCallbackQuery(e){return answerTelegramCallbackQuery({apiBaseUrl:t?.apiBaseUrl,callbackQueryId:e.callbackQueryId,credentials:r,fetch:t?.fetch,showAlert:e.showAlert,text:e.text})},editMessageReplyMarkup(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for reply-markup edit.`);return editTelegramMessageReplyMarkup({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup})},editMessageText(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for text edit.`);return editTelegramMessageText({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup,text:e.text})},post(e){return postTelegramMessage(e,sendOne)},postEphemeral(e,t,n){return postTelegramMessage({...typeof t==`string`?{text:t}:t,ephemeral_message_parameters:{...n?.callbackQueryId===void 0?{}:{callback_query_id:n.callbackQueryId},receiver_user_id:e}},sendMessage)},request(e,n){return callTelegramApi({apiBaseUrl:t?.apiBaseUrl,body:n,botToken:r?.botToken,fetch:t?.fetch,method:e})},sendMessage(e){return postTelegramMessage(e,sendOne)},async startTyping(e=`typing`){let i=n.chatId??``;if(i)try{await sendTelegramChatAction({action:e,apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageThreadId:n.messageThreadId??void 0})}catch(e){logError(log,`Telegram typing indicator failed — swallowed`,e,{chatId:i})}}}}function shouldAnchorTelegramConversation(e){return e===`group`||e===`supergroup`}async function postTelegramMessage(e,t){let n=typeof e==`string`?{text:e}:e,r=splitTelegramMessageText(n.text),i;for(let[e,a]of r.entries()){let r=await t(e===0?{...n,text:a}:{...n.ephemeral_message_parameters===void 0?{}:{ephemeral_message_parameters:n.ephemeral_message_parameters},text:a});i===void 0&&(i=r)}return i??{id:``,raw:null}}async function verifyInbound(e,t){try{return await verifyTelegramRequest(e,{secretToken:t?.webhookVerifier?void 0:t?.webhookSecretToken,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`telegram inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){if(e.message.from?.isBot===!0)return;let t=stateFromTelegramMessage(e.message,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})},r;try{r=await e.onMessage(n,e.message)}catch(e){log.error(`message handler failed`,{error:e});return}if(r==null)return;let i=collectTelegramFileParts(e.message.attachments,e.uploadPolicy),a=buildTelegramTurnMessage(e.message,i),o=formatTelegramContextBlock({botUsername:e.config.botUsername,chatId:e.message.chat.id,chatTitle:e.message.chat.title,chatType:e.message.chat.type,isMentioned:isTelegramBotMentioned(e.message,e.config.botUsername),messageId:e.message.messageId,messageThreadId:e.message.messageThreadId,userId:e.message.from?.id,username:e.message.from?.username}),s=r.context??[];try{await e.from(telegramContinuationTokenFromState(t)).send(a,{auth:r.auth,context:[o,...s],state:t,title:r.title})}catch(e){log.error(`message delivery failed`,{error:e})}}async function dispatchCallbackQuery(e){let t=stateFromTelegramCallbackQuery(e.query,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})};if(e.query.data?.startsWith(TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX)===!0){await dispatchTelegramAuthorizationCallback({continuationToken:telegramContinuationTokenFromState(t),query:e.query,resolveSession:e.resolveSession,state:t,telegram:n});return}if(e.query.data?.startsWith(TELEGRAM_HITL_CALLBACK_PREFIX)===!0){try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Answer received.`})}catch(e){log.warn(`Telegram callback-query acknowledgement failed`,{error:e})}if(!e.query.message||!t.chatId)return;try{await e.from(telegramContinuationTokenFromState(t)).respond([telegramCallbackInputResponse(e.query.data)],{auth:defaultTelegramAuth({...e.query.message,from:e.query.from})})}catch(e){log.error(`callback query delivery failed`,{error:e})}return}if(e.config.onCallbackQuery!==void 0){try{await e.config.onCallbackQuery(n,e.query)}catch(e){log.error(`custom callback-query handler failed`,{error:e})}return}try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Unsupported action.`})}catch(e){log.warn(`Telegram unsupported callback-query acknowledgement failed`,{error:e})}}function attachTelegramDeliver(e){if(!isCompiledChannel(e))return;let t=e.adapter;t.deliver=(e,t)=>{let n=e.state,r=[...e.inputResponses??[],...telegramReplyInputResponses(n?.replyToBotMessageId,e.message)];if(r.some(isTelegramSyntheticResponse)){let n=resolveTelegramInputResponses(t.state,r);return n.length>0?{inputResponses:n,context:e.context}:e.message===void 0?void 0:{message:e.message,context:e.context}}return defaultDeliverResult(e)}}function readChatId(e){if(typeof e==`string`&&e.length>0)return e;if(typeof e==`number`&&Number.isFinite(e))return String(e)}export{telegramChannel};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{displayProperName}from"#shared/display-name.js";import{renderTextInputRequest}from"#channel/resolve-text.js";import{promptQueueEvents}from"#channel/prompt-queue.js";function defaultTwilioAuth(e){let t={channel:e.channel,from:e.from};return e.to!==void 0&&(t.to=e.to),{attributes:t,authenticator:`twilio-webhook`,issuer:`twilio`,principalId:`twilio:${e.from}`,principalType:`user`}}function defaultOnText(e,t){return{auth:defaultTwilioAuth({channel:`text`,from:t.from,to:t.to})}}function defaultOnVoice(e,t){return{}}function defaultOnVoiceTranscription(e,t){return{auth:defaultTwilioAuth({channel:`voice`,from:t.from,to:t.to})}}const defaultEvents={async"message.completed"(e,t,n){e.finishReason!==`tool-calls`&&e.message&&await t.twilio.sendMessage(e.message)},...promptQueueEvents(showPrompt),async"authorization.required"(e,t,n){if(e.candidateId!==void 0)return;let r=e.authorization;await t.twilio.sendMessage([`Sign in to ${r?.displayName??displayProperName(e.name)} to continue.`,r?.instructions,r?.userCode?`Code: ${r.userCode}`:void 0,r?.url].filter(e=>e!==void 0&&e.length>0).join(`
|
|
2
2
|
|
|
3
|
-
`))},async"authorization.completed"(e,t,n){e.candidateId===void 0&&await t.twilio.sendMessage(renderAuthorizationOutcome({displayName:e.authorization?.displayName??displayProperName(e.name),outcome:e.outcome,reason:e.reason}))},async"turn.failed"(e,t,n){let r=formatErrorHint(e),i=extractErrorId(e.details);await t.twilio.sendMessage([`I hit an error while handling your request${r}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...i?[``,`Error id: ${i}`]:[]].join(`
|
|
3
|
+
`))},async"authorization.completed"(e,t,n){e.candidateId===void 0&&await t.twilio.sendMessage(renderAuthorizationOutcome({displayName:e.authorization?.displayName??displayProperName(e.name),outcome:e.outcome,reason:e.reason}))},async"turn.failed"(e,t,n){if(e.terminal)return;let r=formatErrorHint(e),i=extractErrorId(e.details);await t.twilio.sendMessage([`I hit an error while handling your request${r}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...i?[``,`Error id: ${i}`]:[]].join(`
|
|
4
4
|
`))},async"session.failed"(e,t){let n=formatErrorHint(e),r=extractErrorId(e.details);await t.twilio.sendMessage([`This session could not recover from an error${n}.`,``,`Start a new message to continue.`,...r?[``,`Error id: ${r}`]:[]].join(`
|
|
5
5
|
`))}};async function showPrompt(e,t){let n=renderTextInputRequest(t);if((t.options??[]).length===0){await e.twilio.sendMessage(n);return}let r=t.allowFreeform===!0?`Reply with a number, or with your own answer.`:`Reply with a number to choose.`;await e.twilio.sendMessage(`${n}\n\n${r}`)}function renderAuthorizationOutcome(e){if(e.outcome===`authorized`)return`${e.displayName} connected.`;if(e.outcome===`declined`)return`${e.displayName} sign-in cancelled.`;let t=e.outcome===`timed-out`?`timed out`:e.outcome,n=e.reason===void 0?``:` (${e.reason})`;return`${e.displayName} sign-in ${t}${n}.`}export{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createMetadataAudienceProjector}from"#channel/audience.js";import{CHANNEL_SENTINEL}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{SessionStrandedError}from"#channel/session-stranded-error.js";import{normalizeChannelCors}from"#channel/cors.js";import{HTTP_ADAPTER_KIND}from"#channel/http.js";import{DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT,WS}from"#channel/routes.js";const DISABLED_ROUTE_SENTINEL_KIND=`eve:disabled-channel`;function disableRoute(){return{kind:DISABLED_ROUTE_SENTINEL_KIND}}function isDisabledRouteSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_ROUTE_SENTINEL_KIND}function defineChannel(e){let t=buildAdapter(e),n=normalizeChannelCors(e.cors);return{__kind:CHANNEL_SENTINEL,routes:e.routes,adapter:t,cors:n,receive:e.receive,turnPolicy:e.turnPolicy}}const eventTypes=Object.keys({"approval.candidate":null,"approval.settled":null,"context.cleared":null,"compaction.requested":null,"compaction.completed":null,"turn.started":null,"actions.requested":null,"action.partial":null,"action.result":null,"message.completed":null,"message.appended":null,"reasoning.appended":null,"reasoning.completed":null,"step.started":null,"step.completed":null,"input.requested":null,"input.resolved":null,"task.started":null,"task.settled":null,"turn.waiting":null,"turn.failed":null,"turn.completed":null,"turn.cancelled":null,"session.failed":null,"session.completed":null,"session.waiting":null,"authorization.required":null,"authorization.completed":null});function buildAdapter(e){let t=e.state!=null,n=e.context!=null,r=e.fetchFile!==void 0,i=e.metadata,a=i!==void 0,o=e.audience,s=t||n||a,
|
|
1
|
+
import{createMetadataAudienceProjector}from"#channel/audience.js";import{CHANNEL_SENTINEL}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{SessionStrandedError}from"#channel/session-stranded-error.js";import{normalizeChannelCors}from"#channel/cors.js";import{HTTP_ADAPTER_KIND}from"#channel/http.js";import{DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT,WS}from"#channel/routes.js";const DISABLED_ROUTE_SENTINEL_KIND=`eve:disabled-channel`;function disableRoute(){return{kind:DISABLED_ROUTE_SENTINEL_KIND}}function isDisabledRouteSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_ROUTE_SENTINEL_KIND}function defineChannel(e){let t=buildAdapter(e),n=normalizeChannelCors(e.cors);return{__kind:CHANNEL_SENTINEL,routes:e.routes,adapter:t,cors:n,receive:e.receive,turnPolicy:e.turnPolicy}}const eventTypes=Object.keys({"approval.candidate":null,"approval.settled":null,"context.cleared":null,"compaction.requested":null,"compaction.completed":null,"turn.started":null,"actions.requested":null,"action.partial":null,"action.result":null,"message.completed":null,"message.appended":null,"reasoning.appended":null,"reasoning.completed":null,"step.started":null,"step.completed":null,"input.requested":null,"input.resolved":null,"task.started":null,"task.settled":null,"turn.waiting":null,"turn.failed":null,"turn.completed":null,"turn.cancelled":null,"session.failed":null,"session.completed":null,"session.waiting":null,"authorization.required":null,"authorization.completed":null});function buildAdapter(e){let t=e.state!=null,n=e.context!=null,r=e.fetchFile!==void 0,i=e.metadata,a=i!==void 0,o=e.audience,s=e.uploadPolicy===void 0?void 0:mergeUploadPolicy(e.uploadPolicy),c=t||n||a||s!==void 0,l={},u=!1,d={kind:e.kindHint??`defineChannel`},f=e.events;for(let e of eventTypes){let t=f?.[e];t&&(u=!0,l[e]=(n,r)=>{let{session:i,...a}=r,o={...a,continuation:i?.continuation===void 0?void 0:{token:i.continuation.token,alias:e=>i.continuation?.alias(e)}};if(e===`session.failed`)return t(n,o);let s=buildCallbackContext();return t(n,o,s)})}return!c&&!u&&!r?{kind:e.kindHint??HTTP_ADAPTER_KIND,...o===void 0?void 0:{instrumentation:{audience:o}}}:{kind:e.kindHint??`defineChannel`,state:t?{...e.state}:{},fetchFile:e.fetchFile,uploadPolicy:s,instrumentation:i===void 0&&o===void 0?void 0:{...i===void 0?void 0:{metadata(e){let{audience:t,...n}=i(e);return n}},...o===void 0?i===void 0?void 0:{audience:createMetadataAudienceProjector(d,i)}:{audience:o}},createAdapterContext(t){let r=t.state,i=t.session;return{...n?e.context(r,i):{},state:r,ctx:t.ctx,session:i}},deliver(t,n){return e.deliver===void 0?defaultDeliverResult(t):e.deliver(t,n)},...l}}export{DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT,SessionStrandedError,WS,defineChannel,disableRoute,isDisabledRouteSentinel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAdapterKind}from"#channel/adapter.js";import{SCHEDULE_ADAPTER}from"#channel/schedule.js";import{HTTP_ADAPTER}from"#channel/http.js";import{SUBAGENT_ADAPTER}from"#subagents/adapter.js";import{RuntimeRegistryError}from"#internal/runtime-registry.js";const FRAMEWORK_ADAPTERS=[HTTP_ADAPTER,SUBAGENT_ADAPTER,SCHEDULE_ADAPTER],ADAPTER_NON_EVENT_FIELDS=new Set([`kind`,`state`,`deliver`,`createAdapterContext`,`fetchFile`,`instrumentation`]);function createRuntimeAdapterRegistry(e){let t=new Map,n=new Set;for(let e of FRAMEWORK_ADAPTERS){let r=requireAdapterKind(e);n.add(r),t.set(r,e)}for(let r of e.channels){if(r.adapter===void 0)continue;let e={logicalPath:r.logicalPath,sourceId:r.sourceId},i=r.adapter,a=requireAdapterKind(i,e);if(n.has(a)){if(carriesAdapterBehavior(i))throw new RuntimeRegistryError(`adapter`,`Channel adapter kind "${a}" is reserved by the framework. A route-declared adapter may share a framework kind only as a pass-through with no \`deliver\` hook, event handlers, \`attachments\` resolver, or \`createAdapterContext\` factory. Use a custom \`kind\` to add channel-specific behavior.`,{...e,entryName:a});continue}t.set(a,i)}return{adaptersByKind:t}}function deserializeRuntimeAdapter(e,t){let n=t,r=e.adaptersByKind.get(n.kind);if(r===void 0)throw Error(`Unknown adapter kind: "${n.kind}". Declare the adapter on the route that starts this session so the runtime can rehydrate it.`);return{...r,state:n.state}}function requireAdapterKind(e,t){let n=getAdapterKind(e);if(typeof n!=`string`||n.length===0)throw new RuntimeRegistryError(`adapter`,"Adapters must declare a non-empty `kind` field.",{entryName:`unknown`,logicalPath:t?.logicalPath,sourceId:t?.sourceId});return n}function carriesAdapterBehavior(e){if(e.deliver!==void 0||e.fetchFile!==void 0||e.createAdapterContext!==void 0)return!0;for(let[t,n]of Object.entries(e))if(!ADAPTER_NON_EVENT_FIELDS.has(t)&&typeof n==`function`)return!0;return!1}export{createRuntimeAdapterRegistry,deserializeRuntimeAdapter};
|
|
1
|
+
import{getAdapterKind}from"#channel/adapter.js";import{SCHEDULE_ADAPTER}from"#channel/schedule.js";import{HTTP_ADAPTER}from"#channel/http.js";import{SUBAGENT_ADAPTER}from"#subagents/adapter.js";import{RuntimeRegistryError}from"#internal/runtime-registry.js";const FRAMEWORK_ADAPTERS=[HTTP_ADAPTER,SUBAGENT_ADAPTER,SCHEDULE_ADAPTER],ADAPTER_NON_EVENT_FIELDS=new Set([`kind`,`state`,`deliver`,`createAdapterContext`,`fetchFile`,`instrumentation`,`uploadPolicy`]);function createRuntimeAdapterRegistry(e){let t=new Map,n=new Set;for(let e of FRAMEWORK_ADAPTERS){let r=requireAdapterKind(e);n.add(r),t.set(r,e)}for(let r of e.channels){if(r.adapter===void 0)continue;let e={logicalPath:r.logicalPath,sourceId:r.sourceId},i=r.adapter,a=requireAdapterKind(i,e);if(n.has(a)){if(carriesAdapterBehavior(i))throw new RuntimeRegistryError(`adapter`,`Channel adapter kind "${a}" is reserved by the framework. A route-declared adapter may share a framework kind only as a pass-through with no \`deliver\` hook, event handlers, \`attachments\` resolver, or \`createAdapterContext\` factory. Use a custom \`kind\` to add channel-specific behavior.`,{...e,entryName:a});continue}t.set(a,i)}return{adaptersByKind:t}}function deserializeRuntimeAdapter(e,t){let n=t,r=e.adaptersByKind.get(n.kind);if(r===void 0)throw Error(`Unknown adapter kind: "${n.kind}". Declare the adapter on the route that starts this session so the runtime can rehydrate it.`);return{...r,state:n.state}}function requireAdapterKind(e,t){let n=getAdapterKind(e);if(typeof n!=`string`||n.length===0)throw new RuntimeRegistryError(`adapter`,"Adapters must declare a non-empty `kind` field.",{entryName:`unknown`,logicalPath:t?.logicalPath,sourceId:t?.sourceId});return n}function carriesAdapterBehavior(e){if(e.deliver!==void 0||e.fetchFile!==void 0||e.uploadPolicy!==void 0||e.createAdapterContext!==void 0)return!0;for(let[t,n]of Object.entries(e))if(!ADAPTER_NON_EVENT_FIELDS.has(t)&&typeof n==`function`)return!0;return!1}export{createRuntimeAdapterRegistry,deserializeRuntimeAdapter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"../update/package-json.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{readFile}from"node:fs/promises";import{join}from"node:path";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(e){let t=e.packageManager??`pnpm`,n=join(e.projectRoot,`package.json`);if(!await pathExists(n))throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let r;try{r=JSON.parse(await readFile(n,`utf8`))}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Cannot add an eve agent because "${n}" is not valid JSON. No files were changed. Fix the file, then retry eve init. ${t}`)}let i=agentTemplateFiles(e.model,e.reasoning),a=[];for(let t of Object.keys(i))await pathExists(join(e.projectRoot,t))&&a.push(t);if(a.length===0&&await pathExists(join(e.projectRoot,`agent`))&&a.push(`agent/`),a.length>0)throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it already has: ${a.join(`, `)}.`);let o=resolveEvePackageContract(e.evePackage),s=resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.
|
|
1
|
+
import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"../update/package-json.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{readFile}from"node:fs/promises";import{join}from"node:path";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(e){let t=e.packageManager??`pnpm`,n=join(e.projectRoot,`package.json`);if(!await pathExists(n))throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let r;try{r=JSON.parse(await readFile(n,`utf8`))}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Cannot add an eve agent because "${n}" is not valid JSON. No files were changed. Fix the file, then retry eve init. ${t}`)}let i=agentTemplateFiles(e.model,e.reasoning),a=[];for(let t of Object.keys(i))await pathExists(join(e.projectRoot,t))&&a.push(t);if(a.length===0&&await pathExists(join(e.projectRoot,`agent`))&&a.push(`agent/`),a.length>0)throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it already has: ${a.join(`, `)}.`);let o=resolveEvePackageContract(e.evePackage),s=resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.137`),c=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`2.2.0`),l=resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.5.4`),u=[];for(let[t,n]of Object.entries(i)){let r=join(e.projectRoot,t);await writeTextFile(r,n),u.push(r)}let d={"@vercel/connect":c,ai:s,eve:formatEveDependencySpecifier(o.version),zod:l},f={};for(let[e,t]of Object.entries(d))hasDeclaredDependency(r,e)||(f[e]=t);let p={};Object.keys(f).length>0&&(p.dependencies=f),isPackageManagerWorkspaceMember(t,e.projectRoot)||(p.nodeEngineRequirement=o.nodeEngine);let m=await patchPackageJson(n,p),h=await patchWorkspaceRootPackageJson(t,e.projectRoot,{nodeEngineRequirement:o.nodeEngine}),g=h.nodeEngineOverride??m.nodeEngineOverride,_=await applyPackageManagerWorkspaceConfiguration({packageManager:t,projectRoot:e.projectRoot});return{filesWritten:u,dependenciesAdded:Object.keys(f).sort(),nodeEngineOverride:g,configurationFilesChanged:[...m.changed?[n]:[],...h.changed&&h.path!==void 0?[h.path]:[],..._.filesWritten]}}export{addAgentToProject};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{DEFAULT_CONNECT_PACKAGE_VERSION,resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_CHANNEL_TEMPLATES}from"./web-template.js";import{AGENT_INSTRUCTIONS_TEMPLATE}from"./instructions-template.js";import{SCAFFOLDED_AGENT_PATHS}from"./agent-paths.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{DEFAULT_CONNECT_PACKAGE_VERSION,resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_CHANNEL_TEMPLATES}from"./web-template.js";import{AGENT_INSTRUCTIONS_TEMPLATE}from"./instructions-template.js";import{SCAFFOLDED_AGENT_PATHS}from"./agent-paths.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.137`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.77.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{[SCAFFOLDED_AGENT_PATHS.config]:renderAgentTemplate(e,t),[SCAFFOLDED_AGENT_PATHS.channel]:WEB_CHANNEL_TEMPLATES.default,[SCAFFOLDED_AGENT_PATHS.instructions]:AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
|
|
2
2
|
|
|
3
3
|
export default defineAgent({
|
|
4
4
|
model: "__EVE_INIT_MODEL__",
|
|
@@ -114,4 +114,4 @@ __EVE_INIT_REASONING__ modelOptions: {
|
|
|
114
114
|
},
|
|
115
115
|
},
|
|
116
116
|
});
|
|
117
|
-
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(e.includeRootOnlyPackageJsonFields)}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let n=await readdir(e),r=blockingCreateInPlaceEntries(n);if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let t=resolve(e.targetDirectory??process.cwd(),e.projectName),n=e.projectName===`.`,r=e.overwriteExisting??!1,i=e.byokProvider??!1,a=e.packageManager??`pnpm`,o=resolveEvePackageContract(e.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c=resolve(e.workspaceProbeDirectory??t),l=isPackageManagerWorkspaceMember(a,c);if(n)await assertCanCreateInPlace(t,r);else if(await pathExists(t))throw Error(`Cannot create project because "${t}" already exists.`);let u={appName:basename(t),model:e.model,reasoning:e.reasoning,eveVersion:o.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.
|
|
117
|
+
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(e.includeRootOnlyPackageJsonFields)}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let n=await readdir(e),r=blockingCreateInPlaceEntries(n);if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let t=resolve(e.targetDirectory??process.cwd(),e.projectName),n=e.projectName===`.`,r=e.overwriteExisting??!1,i=e.byokProvider??!1,a=e.packageManager??`pnpm`,o=resolveEvePackageContract(e.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c=resolve(e.workspaceProbeDirectory??t),l=isPackageManagerWorkspaceMember(a,c);if(n)await assertCanCreateInPlace(t,r);else if(await pathExists(t))throw Error(`Cannot create project because "${t}" already exists.`);let u={appName:basename(t),model:e.model,reasoning:e.reasoning,eveVersion:o.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.137`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`2.2.0`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.5.4`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,e.typescriptPackageVersion??`7.0.2`),nodeTypesVersion:s,nodeEngine:s};await mkdir(t,{recursive:!0});for(let[a,o]of Object.entries(templateFiles({byokProvider:i,includeRootOnlyPackageJsonFields:!l}))){let i=`${t}/${a}`,s=await pathExists(i);await writeTextFile(i,renderTemplate(o,u),{force:n&&r}),s&&await e.onOverwriteFile?.(i)}return await applyPackageManagerWorkspaceConfiguration({packageManager:a,projectRoot:t,workspaceProbeRoot:c,onWorkspaceRootMutation:e.onWorkspaceRootMutation}),await patchWorkspaceRootPackageJson(a,c,{nodeEngineRequirement:o.nodeEngine,onWorkspaceRootMutation:e.onWorkspaceRootMutation}),t}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,ROOT_ONLY_PACKAGE_JSON_TEMPLATE_SUFFIX,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_EVE_PACKAGE_CONTRACT}from"../create/project.js";function resolveWebPackageVersions(e,t){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`^7.0.
|
|
1
|
+
import{DEFAULT_EVE_PACKAGE_CONTRACT}from"../create/project.js";function resolveWebPackageVersions(e,t){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`^7.0.137`,betterAuthPackageVersion:e?.betterAuthPackageVersion??`1.6.26`,nextPackageVersion:e?.nextPackageVersion??(t===`sign-in-with-vercel`?`16.3.0`:`16.3.4`),reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.5.4`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}export{resolveWebPackageVersions};
|
|
@@ -35,8 +35,9 @@ export type AnthropicPromptCacheTtl = "5m" | "1h";
|
|
|
35
35
|
export declare const ANTHROPIC_PROMPT_CACHE_TTLS: readonly AnthropicPromptCacheTtl[];
|
|
36
36
|
/**
|
|
37
37
|
* Provider-agnostic reasoning effort forwarded to the AI SDK model call.
|
|
38
|
+
* The AI SDK's `max` level is not supported yet: eve's manifest and agent info list the levels.
|
|
38
39
|
*/
|
|
39
|
-
export type AgentReasoningDefinition = NonNullable<CallSettings["reasoning"]>;
|
|
40
|
+
export type AgentReasoningDefinition = Exclude<NonNullable<CallSettings["reasoning"]>, "max">;
|
|
40
41
|
/**
|
|
41
42
|
* How an agent's model is reached at runtime, decided at compile time from the
|
|
42
43
|
* authored model value.
|
|
@@ -5,6 +5,7 @@ import type { RouteDefinition } from "#channel/routes.js";
|
|
|
5
5
|
import type { Session, SessionHandle } from "#channel/session.js";
|
|
6
6
|
import type { DeliverPayload, SessionAuthContext, TurnPolicy } from "#channel/types.js";
|
|
7
7
|
import type { StepInput } from "#harness/types.js";
|
|
8
|
+
import type { UploadPolicyInput } from "#public/channels/upload-policy.js";
|
|
8
9
|
import type { AudienceContext } from "#shared/conversation-context.js";
|
|
9
10
|
import type { ChannelAudience } from "#shared/channel-audience.js";
|
|
10
11
|
/**
|
|
@@ -24,6 +25,8 @@ export interface FetchFileResult {
|
|
|
24
25
|
/** Runtime context supplied while resolving a channel-owned file URL. */
|
|
25
26
|
export interface FetchFileContext {
|
|
26
27
|
readonly state: Readonly<Record<string, unknown>>;
|
|
28
|
+
/** The session the attachment arrived in, for checking it against the session's caller. */
|
|
29
|
+
readonly session: SessionHandle;
|
|
27
30
|
}
|
|
28
31
|
export type FetchFileFunction = (url: string, context?: FetchFileContext) => Promise<Buffer | FetchFileResult | null>;
|
|
29
32
|
/**
|
|
@@ -75,12 +78,21 @@ export interface GenericChannelDefinition<TEvents, TState = undefined, TCtx = vo
|
|
|
75
78
|
receive?(input: GenericReceiveInput<TReceiveTarget>, ctx: ChannelReceiveContext<TState>): Promise<Session>;
|
|
76
79
|
readonly events?: TEvents;
|
|
77
80
|
/**
|
|
78
|
-
* Fetches bytes for a
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* the
|
|
81
|
+
* Fetches bytes for a link encountered on a `FilePart.data` by the staging
|
|
82
|
+
* pipeline. Return bytes / {@link FetchFileResult} to stage the file to the
|
|
83
|
+
* sandbox, or `null` when the link is not this channel's: eve then downloads
|
|
84
|
+
* a public `https:` link itself, and any other link reaches the model as a
|
|
85
|
+
* note. A provider never fetches an attachment.
|
|
82
86
|
*/
|
|
83
87
|
readonly fetchFile?: FetchFileFunction;
|
|
88
|
+
/**
|
|
89
|
+
* Size cap and media types for every file eve stages for this channel,
|
|
90
|
+
* checked against the final bytes and the media type they prove, including
|
|
91
|
+
* links eve downloads itself. A file that breaks the policy reaches the
|
|
92
|
+
* model as a note. Omit to check nothing beyond your own `fetchFile`; eve's
|
|
93
|
+
* own downloads then stop at the 25 MB framework default.
|
|
94
|
+
*/
|
|
95
|
+
readonly uploadPolicy?: UploadPolicyInput;
|
|
84
96
|
/**
|
|
85
97
|
* Channel-owned metadata exposed to instrumentation callbacks. This is the
|
|
86
98
|
* channel's public observability surface, not a dump of durable adapter state,
|
|
@@ -3,6 +3,5 @@ export { type EveAgentReducer, type EveAgentReducerEvent, type ClientInputRespon
|
|
|
3
3
|
export { conversationReducer } from "#client/conversation-reducer.js";
|
|
4
4
|
export { openConversationInputs } from "#client/conversation-state.js";
|
|
5
5
|
export { toolCallState, type ToolCallState, type ToolCallStatus } from "#client/tool-call-state.js";
|
|
6
|
-
export type { SessionAuthorization, SessionCall, SessionCallStatus, SessionProjection, } from "#protocol/session-projection.js";
|
|
7
6
|
export type { AgentObservation, ConversationAgentSession, ConversationInput, ConversationState, ConversationTask, ConversationTaskCall, ConversationTurn, } from "#client/conversation-state.js";
|
|
8
7
|
export { defaultMessageReducer, type EveAuthorizationChallenge, type EveAuthorizationOutcome, type EveAuthorizationPart, type EveMessageData, type EveDynamicToolPart, type EveMessageInputRequest, type EveMessage, type EveMessageMetadata, type EveMessagePart, type EveMessageToolMetadata, } from "#client/message-reducer.js";
|
package/dist/src/svelte/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as conversationProjection, i as openConversationInputs, n as conversationReducer, o as callStatus, r as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-
|
|
1
|
+
import { a as conversationProjection, i as openConversationInputs, n as conversationReducer, o as callStatus, r as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-BSYe_Re7.js";
|
|
2
2
|
|
|
3
3
|
//#region src/client/tool-call-state.ts
|
|
4
4
|
function toolCallState(conversation, callId, options = {}) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
async function executeAskQuestionTool(e,t){"use workflow";return toAskQuestionOutput(await t.ask(toAskQuestionRequest(e)))}function toAskQuestionRequest(e){let t=e.options?.map(e=>({description:e.description,id:e.label,label:e.label}));return{allowFreeform:!0,display:t===void 0?`text`:`select`,prompt:e.question,...t!==void 0&&{options:t}}}function toAskQuestionOutput(e){switch(e.status){case`answered`:return{answer:e.optionId??e.text??``,status:`answered`};case`cancelled`:return{interrupted:!0};case`unavailable`:return{status:`unavailable`}}}executeAskQuestionTool.workflowId=`workflow//eve@0.
|
|
1
|
+
async function executeAskQuestionTool(e,t){"use workflow";return toAskQuestionOutput(await t.ask(toAskQuestionRequest(e)))}function toAskQuestionRequest(e){let t=e.options?.map(e=>({description:e.description,id:e.label,label:e.label}));return{allowFreeform:!0,display:t===void 0?`text`:`select`,prompt:e.question,...t!==void 0&&{options:t}}}function toAskQuestionOutput(e){switch(e.status){case`answered`:return{answer:e.optionId??e.text??``,status:`answered`};case`cancelled`:return{interrupted:!0};case`unavailable`:return{status:`unavailable`}}}executeAskQuestionTool.workflowId=`workflow//eve@0.77.0//executeAskQuestionTool`;export{executeAskQuestionTool,toAskQuestionOutput,toAskQuestionRequest};
|
|
@@ -6,10 +6,11 @@ export interface ReadFileToolInput {
|
|
|
6
6
|
}
|
|
7
7
|
export interface ReadFileToolOutput {
|
|
8
8
|
content: string;
|
|
9
|
-
/** Set when the file is a PNG, JPEG, GIF, or WebP image the model
|
|
10
|
-
|
|
9
|
+
/** Set when the file is a PNG, JPEG, GIF, or WebP image or a PDF that the model reads natively. */
|
|
10
|
+
file?: {
|
|
11
11
|
height?: number;
|
|
12
12
|
mediaType: string;
|
|
13
|
+
pages?: number;
|
|
13
14
|
size: number;
|
|
14
15
|
width?: number;
|
|
15
16
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{frameworkTool}from"./framework-tool.js";import{contextStorage}from"#context/container.js";import{SandboxKey}from"#context/keys.js";import{basename}from"node:path";import{defineJsonSchema}from"#tools/schema.js";import{defineTool}from"#tools/definition.js";import{resolveAbsoluteFilePath}from"#execution/sandbox/require-sandbox.js";import{toolLabel}from"#tools/tool-label.js";import{toolOutput,toolOutputPart}from"#tools/model-output.js";import{executeReadFileOnSandbox}from"#execution/sandbox/read-file.js";const READ_FILE_INPUT_SCHEMA=defineJsonSchema({type:`object`,properties:{filePath:{type:`string`,description:`The absolute path to the file to read. A leading $HOME is supported.`},limit:{type:`integer`,minimum:1,description:`Maximum number of lines to return. Defaults to 2000.`},offset:{type:`integer`,minimum:1,description:`1-based line number to start from. Defaults to 1.`}},required:[`filePath`],additionalProperties:!1}),READ_FILE_OUTPUT_SCHEMA=defineJsonSchema({type:`object`,properties:{content:{type:`string`},
|
|
2
|
-
`),async execute(e,t){return await executeReadFileOnSandbox(await t.getSandbox(),e)},inputSchema:READ_FILE_INPUT_SCHEMA,outputSchema:READ_FILE_OUTPUT_SCHEMA,async toModelOutput(e){if(e.
|
|
1
|
+
import{frameworkTool}from"./framework-tool.js";import{contextStorage}from"#context/container.js";import{SandboxKey}from"#context/keys.js";import{basename}from"node:path";import{defineJsonSchema}from"#tools/schema.js";import{defineTool}from"#tools/definition.js";import{resolveAbsoluteFilePath}from"#execution/sandbox/require-sandbox.js";import{toolLabel}from"#tools/tool-label.js";import{toolOutput,toolOutputPart}from"#tools/model-output.js";import{executeReadFileOnSandbox}from"#execution/sandbox/read-file.js";const READ_FILE_INPUT_SCHEMA=defineJsonSchema({type:`object`,properties:{filePath:{type:`string`,description:`The absolute path to the file to read. A leading $HOME is supported.`},limit:{type:`integer`,minimum:1,description:`Maximum number of lines to return. Defaults to 2000.`},offset:{type:`integer`,minimum:1,description:`1-based line number to start from. Defaults to 1.`}},required:[`filePath`],additionalProperties:!1}),READ_FILE_OUTPUT_SCHEMA=defineJsonSchema({type:`object`,properties:{content:{type:`string`},file:{type:`object`,properties:{height:{type:`integer`,minimum:1},mediaType:{type:`string`},pages:{type:`integer`,minimum:1},size:{type:`integer`,minimum:0},width:{type:`integer`,minimum:1}},required:[`mediaType`,`size`],additionalProperties:!1},nextOffset:{type:`integer`,minimum:1},path:{type:`string`},totalLines:{type:`integer`,minimum:0},truncated:{type:`boolean`}},required:[`content`,`path`,`totalLines`,`truncated`],additionalProperties:!1}),readFile=frameworkTool(defineTool({label:{start:e=>toolLabel(`Read`,e.filePath)},description:[`Read a file from the local filesystem. If the path does not exist, an error is returned.`,``,`Usage:`,`- The filePath parameter should be an absolute path or begin with $HOME/.`,`- By default, this tool returns up to 2000 lines from the start of the file.`,`- The offset parameter is the line number to start from (1-indexed).`,`- To read later sections, call this tool again with a larger offset.`,'- Contents are returned with each line prefixed by its line number as `<line>: <content>`. For example, if a file has contents "foo\\n", you will receive "1: foo\\n".',`- Any line longer than 2000 characters is truncated.`,"- PNG, JPEG, GIF, and WebP images up to 3 MiB and PDFs up to 20 MiB are shown to you as files, including files named in `Attached file <path>` references.",`- Call this tool in parallel when you know there are multiple files you want to read.`,`- Avoid tiny repeated slices (30 line chunks). If you need more context, read a larger window.`].join(`
|
|
2
|
+
`),async execute(e,t){return await executeReadFileOnSandbox(await t.getSandbox(),e)},inputSchema:READ_FILE_INPUT_SCHEMA,outputSchema:READ_FILE_OUTPUT_SCHEMA,async toModelOutput(e){if(e.file===void 0)return toolOutput.json(e);let t=await contextStorage.getStore()?.get(SandboxKey)?.get(),n=t==null?null:await t.readBinaryFile({path:await resolveAbsoluteFilePath(t,e.path)});return n===null?toolOutput.text(`${e.content} The file could not be loaded.`):n.byteLength===e.file.size?toolOutput.content([toolOutputPart.text(e.content),toolOutputPart.file(Buffer.from(n).toString(`base64`),{filename:basename(e.path),mediaType:e.file.mediaType})]):toolOutput.text(`${e.content} The file changed after it was read; read it again.`)}}));export{READ_FILE_INPUT_SCHEMA,READ_FILE_OUTPUT_SCHEMA,readFile as default,readFile};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{sleep}from"#compiled/@workflow/core/index.js";async function executeSleepTool(e,t){"use workflow";let n=new Promise(e=>t.abortSignal.addEventListener(`abort`,()=>e(`interrupted`),{once:!0})),r=sleep(Math.ceil(e.seconds*1e3)).then(()=>`elapsed`);return await Promise.race([r,n])===`elapsed`?{waitedSeconds:e.seconds}:{interrupted:!0}}executeSleepTool.workflowId=`workflow//eve@0.
|
|
1
|
+
import{sleep}from"#compiled/@workflow/core/index.js";async function executeSleepTool(e,t){"use workflow";let n=new Promise(e=>t.abortSignal.addEventListener(`abort`,()=>e(`interrupted`),{once:!0})),r=sleep(Math.ceil(e.seconds*1e3)).then(()=>`elapsed`);return await Promise.race([r,n])===`elapsed`?{waitedSeconds:e.seconds}:{interrupted:!0}}executeSleepTool.workflowId=`workflow//eve@0.77.0//executeSleepTool`;export{executeSleepTool};
|
package/dist/src/vue/index.d.ts
CHANGED
|
@@ -3,6 +3,5 @@ export { type EveAgentReducer, type EveAgentReducerEvent, type ClientInputRespon
|
|
|
3
3
|
export { conversationReducer } from "#client/conversation-reducer.js";
|
|
4
4
|
export { openConversationInputs } from "#client/conversation-state.js";
|
|
5
5
|
export { toolCallState, type ToolCallState, type ToolCallStatus } from "#client/tool-call-state.js";
|
|
6
|
-
export type { SessionAuthorization, SessionCall, SessionCallStatus, SessionProjection, } from "#protocol/session-projection.js";
|
|
7
6
|
export type { AgentObservation, ConversationAgentSession, ConversationInput, ConversationState, ConversationTask, ConversationTaskCall, ConversationTurn, } from "#client/conversation-state.js";
|
|
8
7
|
export { defaultMessageReducer, type EveAuthorizationChallenge, type EveAuthorizationOutcome, type EveAuthorizationPart, type EveMessageData, type EveDynamicToolPart, type EveMessageInputRequest, type EveMessage, type EveMessageMetadata, type EveMessagePart, type EveMessageToolMetadata, } from "#client/message-reducer.js";
|
package/dist/src/vue/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as conversationProjection, i as openConversationInputs, n as conversationReducer, o as callStatus, r as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-
|
|
1
|
+
import { a as conversationProjection, i as openConversationInputs, n as conversationReducer, o as callStatus, r as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-B8brxCk-.js";
|
|
2
2
|
|
|
3
3
|
//#region src/client/tool-call-state.ts
|
|
4
4
|
function toolCallState(conversation, callId, options = {}) {
|
|
@@ -245,7 +245,7 @@ bot.onNewMention(async (thread, message) => {
|
|
|
245
245
|
});
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
-
When the adapter can download an attachment (it sets `fetchData`, as the Slack, Google Chat, WhatsApp, and Twilio adapters do), eve downloads it with the adapter's credentials when the turn runs, not in the webhook, and passes the bytes. Platform file URLs usually need those credentials, so the model provider couldn't open them. eve rebuilds the download with the adapter's `rehydrateAttachment`; an adapter without one can't download after the webhook returns, so its files reach the agent as a short note. A failed download, or a file over 25 MB, also becomes a note. An attachment with only a URL is
|
|
248
|
+
When the adapter can download an attachment (it sets `fetchData`, as the Slack, Google Chat, WhatsApp, and Twilio adapters do), eve downloads it with the adapter's credentials when the turn runs, not in the webhook, and passes the bytes. Platform file URLs usually need those credentials, so the model provider couldn't open them. eve rebuilds the download with the adapter's `rehydrateAttachment`; an adapter without one can't download after the webhook returns, so its files reach the agent as a short note. A failed download, or a file over 25 MB, also becomes a note. An attachment with only a URL is downloaded by eve when the URL is public `https:`; otherwise it becomes a note.
|
|
249
249
|
|
|
250
250
|
See [File uploads](./custom#file-uploads) for how eve stages remote file URLs before the model call.
|
|
251
251
|
|
package/docs/channels/custom.mdx
CHANGED
|
@@ -81,6 +81,13 @@ the exact session, while `channel.continuation` exposes the current address and
|
|
|
81
81
|
receives only `(eventData, channel)` because it runs outside session context;
|
|
82
82
|
its event data contains `sessionId` directly.
|
|
83
83
|
|
|
84
|
+
A failed turn emits `turn.failed`, then either `session.waiting` or
|
|
85
|
+
`session.failed`. `turn.failed` carries `terminal: true` when the failure ends
|
|
86
|
+
the session and `session.failed` follows. The built-in channels skip terminal
|
|
87
|
+
`turn.failed` events, so a person sees one notice: the `session.failed` handler
|
|
88
|
+
tells them to start over instead of to try again. Check `eventData.terminal` the
|
|
89
|
+
same way in a custom channel that posts on both events.
|
|
90
|
+
|
|
84
91
|
A channel that renders questions and approvals from `input.requested` can handle
|
|
85
92
|
`input.resolved` to learn when each request ends, however it ended: answered from
|
|
86
93
|
the channel, answered by a plain-text reply, or withdrawn. A request that a
|
|
@@ -550,11 +557,31 @@ defineChannel({
|
|
|
550
557
|
});
|
|
551
558
|
```
|
|
552
559
|
|
|
553
|
-
If `fetchFile` throws, eve replaces that attachment with a model-visible
|
|
560
|
+
If `fetchFile` throws, eve replaces that attachment with a model-visible note and continues the turn. To tell the model why, throw `attachmentError` from `eve/channels`:
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
import { attachmentError } from "eve/channels";
|
|
564
|
+
|
|
565
|
+
async function fetchUpload(url: string) {
|
|
566
|
+
const response = await fetch(url, { headers: { authorization: `Bearer ${token}` } });
|
|
567
|
+
if (response.status === 413) {
|
|
568
|
+
throw attachmentError("The file is over 100 MB. Ask for a smaller file.");
|
|
569
|
+
}
|
|
570
|
+
return Buffer.from(await response.arrayBuffer());
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
The model then reads `Attachment report.pdf could not be retrieved: The file is over 100 MB. Ask for a smaller file.` The message reaches the model as written, so keep it to details the person can act on, such as a size limit or a missing permission, and never include URLs, tokens, or upstream response text. Pass the original error as `attachmentError(message, { cause })` to keep it in operator logs. Any other error that `fetchFile` throws becomes a generic note, and eve keeps the original error in operator logs.
|
|
575
|
+
|
|
576
|
+
`fetchFile` receives the channel's `state` and the `session` the attachment arrived in as its second argument, so a resolver can check a file against the session's caller in `session.auth`.
|
|
577
|
+
|
|
578
|
+
The `URL` object survives the queue boundary as a string and is reconstituted inside the workflow step. A string with a URL scheme, such as `https://...` or `myapp-file:abc`, is handled the same way. The staging pipeline calls `fetchFile` with the URL serialized as a string (the URL's `href`), which is why the example matches on `url.startsWith(...)`.
|
|
579
|
+
|
|
580
|
+
Return bytes to stage the file to the sandbox. Return `null` when the URL is not one your channel resolves: eve then downloads a public `https:` URL itself, with the 25 MB default size cap and a 30-second timeout, and refuses private or reserved addresses. It downloads at most 10 URLs per message, one at a time. Any other URL, or a download that fails, reaches the model as a note. The model provider never fetches an attachment, so a link that expires or needs credentials can't fail later model calls.
|
|
554
581
|
|
|
555
|
-
|
|
582
|
+
Set `uploadPolicy` on `defineChannel` to cap what eve stages for the channel, for example `uploadPolicy: { maxBytes: 10 * 1024 * 1024, allowedMediaTypes: ["image/*", "application/pdf"] }`. eve checks every staged file against it, on the final bytes and the media type they prove, including URLs it downloads itself. A file that breaks the policy reaches the model as a note. Without `uploadPolicy`, eve checks only what your `fetchFile` enforces, and its own downloads stop at 25 MB.
|
|
556
583
|
|
|
557
|
-
The framework handles staging bytes to the sandbox,
|
|
584
|
+
The framework handles staging bytes to the sandbox, hydrating files for the model call, and reconstituting `URL` objects after queue serialization. See [Inbound attachments](../sandbox#inbound-attachments) for the shared storage, size, and provider-input behavior.
|
|
558
585
|
|
|
559
586
|
## What to read next
|
|
560
587
|
|
package/docs/channels/eve.mdx
CHANGED
|
@@ -163,6 +163,40 @@ An existing workflow whose inbox is not yet available returns `409 session_not_r
|
|
|
163
163
|
A session that another eve version built returns `409 session_stranded` with the `eveVersion`
|
|
164
164
|
that built it.
|
|
165
165
|
|
|
166
|
+
### Send files
|
|
167
|
+
|
|
168
|
+
A message can mix text and file parts. A file part's `data` is base64, a `data:` URL, or a URL:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
curl -X POST https://<deployment>/eve/v1/session/wrun_A \
|
|
172
|
+
-H "Content-Type: application/json" \
|
|
173
|
+
-d '{"message":[{"type":"text","text":"Summarize this report."},{"type":"file","mediaType":"application/pdf","filename":"report.pdf","data":"data:application/pdf;base64,JVBERi0xLjQK..."}]}'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`uploadPolicy` sets the size cap and allowed media types, 25 MB and every type by default. A request whose inline file breaks the policy returns `413` for size or `415` for type. Inline bytes also count toward the request body limit of the platform that serves the channel. On Vercel Functions that limit is 4.5 MB, so a base64 file stops at about 3.3 MB.
|
|
177
|
+
|
|
178
|
+
For larger files, upload them from the browser to your own storage and send the URL in the file part. Add `fetchFile` to load the URLs you own inside the workflow step, so the bytes never pass through the request or the workflow start payload:
|
|
179
|
+
|
|
180
|
+
```ts title="agent/channels/eve.ts"
|
|
181
|
+
import { eveChannel } from "eve/channels/eve";
|
|
182
|
+
import { localDev, vercelOidc } from "eve/channels/auth";
|
|
183
|
+
|
|
184
|
+
export default eveChannel({
|
|
185
|
+
auth: [vercelOidc(), localDev()],
|
|
186
|
+
uploadPolicy: { maxBytes: 100 * 1024 * 1024 },
|
|
187
|
+
async fetchFile(url) {
|
|
188
|
+
if (!url.startsWith("https://uploads.example.com/")) return null;
|
|
189
|
+
const response = await fetch(url, {
|
|
190
|
+
headers: { authorization: `Bearer ${process.env.UPLOADS_TOKEN}` },
|
|
191
|
+
});
|
|
192
|
+
if (!response.ok) throw new Error(`Upload fetch returned HTTP ${response.status}`);
|
|
193
|
+
return Buffer.from(await response.arrayBuffer());
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`fetchFile` follows the [custom channel contract](./custom#file-uploads): return bytes to stage the file, or `null` for a URL that isn't yours. eve then downloads a public `https:` URL itself, and any other URL reaches the model as a note. `uploadPolicy` covers every file eve stages for the channel, including URLs that `fetchFile` loads and URLs eve downloads itself. eve checks the final bytes and the media type they prove, so a file over the cap, or one whose bytes are a disallowed type, reaches the model as a note instead of failing the request. See [Inbound attachments](../sandbox#inbound-attachments) for how eve stores files and shows them to the model.
|
|
199
|
+
|
|
166
200
|
### Stream events
|
|
167
201
|
|
|
168
202
|
Stream a session as newline-delimited JSON from `GET /eve/v1/session/:sessionId/stream`. The [session protocol](../concepts/sessions-runs-and-streaming#stream-a-session) defines the event set, envelopes, cursors, and reconnection behavior.
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -399,7 +399,7 @@ slackChannel({
|
|
|
399
399
|
});
|
|
400
400
|
```
|
|
401
401
|
|
|
402
|
-
The bases say where a call may go. `apiBaseUrl` is the base Slack Web API method names resolve against, and defaults to `https://slack.com/api/`. `fileBaseUrl` adds a base for attachment downloads and falls back to `apiBaseUrl`: a download URL under it is fetched with the bot token, in addition to `files.slack.com` and Enterprise Grid file URLs.
|
|
402
|
+
The bases say where a call may go. `apiBaseUrl` is the base Slack Web API method names resolve against, and defaults to `https://slack.com/api/`. `fileBaseUrl` adds a base for attachment downloads and falls back to `apiBaseUrl`: a download URL under it is fetched with the bot token, in addition to `files.slack.com` and Enterprise Grid file URLs. eve downloads every other public `https:` URL without the bot token. Both bases must be absolute `http:` or `https:` URLs carrying no query string or fragment; `slackChannel()` throws on one that is not, naming the option. A missing trailing slash is added, so `https://sim.example/api` sends `chat.postMessage` to `https://sim.example/api/chat.postMessage`.
|
|
403
403
|
|
|
404
404
|
`api.fetch` says how the traffic travels. It replaces the global `fetch` for calls to the configured bases — use it to attach the per-call header a host behind an authenticating proxy requires, as the example does for a simulator behind Vercel Deployment Protection. eve confines it to those bases' origins, so that header reaches the simulator alone: `files.slack.com`, and any other host Slack names in a response or an inbound payload, keep the global `fetch`. A wrapper therefore attaches its credential unconditionally. With no base configured every call already goes to Slack's own hosts, and `api.fetch` carries all of them, which is what observes or stubs the traffic in a test.
|
|
405
405
|
|
|
@@ -744,6 +744,10 @@ For a Slack post without an agent turn, use `ctx.thread.post(...)` in an inbound
|
|
|
744
744
|
|
|
745
745
|
Inbound files behind authenticated Slack URLs are staged with `fetchFile`. See [File uploads](./custom#file-uploads) for the `fetchFile` contract.
|
|
746
746
|
|
|
747
|
+
The agent receives the files attached to the message that reaches it. When a mention carries no files, eve also collects the files posted in the thread since the previous mention of the app, up to 10 messages back, so a person can share a file and then ask about it in a follow-up. This works for mentions up to 1,000 replies into a thread. The app's own messages are skipped. A DM, or a thread where the app answers without a mention, gets no lookback, because each earlier message brought its own files.
|
|
748
|
+
|
|
749
|
+
Images, PDFs, audio, video, and other files all reach the agent. See [Inbound attachments](../sandbox#inbound-attachments) for which files the model reads directly and which it opens with tools. Files shared through an integration such as Google Drive or Dropbox are links to the other service, not Slack files, so eve skips them; their link stays in the message text. A download that fails or takes longer than 30 seconds reaches the model as a note.
|
|
750
|
+
|
|
747
751
|
Private file downloads resolve credentials from the session's app installation workspace and require the Slack bot token's `files:read` scope. Add the scope and reinstall the Slack app before sending attachments.
|
|
748
752
|
|
|
749
753
|
Downloads cover Slack's own file hosts plus URLs under a configured [`api.fileBaseUrl`](#point-the-channel-at-a-different-slack-api-host), and travel on `api.fetch` when one is configured.
|
|
@@ -81,7 +81,7 @@ export default disableTool();
|
|
|
81
81
|
|
|
82
82
|
### `read_file`
|
|
83
83
|
|
|
84
|
-
`read_file` reads text files from the sandbox with line-numbered output, and shows PNG, JPEG, GIF, and WebP images up to 3 MiB to the model as
|
|
84
|
+
`read_file` reads text files from the sandbox with line-numbered output, and shows PNG, JPEG, GIF, and WebP images up to 3 MiB and 8000 pixels per side, and PDFs up to 20 MiB, to the model as files. Images and PDFs are detected from their bytes, so a missing or mismatched filename extension does not matter, and other text files are always read as text. It accepts absolute paths and paths beginning with `$HOME/`.
|
|
85
85
|
|
|
86
86
|
```sh
|
|
87
87
|
eve add tool/read_file
|
|
@@ -95,7 +95,7 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
|
|
|
95
95
|
| `step.failed` | A model step failed; carries `{ code, message, details? }`. |
|
|
96
96
|
| `turn.waiting` | The open turn parked; carries `turnId` and `on`: `"input"` while a person must act on a sign-in, approval, or question, `"tasks"` while work it started runs. The turn has not ended. |
|
|
97
97
|
| `turn.completed` | The turn finished. |
|
|
98
|
-
| `turn.failed` | The turn failed; carries `{ code, message, details? }`.
|
|
98
|
+
| `turn.failed` | The turn failed; carries `{ code, message, details?, terminal? }`. `terminal` is `true` when `session.failed` follows instead of `session.waiting`. |
|
|
99
99
|
| `turn.cancelled` | The turn was cancelled before finishing; always followed by `session.waiting`. |
|
|
100
100
|
| `session.waiting` | The session parked and is ready for the next message. |
|
|
101
101
|
| `session.failed` | The session failed. |
|
|
@@ -131,7 +131,7 @@ A call to a tool that runs as a task, such as an agent tool, `agentRouter()`, th
|
|
|
131
131
|
|
|
132
132
|
A turn doesn't end while tasks are working. When the model ends its text early, eve holds the turn and the stream emits `turn.waiting` for it; the turn continues once a result arrives or its caller writes. In a root session, that text completes as an ordinary `message.completed`. In a child session or a schedule's session, it reports `finishReason: "tool-calls"`, so channels post only the final reply. When the model calls `eve__task_wait` and no result is ready yet, the stream also emits `turn.waiting`. Either way, the next `step.started` for the same `turnId` means the turn resumed, and `session.waiting` comes only after the turn ends. See [Tasks](/docs/tools/tasks#turns-wait-for-their-tasks).
|
|
133
133
|
|
|
134
|
-
`step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally. Whatever the turn streamed before cancellation stays on the stream. Durable history keeps the accepted user input and previously settled work, and discards incomplete assistant output. Tool calls the cancellation stopped stay in history, each answered as cancelled, so the model sees that the work started and stopped instead of a request left unanswered. Before `turn.cancelled`, the stream reports requests the cancel strands as `cancelled` in `input.resolved`. These include the turn's own questions, the session-limit prompt, and requests relayed from the work it stops. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`). Both carry `data.principalId` when a session principal started the sign-in. It holds the same value as `responderPrincipalId` on approval events, so a channel can deliver the challenge privately to that person even after someone else starts a later turn.
|
|
134
|
+
`step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.failed` also carries `terminal`: `true` when the failure ends the session and `session.failed` follows, `false` when `session.waiting` follows and the next message can retry. Events from eve versions before `terminal` was added omit it. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally. Whatever the turn streamed before cancellation stays on the stream. Durable history keeps the accepted user input and previously settled work, and discards incomplete assistant output. Tool calls the cancellation stopped stay in history, each answered as cancelled, so the model sees that the work started and stopped instead of a request left unanswered. Before `turn.cancelled`, the stream reports requests the cancel strands as `cancelled` in `input.resolved`. These include the turn's own questions, the session-limit prompt, and requests relayed from the work it stops. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`). Both carry `data.principalId` when a session principal started the sign-in. It holds the same value as `responderPrincipalId` on approval events, so a channel can deliver the challenge privately to that person even after someone else starts a later turn.
|
|
135
135
|
|
|
136
136
|
A provider response ending with `content-filter` fails with `MODEL_CALL_FAILED`,
|
|
137
137
|
`details.semanticErrorId: "model-response-content-filtered"`, and
|
package/docs/evals/overview.mdx
CHANGED
|
@@ -139,7 +139,7 @@ model: mockModel({
|
|
|
139
139
|
});
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
`mockModel()` uses `"Mock response"` when no response is supplied. It handles both generated and streamed responses, derives deterministic response metadata, and estimates token usage. Because the model is part of the agent definition, use it for a dedicated fixture agent; it remains mocked whether that fixture runs locally or as a deployed eval target.
|
|
142
|
+
`mockModel()` uses `"Mock response"` when no response is supplied. It handles both generated and streamed responses, derives deterministic response metadata, and estimates token usage. It compiles with a 1,000,000-token context window, so compaction stays out of the way; set `modelContextWindowTokens` on the agent to exercise compaction with a smaller window. Because the model is part of the agent definition, use it for a dedicated fixture agent; it remains mocked whether that fixture runs locally or as a deployed eval target.
|
|
143
143
|
|
|
144
144
|
## The `t` context
|
|
145
145
|
|
|
@@ -161,7 +161,7 @@ A call to a tool that runs as a [task](/docs/tools/workflows#run-calls-as-tasks-
|
|
|
161
161
|
When a submitted message includes attachments, `message.received.data.message` stays the
|
|
162
162
|
flattened compatibility summary, while `message.received.data.parts` carries renderable text and
|
|
163
163
|
file metadata. File parts never include raw bytes or internal sandbox paths; `url` appears only for
|
|
164
|
-
|
|
164
|
+
`http(s)` URLs, and an inline file reports its `size` instead.
|
|
165
165
|
|
|
166
166
|
## Authorization pauses
|
|
167
167
|
|
|
@@ -165,7 +165,9 @@ During compaction, eve excludes recalled records from the summarizer, keeps the
|
|
|
165
165
|
latest value for each keyed record plus every unkeyed record, and then calls
|
|
166
166
|
`recall["compaction.completed"]` against the new checkpoint. This keeps
|
|
167
167
|
provider content attributable and prevents a summary from turning it into
|
|
168
|
-
ordinary conversation history.
|
|
168
|
+
ordinary conversation history. During a turn, eve places those recalled records
|
|
169
|
+
before the turn's latest user message, as it does at turn start; between turns
|
|
170
|
+
they follow the checkpoint. If raw superseded records exceed 512 entries or
|
|
169
171
|
256 KiB, eve canonicalizes them without waiting for the normal token threshold;
|
|
170
172
|
this changes session history only, not the provider's store.
|
|
171
173
|
|
package/docs/sandbox/index.mdx
CHANGED
|
@@ -153,14 +153,18 @@ Docker and microsandbox mount the compiled trees read-only under `/eve/resources
|
|
|
153
153
|
|
|
154
154
|
eve writes byte-backed files that reach the agent into the sandbox under `/workspace/.eve/attachments/` and keeps only a reference in session history. This covers files attached to user messages and files that tools return to the model with `toolOutputPart.file` or as MCP image, audio, and blob content.
|
|
155
155
|
|
|
156
|
-
Before every model call, eve reads the referenced files back from the sandbox:
|
|
156
|
+
Before every model call, eve reads the referenced files back from the sandbox. Every file, whether attached to a message or returned by a tool, reaches the model with a label that names its sandbox path, such as `Attached file /workspace/.eve/attachments/<hash>/report.csv (text/csv)`. The agent can open that path with `read_file` or `bash`. The file's bytes follow its label only when every major provider reads the format natively:
|
|
157
157
|
|
|
158
|
-
-
|
|
159
|
-
- A
|
|
158
|
+
- A PNG, JPEG, GIF, or WebP image up to 3 MiB and at most 8000 pixels per side.
|
|
159
|
+
- A PDF up to 20 MiB.
|
|
160
|
+
|
|
161
|
+
Other files, such as CSV, HEIC, audio, and video, reach the model as the label alone. eve checks image and PDF media types against the file's bytes when it stages the file. A file whose bytes don't match its declared image or PDF type is staged as `application/octet-stream`, so a provider never receives bytes it would reject.
|
|
160
162
|
|
|
161
163
|
If a referenced file is missing, or its bytes no longer match what eve staged because something in the sandbox overwrote it, the model receives a `FileNotFound` note in its place.
|
|
162
164
|
|
|
163
|
-
|
|
165
|
+
A file that eve can't stage never enters session history. When a channel's `fetchFile` fails, or a file part's `data` is not bytes, base64, a `data:` URL, or a URL, the model receives a note that names the file instead.
|
|
166
|
+
|
|
167
|
+
Each call sends the same bytes for the same file, so the model still sees attachments from earlier turns and the provider's prompt cache stays valid. Compaction replaces files in older tool results with their text reference. The `read_file` tool shows the same images and PDFs to the model as files, so the agent can look at an attachment again after compaction, or open a PDF that a tool or `bash` wrote to the sandbox.
|
|
164
168
|
|
|
165
169
|
## Custom providers
|
|
166
170
|
|
package/docs/tools/overview.mdx
CHANGED
|
@@ -336,7 +336,7 @@ File payloads must be base64 strings — raw bytes (`Uint8Array`, `Buffer`) are
|
|
|
336
336
|
|
|
337
337
|
eve writes each returned file to the session sandbox and keeps only a reference in session history, so the file's bytes are not stored again on every workflow step. Every later model call sends the same file, which keeps it visible on later turns and keeps the provider's prompt cache valid. See [Inbound attachments](/docs/sandbox#inbound-attachments). Compaction counts an image at roughly what providers bill for it rather than its base64 length.
|
|
338
338
|
|
|
339
|
-
When compaction drops older tool results, each file becomes a text reference such as `Attached file /workspace/.eve/attachments/<hash>/chart.png (image/png)`. The built-in `read_file` tool shows PNG, JPEG, GIF, and WebP
|
|
339
|
+
When compaction drops older tool results, each file becomes a text reference such as `Attached file /workspace/.eve/attachments/<hash>/chart.png (image/png)`. The built-in `read_file` tool shows PNG, JPEG, GIF, and WebP images up to 3 MiB and PDFs up to 20 MiB to the model as files, so the agent can open a compacted image or PDF again.
|
|
340
340
|
|
|
341
341
|
Do not return secrets, credentials, unnecessary personal data, or unbounded sensitive content from tools. Filter, minimize, and redact tool outputs before returning them.
|
|
342
342
|
|