eve 0.27.2 → 0.27.4
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 +25 -0
- package/dist/src/channel/reset-session.d.ts +8 -0
- package/dist/src/channel/reset-session.js +1 -0
- package/dist/src/channel/routes.d.ts +24 -1
- package/dist/src/channel/send.js +1 -1
- package/dist/src/channel/session-callback.js +1 -1
- package/dist/src/channel/types.d.ts +14 -0
- package/dist/src/chunks/{use-eve-agent-CbF0l_Fp.js → use-eve-agent-BtkhbY2I.js} +53 -4
- package/dist/src/chunks/{use-eve-agent-CgxB9WQv.js → use-eve-agent-NUjD28Iu.js} +53 -4
- package/dist/src/cli/commands/build.js +1 -1
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/dev/tui/blocks.d.ts +7 -0
- package/dist/src/cli/dev/tui/blocks.js +3 -3
- package/dist/src/cli/dev/tui/message-queue.d.ts +88 -0
- package/dist/src/cli/dev/tui/message-queue.js +1 -0
- package/dist/src/cli/dev/tui/runner.d.ts +33 -0
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.js +1 -1
- package/dist/src/cli/dev/tui/subagent-pump.d.ts +9 -0
- package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +9 -0
- package/dist/src/cli/dev/tui/terminal-renderer.js +13 -11
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/session.d.ts +13 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/types.d.ts +10 -0
- package/dist/src/context/dynamic-tool-lifecycle.d.ts +13 -1
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/keys.d.ts +5 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/execution/node-step.d.ts +6 -0
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/terminal-session-failure-step.js +1 -1
- package/dist/src/execution/workflow-callback-url.d.ts +12 -2
- package/dist/src/execution/workflow-callback-url.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-module-loader.js +3 -3
- package/dist/src/internal/authored-package-tsconfig-paths.js +1 -1
- package/dist/src/internal/authored-relative-extension-resolver.d.ts +6 -0
- package/dist/src/internal/authored-relative-extension-resolver.js +1 -0
- package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
- package/dist/src/internal/nitro/host/build-application.js +1 -1
- package/dist/src/internal/nitro/host/types.d.ts +9 -0
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/node-esm-compat-banner.js +1 -1
- package/dist/src/internal/workflow-bundle/builder-support.d.ts +5 -0
- package/dist/src/internal/workflow-bundle/builder.js +2 -2
- package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.d.ts +39 -0
- package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.js +1 -0
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +4 -4
- package/dist/src/internal/workflow-bundle/vercel-workflow-output.d.ts +10 -1
- package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/protocol/reset-session.d.ts +14 -0
- package/dist/src/protocol/reset-session.js +1 -0
- package/dist/src/protocol/routes.d.ts +5 -0
- package/dist/src/protocol/routes.js +1 -1
- package/dist/src/public/channels/eve.d.ts +2 -2
- package/dist/src/public/channels/eve.js +1 -1
- package/dist/src/public/channels/index.d.ts +1 -1
- package/dist/src/public/channels/linear/inbound-images.d.ts +18 -0
- package/dist/src/public/channels/linear/inbound-images.js +1 -0
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/slack/limits.js +1 -1
- package/dist/src/public/definitions/channel.d.ts +1 -1
- package/dist/src/public/next/vercel-output-config.js +1 -1
- package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
- package/dist/src/setup/flows/install-vercel-cli.d.ts +8 -2
- package/dist/src/setup/flows/install-vercel-cli.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/vercel-project-api.d.ts +1 -1
- package/dist/src/setup/vercel-project-api.js +1 -1
- package/dist/src/shared/public-route-prefix.d.ts +23 -0
- package/dist/src/shared/public-route-prefix.js +1 -0
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/custom.mdx +38 -1
- package/docs/channels/linear.mdx +1 -1
- package/docs/extensions.md +100 -20
- package/docs/guides/dev-tui.md +9 -2
- package/docs/guides/frontend/nextjs.mdx +2 -0
- package/docs/reference/cli.md +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_INFO_ROUTE_PATH}from"#protocol/routes.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{readAgentInfoRouteResponse,readRouteAgent}from"#internal/nitro/routes/channel-route-context.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";const log=createLogger(`eve.channel`);function defaultEveAuth(e){return e.eve.caller}function eveChannel(e){let n=mergeUploadPolicy(e.uploadPolicy);return defineChannel({cors:normalizeEveCors(e.cors),routes:[GET(EVE_INFO_ROUTE_PATH,async(t,n)=>{let r=await routeAuth(t,e.auth);if(r instanceof Response)return r;let i=readAgentInfoRouteResponse(n);return i===void 0?Response.json({error:`Agent info route requires internal channel dispatch context.`,ok:!1},{status:500}):await i()}),POST(`/eve/v1/session`,async(t,{send:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=i,o;try{o=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof o!=`object`||!o)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let s=parseCreateBody(o);if(s instanceof Response)return s;let c=checkUploadPolicy(s,n);if(c!==null)return c;let l=await resolveOnMessage({auth:a,config:e,message:s.message,request:t});if(l instanceof Response)return l;if(!l.dispatch)return droppedMessageResponse();let u=`eve:${crypto.randomUUID()}`,d=await r(createSendPayload(s,mergeContext(s.context,l.context)),{auth:l.auth,callback:s.callback,continuationToken:u,mode:s.mode});return Response.json({continuationToken:d.continuationToken,ok:!0,sessionId:d.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:d.id},status:202})}),POST(`/eve/v1/session/:sessionId`,async(t,{send:r,getSession:i,params:a})=>{let o=await routeAuth(t,e.auth);if(o instanceof Response)return o;let s=o,c=a.sessionId;if(!c)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(c)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let l;try{l=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof l!=`object`||!l)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let u=parseContinueBody(l);if(u instanceof Response)return u;let d=checkUploadPolicy(u,n);if(d!==null)return d;let f=u.context,p=s;if(u.message!==void 0){let n=await resolveOnMessage({auth:s,config:e,message:u.message,request:t,sessionId:c});if(n instanceof Response)return n;if(!n.dispatch)return droppedMessageResponse();f=mergeContext(u.context,n.context),p=n.auth}let m=await r({inputResponses:u.inputResponses,message:u.message,context:f,outputSchema:u.outputSchema},{auth:p,continuationToken:u.continuationToken});return Response.json({ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:200})}),POST(EVE_CANCEL_TURN_ROUTE_PATTERN,async(n,r)=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=r.params.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let o=await parseCancelTurnBody(n);if(o instanceof Response)return o;let s;try{let e=readRouteAgent(r);if(e===void 0)throw Error(`Missing route agent.`);s=await e.cancelTurn({sessionId:a,turnId:o.turnId})}catch(e){let n=logError(log,`cancel-turn request failed`,e,{sessionId:a});return Response.json({error:`Failed to cancel the turn.`,errorId:n,ok:!1},{status:500})}return Response.json({ok:!0,sessionId:a,status:s.status},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:a},status:202})}),GET(`/eve/v1/session/:sessionId/stream`,async(t,{getSession:n,params:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let u=r.sessionId;if(!u)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let d=parseStartIndex(t);if(d instanceof Response)return d;try{let e=serializeAsNdjson(await n(u).getEventStream({startIndex:d}));return new Response(e,{headers:{"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:u,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}function normalizeEveCors(e){if(e===void 0||e===!1)return!1;if(e===!0)return!0;let t={};return e.origin!==void 0&&(t.origin=normalizeEveCorsOrigin(e.origin)),e.methods!==void 0&&(t.methods=e.methods),e.allowedHeaders!==void 0&&(t.allowHeaders=e.allowedHeaders),e.exposedHeaders!==void 0&&(t.exposeHeaders=e.exposedHeaders),e.credentials!==void 0&&(t.credentials=e.credentials),e.maxAge!==void 0&&(t.maxAge=e.maxAge),e.preflightStatus!==void 0&&(t.preflight={statusCode:e.preflightStatus}),t}function normalizeEveCorsOrigin(e){return e===`*`||e===`null`?e:typeof e==`string`?[e]:e}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({eve:e.sessionId===void 0?{caller:e.auth,request:e.request}:{caller:e.auth,request:e.request,sessionId:e.sessionId}},e.message)}catch(n){let r=logError(log,`onMessage handler failed`,n,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:r,ok:!1},{status:500})}return r==null?{dispatch:!1}:r.context===void 0?{auth:r.auth,dispatch:!0}:{auth:r.auth,context:r.context,dispatch:!0}}function defaultOnMessage(e){return{auth:defaultEveAuth(e)}}function droppedMessageResponse(){return new Response(null,{headers:{"cache-control":`no-store`},status:204})}function parseCreateBody(e){let t=parseMessageField(e.message);if(t instanceof Response)return t;let n=parseClientContextField(e.clientContext);if(n instanceof Response)return n;let r=parseCallbackField(e.callback);if(r instanceof Response)return r;let i=parseModeField(e.mode);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,context:n,outputSchema:a}}function parseContinueBody(e){let t=typeof e.continuationToken==`string`&&e.continuationToken.length>0?e.continuationToken:void 0;if(t===void 0)return Response.json({error:`Missing or empty 'continuationToken' field.`,ok:!1},{status:400});let n=parseMessageField(e.message);if(n instanceof Response)return n;let r=parseInputResponses(e.inputResponses);if(r instanceof Response)return r;let i=parseClientContextField(e.clientContext);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:n===void 0&&r===void 0?Response.json({error:`Expected a non-empty 'message', a non-empty 'inputResponses' array, or both.`,ok:!1},{status:400}):{message:n,continuationToken:t,inputResponses:r,context:i,outputSchema:a}}async function parseCancelTurnBody(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof n!=`object`||!n||Array.isArray(n))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let r=n.turnId;return r===void 0?{}:typeof r!=`string`||r.length===0?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):{turnId:r}}function createSendPayload(e,t=e.context){if(t===void 0&&e.outputSchema===void 0)return e.message;let n={message:e.message};return t!==void 0&&(n.context=t),e.outputSchema!==void 0&&(n.outputSchema=e.outputSchema),n}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseModeField(e){if(e!==void 0)return e===`conversation`||e===`task`?e:Response.json({error:`Expected 'mode' to be either 'conversation' or 'task'.`,ok:!1},{status:400})}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function mergeContext(e,t){return e===void 0?t:t===void 0?e:[...e,...t]}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?[toClientContextMessage(e)]:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e.map(e=>toClientContextMessage(e)):Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{let t=parseJsonObject(e);return[toClientContextMessage(JSON.stringify(t))]}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function toClientContextMessage(e){return`Client context:
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_INFO_ROUTE_PATH,EVE_RESET_SESSION_ROUTE_PATH}from"#protocol/routes.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{readAgentInfoRouteResponse,readRouteAgent}from"#internal/nitro/routes/channel-route-context.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";const log=createLogger(`eve.channel`);function defaultEveAuth(e){return e.eve.caller}function eveChannel(e){let n=mergeUploadPolicy(e.uploadPolicy);return defineChannel({cors:normalizeEveCors(e.cors),routes:[GET(EVE_INFO_ROUTE_PATH,async(t,n)=>{let r=await routeAuth(t,e.auth);if(r instanceof Response)return r;let i=readAgentInfoRouteResponse(n);return i===void 0?Response.json({error:`Agent info route requires internal channel dispatch context.`,ok:!1},{status:500}):await i()}),POST(`/eve/v1/session`,async(t,{send:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=i,o;try{o=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof o!=`object`||!o)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let s=parseCreateBody(o);if(s instanceof Response)return s;let c=checkUploadPolicy(s,n);if(c!==null)return c;let l=await resolveOnMessage({auth:a,config:e,message:s.message,request:t});if(l instanceof Response)return l;if(!l.dispatch)return droppedMessageResponse();let u=`eve:${crypto.randomUUID()}`,d=await r(createSendPayload(s,mergeContext(s.context,l.context)),{auth:l.auth,callback:s.callback,continuationToken:u,mode:s.mode});return Response.json({continuationToken:d.continuationToken,ok:!0,sessionId:d.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:d.id},status:202})}),POST(EVE_RESET_SESSION_ROUTE_PATH,async(n,{reset:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=await parseResetSessionBody(n);if(a instanceof Response)return a;let o;try{o=await r({continuationToken:a.continuationToken,reason:`Client requested session reset`})}catch(e){let n=logError(log,`session-reset request failed`,e);return Response.json({error:`Failed to reset the session.`,errorId:n,ok:!1},{status:500})}let s=o.status===`reset`?{ok:!0,previousSessionId:o.previousSessionId,status:`reset`}:{ok:!0,status:`no_active_session`};return Response.json(s,{headers:{"cache-control":`no-store`}})}),POST(`/eve/v1/session/:sessionId`,async(t,{send:r,getSession:i,params:a})=>{let o=await routeAuth(t,e.auth);if(o instanceof Response)return o;let s=o,c=a.sessionId;if(!c)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(c)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let l;try{l=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof l!=`object`||!l)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let u=parseContinueBody(l);if(u instanceof Response)return u;let d=checkUploadPolicy(u,n);if(d!==null)return d;let f=u.context,p=s;if(u.message!==void 0){let n=await resolveOnMessage({auth:s,config:e,message:u.message,request:t,sessionId:c});if(n instanceof Response)return n;if(!n.dispatch)return droppedMessageResponse();f=mergeContext(u.context,n.context),p=n.auth}let m=await r({inputResponses:u.inputResponses,message:u.message,context:f,outputSchema:u.outputSchema},{auth:p,continuationToken:u.continuationToken});return Response.json({ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:200})}),POST(EVE_CANCEL_TURN_ROUTE_PATTERN,async(n,r)=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=r.params.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let o=await parseCancelTurnBody(n);if(o instanceof Response)return o;let s;try{let e=readRouteAgent(r);if(e===void 0)throw Error(`Missing route agent.`);s=await e.cancelTurn({sessionId:a,turnId:o.turnId})}catch(e){let n=logError(log,`cancel-turn request failed`,e,{sessionId:a});return Response.json({error:`Failed to cancel the turn.`,errorId:n,ok:!1},{status:500})}return Response.json({ok:!0,sessionId:a,status:s.status},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:a},status:202})}),GET(`/eve/v1/session/:sessionId/stream`,async(t,{getSession:n,params:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=r.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let d=parseStartIndex(t);if(d instanceof Response)return d;try{let e=serializeAsNdjson(await n(a).getEventStream({startIndex:d}));return new Response(e,{headers:{"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:a,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}function normalizeEveCors(e){if(e===void 0||e===!1)return!1;if(e===!0)return!0;let t={};return e.origin!==void 0&&(t.origin=normalizeEveCorsOrigin(e.origin)),e.methods!==void 0&&(t.methods=e.methods),e.allowedHeaders!==void 0&&(t.allowHeaders=e.allowedHeaders),e.exposedHeaders!==void 0&&(t.exposeHeaders=e.exposedHeaders),e.credentials!==void 0&&(t.credentials=e.credentials),e.maxAge!==void 0&&(t.maxAge=e.maxAge),e.preflightStatus!==void 0&&(t.preflight={statusCode:e.preflightStatus}),t}function normalizeEveCorsOrigin(e){return e===`*`||e===`null`?e:typeof e==`string`?[e]:e}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({eve:e.sessionId===void 0?{caller:e.auth,request:e.request}:{caller:e.auth,request:e.request,sessionId:e.sessionId}},e.message)}catch(n){let r=logError(log,`onMessage handler failed`,n,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:r,ok:!1},{status:500})}return r==null?{dispatch:!1}:r.context===void 0?{auth:r.auth,dispatch:!0}:{auth:r.auth,context:r.context,dispatch:!0}}function defaultOnMessage(e){return{auth:defaultEveAuth(e)}}function droppedMessageResponse(){return new Response(null,{headers:{"cache-control":`no-store`},status:204})}function parseCreateBody(e){let t=parseMessageField(e.message);if(t instanceof Response)return t;let n=parseClientContextField(e.clientContext);if(n instanceof Response)return n;let r=parseCallbackField(e.callback);if(r instanceof Response)return r;let i=parseModeField(e.mode);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,context:n,outputSchema:a}}function parseContinueBody(e){let t=typeof e.continuationToken==`string`&&e.continuationToken.length>0?e.continuationToken:void 0;if(t===void 0)return Response.json({error:`Missing or empty 'continuationToken' field.`,ok:!1},{status:400});let n=parseMessageField(e.message);if(n instanceof Response)return n;let r=parseInputResponses(e.inputResponses);if(r instanceof Response)return r;let i=parseClientContextField(e.clientContext);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:n===void 0&&r===void 0?Response.json({error:`Expected a non-empty 'message', a non-empty 'inputResponses' array, or both.`,ok:!1},{status:400}):{message:n,continuationToken:t,inputResponses:r,context:i,outputSchema:a}}async function parseResetSessionBody(e){let t;try{t=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof t!=`object`||!t||Array.isArray(t))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let n=t.continuationToken;return typeof n!=`string`||n.length===0?Response.json({error:`Expected 'continuationToken' to be a non-empty string.`,ok:!1},{status:400}):{continuationToken:n}}async function parseCancelTurnBody(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof n!=`object`||!n||Array.isArray(n))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let r=n.turnId;return r===void 0?{}:typeof r!=`string`||r.length===0?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):{turnId:r}}function createSendPayload(e,t=e.context){if(t===void 0&&e.outputSchema===void 0)return e.message;let n={message:e.message};return t!==void 0&&(n.context=t),e.outputSchema!==void 0&&(n.outputSchema=e.outputSchema),n}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseModeField(e){if(e!==void 0)return e===`conversation`||e===`task`?e:Response.json({error:`Expected 'mode' to be either 'conversation' or 'task'.`,ok:!1},{status:400})}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function mergeContext(e,t){return e===void 0?t:t===void 0?e:[...e,...t]}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?[toClientContextMessage(e)]:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e.map(e=>toClientContextMessage(e)):Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{let t=parseJsonObject(e);return[toClientContextMessage(JSON.stringify(t))]}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function toClientContextMessage(e){return`Client context:
|
|
2
2
|
${e}`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number(t);return!/^-?\d+$/.test(t)||!Number.isSafeInteger(n)?Response.json({error:`Expected startIndex to be an integer.`,ok:!1},{status:400}):n}function serializeAsNdjson(e){let t=new TextEncoder;return e.pipeThrough(new TransformStream({start(e){e.enqueue(t.encode(`
|
|
3
3
|
`))},transform(e,n){n.enqueue(t.encode(`${JSON.stringify(e)}\n`))}}))}export{defaultEveAuth,eveChannel};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { defineChannel, GET, POST, PUT, PATCH, DELETE, WS, type CancelFn, type CancelOptions, type CancelTurnResult, type Channel, type ChannelCors, type ChannelCorsOptions, type ChannelDefinition, type ChannelSessionOps, type ChannelEvents, type InferChannelMetadata, type Session, type SessionHandle, type RouteDefinition, type RouteHandlerArgs, type SendFn, type SendOptions, type SendPayload, type GetSessionFn, type HttpRouteDefinition, type WebSocketMessage, type WebSocketPeer, type WebSocketRouteDefinition, type WebSocketRouteHandler, type WebSocketRouteHooks, type WebSocketUpgradeRequest, type WebSocketUpgradeResult, } from "#public/definitions/channel.js";
|
|
1
|
+
export { defineChannel, GET, POST, PUT, PATCH, DELETE, WS, type CancelFn, type CancelOptions, type CancelTurnResult, type Channel, type ChannelCors, type ChannelCorsOptions, type ChannelDefinition, type ChannelSessionOps, type ChannelEvents, type InferChannelMetadata, type Session, type SessionHandle, type RouteDefinition, type RouteHandlerArgs, type ResetFn, type ResetOptions, type ResetResult, type SendFn, type SendOptions, type SendPayload, type GetSessionFn, type HttpRouteDefinition, type WebSocketMessage, type WebSocketPeer, type WebSocketRouteDefinition, type WebSocketRouteHandler, type WebSocketRouteHooks, type WebSocketUpgradeRequest, type WebSocketUpgradeResult, } from "#public/definitions/channel.js";
|
|
2
2
|
export { createWebSocketUpgradeServer, type WebSocketUpgradeServerBridge, } from "#channel/websocket-upgrade-server.js";
|
|
3
3
|
import type { Channel, InferChannelMetadata } from "#public/definitions/channel.js";
|
|
4
4
|
/**
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { UserContent } from "ai";
|
|
2
|
+
import type { LinearFetch } from "#public/channels/linear/api.js";
|
|
3
|
+
import { type LinearChannelCredentials } from "#public/channels/linear/auth.js";
|
|
4
|
+
/** One trusted Linear upload referenced by markdown image syntax. */
|
|
5
|
+
export interface LinearUploadImageReference {
|
|
6
|
+
readonly altText: string;
|
|
7
|
+
readonly end: number;
|
|
8
|
+
readonly start: number;
|
|
9
|
+
readonly url: URL;
|
|
10
|
+
}
|
|
11
|
+
/** Extracts markdown image references that target Linear's exact upload origin. */
|
|
12
|
+
export declare function extractLinearUploadImageReferences(markdown: string): readonly LinearUploadImageReference[];
|
|
13
|
+
/** Adds authenticated Linear upload images to otherwise text-only inbound content. */
|
|
14
|
+
export declare function attachLinearInboundImages(input: {
|
|
15
|
+
readonly content: UserContent;
|
|
16
|
+
readonly credentials?: LinearChannelCredentials;
|
|
17
|
+
readonly fetch?: LinearFetch;
|
|
18
|
+
}): Promise<UserContent>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{resolveLinearAccessToken}from"#public/channels/linear/auth.js";const MARKDOWN_IMAGE_PATTERN=/!\[([^\]\r\n]*)\]\(\s*(?:<([^>\r\n]+)>|([^\s)\r\n]+))(?:\s+(?:"[^"\r\n]*"|'[^'\r\n]*'|\([^)\r\n]*\)))?\s*\)/gu;function extractLinearUploadImageReferences(e){let n=[];for(let r of e.matchAll(MARKDOWN_IMAGE_PATTERN)){let e=r[2]??r[3],t=r.index;if(e===void 0||t===void 0)continue;let i=parseLinearUploadUrl(e);i!==null&&n.push({altText:r[1]??``,end:t+r[0].length,start:t,url:i})}return n}async function attachLinearInboundImages(t){if(typeof t.content!=`string`)return t.content;let n=extractLinearUploadImageReferences(t.content);if(n.length===0)return t.content;let r;try{r=await resolveLinearAccessToken(t.credentials?.accessToken)}catch{return t.content}let i=t.fetch??fetch,a=await Promise.all(n.map(e=>fetchLinearUploadImage(e.url,r,i)));return a.every(e=>e===null)?t.content:buildLinearImageContent(t.content,n,a)}function parseLinearUploadUrl(e){let t;try{t=new URL(e)}catch{return null}return t.origin!==`https://uploads.linear.app`||t.username!==``||t.password!==``?null:t}async function fetchLinearUploadImage(e,t,n){if(parseLinearUploadUrl(e.href)===null)return null;try{let r=await n(e.href,{credentials:`omit`,headers:{accept:`image/*`,authorization:`Bearer ${t}`},redirect:`manual`});if(!r.ok)return null;let i=readImageMediaType(r.headers.get(`content-type`));return i===null?null:{data:Buffer.from(await r.arrayBuffer()),mediaType:i,type:`file`}}catch{return null}}function readImageMediaType(e){let t=e?.split(`;`,1)[0]?.trim().toLowerCase();return t?.startsWith(`image/`)===!0&&t.length>6?t:null}function buildLinearImageContent(e,t,n){let r=0,i=``,a=[];for(let[o,s]of t.entries()){let t=n[o];t!=null&&(i+=e.slice(r,s.start),i+=s.altText,r=s.end,a.push(t))}return i+=e.slice(r),i.trim().length===0?a:[{text:i,type:`text`},...a]}export{attachLinearInboundImages,extractLinearUploadImageReferences};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{createLinearAgentActivity,createLinearAgentSessionOnComment,createLinearAgentSessionOnIssue,listLinearAgentSessionActivities,updateLinearAgentSession}from"#public/channels/linear/api.js";import{LINEAR_CHANNEL_DEFAULT_ROUTE}from"#public/channels/linear/constants.js";import{createDefaultEvents,defaultOnAgentSession}from"#public/channels/linear/defaults.js";import{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent}from"#public/channels/linear/inbound.js";import{verifyLinearRequest}from"#public/channels/linear/verify.js";const log=createLogger(`linear.channel`);function linearChannel(e={}){let t=e.onAgentSession??defaultOnAgentSession,a={...createDefaultEvents({api:e.api,credentials:e.credentials}),...e.events};return defineChannel({kindHint:`linear`,state:initialLinearState(),metadata(e){return{agentSessionId:e.agentSessionId,commentId:e.commentId??null,issueId:e.issueId??null,issueIdentifier:e.issueIdentifier??null,organizationId:e.organizationId??null}},context(t,n){return rebuildLinearContext(t,n,e)},routes:[POST(e.route??LINEAR_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseLinearWebhookEvent({body:a,headers:n.headers})}catch(e){return log.warn(`inbound Linear body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`agent_session`?(i(dispatchAgentSession({config:e,event:o,onAgentSession:t,send:r})),jsonOk({ok:!0})):e.onDataWebhook===void 0?jsonOk({ignored:!0,ok:!0}):(i(Promise.resolve(e.onDataWebhook(o))),jsonOk({ok:!0}))})],async receive(t,{send:n}){let r=t.target,a=await resolveReceiveSession(r,e),o=readString(r.initialActivity);return o!==void 0&&await createLinearAgentActivity({api:e.api,credentials:e.credentials,activity:{agentSessionId:a.id,content:{body:o,type:`thought`}}}),n(t.message,{auth:t.auth,continuationToken:linearContinuationToken(a.id),state:stateFromAgentSession(a)})},events:a})}function rebuildLinearContext(e,t,n){return{linear:buildLinearHandle({agentSessionId:e.agentSessionId??``,config:n}),state:e}}function buildLinearHandle(e){return{agentSessionId:e.agentSessionId,createActivity(t,n){return createLinearAgentActivity({api:e.config.api,credentials:e.config.credentials,activity:{agentSessionId:e.agentSessionId,content:t,ephemeral:n?.ephemeral,signal:n?.signal,signalMetadata:n?.signalMetadata}})},listActivities(t){return listLinearAgentSessionActivities({api:e.config.api,credentials:e.config.credentials,agentSessionId:e.agentSessionId,last:t?.last})},updateSession(t){return updateLinearAgentSession({api:e.config.api,credentials:e.config.credentials,id:e.agentSessionId,update:t})}}}async function dispatchAgentSession(e){let{event:t}=e,n={delivery:t.delivery,linear:buildLinearHandle({agentSessionId:t.agentSession.id,config:e.config}),session:t.agentSession},r=await e.onAgentSession(n,t);r
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{createLinearAgentActivity,createLinearAgentSessionOnComment,createLinearAgentSessionOnIssue,listLinearAgentSessionActivities,updateLinearAgentSession}from"#public/channels/linear/api.js";import{LINEAR_CHANNEL_DEFAULT_ROUTE}from"#public/channels/linear/constants.js";import{createDefaultEvents,defaultOnAgentSession}from"#public/channels/linear/defaults.js";import{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent}from"#public/channels/linear/inbound.js";import{verifyLinearRequest}from"#public/channels/linear/verify.js";import{attachLinearInboundImages}from"#public/channels/linear/inbound-images.js";const log=createLogger(`linear.channel`);function linearChannel(e={}){let t=e.onAgentSession??defaultOnAgentSession,a={...createDefaultEvents({api:e.api,credentials:e.credentials}),...e.events};return defineChannel({kindHint:`linear`,state:initialLinearState(),metadata(e){return{agentSessionId:e.agentSessionId,commentId:e.commentId??null,issueId:e.issueId??null,issueIdentifier:e.issueIdentifier??null,organizationId:e.organizationId??null}},context(t,n){return rebuildLinearContext(t,n,e)},routes:[POST(e.route??LINEAR_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseLinearWebhookEvent({body:a,headers:n.headers})}catch(e){return log.warn(`inbound Linear body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`agent_session`?(i(dispatchAgentSession({config:e,event:o,onAgentSession:t,send:r})),jsonOk({ok:!0})):e.onDataWebhook===void 0?jsonOk({ignored:!0,ok:!0}):(i(Promise.resolve(e.onDataWebhook(o))),jsonOk({ok:!0}))})],async receive(t,{send:n}){let r=t.target,a=await resolveReceiveSession(r,e),o=readString(r.initialActivity);return o!==void 0&&await createLinearAgentActivity({api:e.api,credentials:e.credentials,activity:{agentSessionId:a.id,content:{body:o,type:`thought`}}}),n(t.message,{auth:t.auth,continuationToken:linearContinuationToken(a.id),state:stateFromAgentSession(a)})},events:a})}function rebuildLinearContext(e,t,n){return{linear:buildLinearHandle({agentSessionId:e.agentSessionId??``,config:n}),state:e}}function buildLinearHandle(e){return{agentSessionId:e.agentSessionId,createActivity(t,n){return createLinearAgentActivity({api:e.config.api,credentials:e.config.credentials,activity:{agentSessionId:e.agentSessionId,content:t,ephemeral:n?.ephemeral,signal:n?.signal,signalMetadata:n?.signalMetadata}})},listActivities(t){return listLinearAgentSessionActivities({api:e.config.api,credentials:e.config.credentials,agentSessionId:e.agentSessionId,last:t?.last})},updateSession(t){return updateLinearAgentSession({api:e.config.api,credentials:e.config.credentials,id:e.agentSessionId,update:t})}}}async function dispatchAgentSession(e){let{event:t}=e,n={delivery:t.delivery,linear:buildLinearHandle({agentSessionId:t.agentSession.id,config:e.config}),session:t.agentSession},r=await e.onAgentSession(n,t);if(r===null)return;let i=await attachLinearInboundImages({content:messageFromLinearAgentSessionEvent(t),credentials:e.config.credentials,fetch:e.config.api?.fetch});await e.send({context:[formatLinearContextBlock(t),...t.previousComments,...r.context??[]],message:i},{auth:r.auth,continuationToken:linearContinuationToken(t.agentSession.id),state:stateFromAgentSession(t.agentSession)})}async function resolveReceiveSession(e,t){if(hasString(e,`agentSessionId`))return{id:e.agentSessionId};if(hasString(e,`issueId`))return createLinearAgentSessionOnIssue({api:t.api,credentials:t.credentials,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls),issueId:e.issueId});if(hasString(e,`commentId`))return createLinearAgentSessionOnComment({api:t.api,credentials:t.credentials,commentId:e.commentId,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls)});throw Error(`linearChannel().receive requires target.agentSessionId, issueId, or commentId.`)}function stateFromAgentSession(e){return{agentSessionId:e.id,agentSessionUrl:e.url??null,commentId:e.commentId??null,issueId:e.issueId??e.issue?.id??null,issueIdentifier:e.issue?.identifier??null,issueTitle:e.issue?.title??null,issueUrl:e.issue?.url??null,organizationId:`organizationId`in e?e.organizationId??null:null,pendingToolCallMessage:null,sourceCommentId:e.sourceCommentId??null}}function initialLinearState(){return{agentSessionId:null,agentSessionUrl:null,commentId:null,issueId:null,issueIdentifier:null,issueTitle:null,issueUrl:null,organizationId:null,pendingToolCallMessage:null,sourceCommentId:null}}async function verifyInbound(e,t){try{return await verifyLinearRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`linear inbound verification failed`,{error:e}),null}}function hasString(e,t){return typeof e[t]==`string`&&e[t].length>0}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}function readExternalUrls(e){if(!Array.isArray(e))return;let n=e.filter(e=>isObject(e)&&typeof e.label==`string`&&typeof e.url==`string`);return n.length>0?n:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{linearChannel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const SLACK_TYPING_STATUS_MAX_LENGTH=50,SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH=75,SLACK_SECTION_TEXT_MAX_LENGTH=3e3,SLACK_CARD_BODY_TEXT_MAX_LENGTH=200,SLACK_CARD_SUBTEXT_MAX_LENGTH=200,SLACK_MESSAGE_TEXT_MAX_LENGTH=4e4,SLACK_MAX_BLOCKS_PER_MESSAGE=50,SLACK_MODAL_TITLE_MAX_LENGTH=24;function truncateTypingStatus(e){return truncateWithEllipsis(stripTypingStatusMarkdown(e).trim().replace(/\s+/gu,` `),50)}function truncatePlainText(e){if(e!==void 0)return truncateWithEllipsis(e,75)}function truncateSectionText(e){return truncateWithEllipsis(e,SLACK_SECTION_TEXT_MAX_LENGTH)}function truncateCardBodyText(e){return truncateWithEllipsis(e,200)}function truncateCardSubtext(e){return truncateWithEllipsis(e,200)}function truncateMessageText(e){return truncateWithEllipsis(e,SLACK_MESSAGE_TEXT_MAX_LENGTH)}function truncateModalTitle(e){return truncateWithEllipsis(e,24)}function truncateWithEllipsis(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function stripTypingStatusMarkdown(e){return e.replace(/\[([^\]]+)\]\([^)]+\)/gu,`$1`).replace(/`([^`]+)`/gu,`$1`).replace(/~~([^~]+)~~/gu,`$1`).replace(/(\*\*|__)([^*_]+)\
|
|
1
|
+
const SLACK_TYPING_STATUS_MAX_LENGTH=50,SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH=75,SLACK_SECTION_TEXT_MAX_LENGTH=3e3,SLACK_CARD_BODY_TEXT_MAX_LENGTH=200,SLACK_CARD_SUBTEXT_MAX_LENGTH=200,SLACK_MESSAGE_TEXT_MAX_LENGTH=4e4,SLACK_MAX_BLOCKS_PER_MESSAGE=50,SLACK_MODAL_TITLE_MAX_LENGTH=24;function truncateTypingStatus(e){return truncateWithEllipsis(stripTypingStatusMarkdown(e).trim().replace(/\s+/gu,` `),50)}function truncatePlainText(e){if(e!==void 0)return truncateWithEllipsis(e,75)}function truncateSectionText(e){return truncateWithEllipsis(e,SLACK_SECTION_TEXT_MAX_LENGTH)}function truncateCardBodyText(e){return truncateWithEllipsis(e,200)}function truncateCardSubtext(e){return truncateWithEllipsis(e,200)}function truncateMessageText(e){return truncateWithEllipsis(e,SLACK_MESSAGE_TEXT_MAX_LENGTH)}function truncateModalTitle(e){return truncateWithEllipsis(e,24)}function truncateWithEllipsis(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function stripTypingStatusMarkdown(e){return e.replace(/\[([^\]]+)\]\([^)]+\)/gu,`$1`).replace(/`([^`]+)`/gu,`$1`).replace(/~~([^~]+)~~/gu,`$1`).replace(/(^|[^\p{L}\p{N}])(\*\*|__)([^*_]+)\2(?=$|[^\p{L}\p{N}])/gu,`$1$3`).replace(/(^|[^\p{L}\p{N}*])\*([^*_]+)\*(?=$|[^\p{L}\p{N}*])/gu,`$1$2`).replace(/(^|[^\p{L}\p{N}_])_([^*_]+)_(?=$|[^\p{L}\p{N}_])/gu,`$1$2`)}export{SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH,SLACK_CARD_BODY_TEXT_MAX_LENGTH,SLACK_CARD_SUBTEXT_MAX_LENGTH,SLACK_MAX_BLOCKS_PER_MESSAGE,SLACK_MESSAGE_TEXT_MAX_LENGTH,SLACK_MODAL_TITLE_MAX_LENGTH,SLACK_SECTION_TEXT_MAX_LENGTH,SLACK_TYPING_STATUS_MAX_LENGTH,truncateCardBodyText,truncateCardSubtext,truncateMessageText,truncateModalTitle,truncatePlainText,truncateSectionText,truncateTypingStatus};
|
|
@@ -12,7 +12,7 @@ export type { CancelTurnInput, CancelTurnResult, GetEventStreamOptions } from "#
|
|
|
12
12
|
export type { Session, SessionHandle } from "#channel/session.js";
|
|
13
13
|
export type { ChannelCors, ChannelCorsOptions } from "#channel/cors.js";
|
|
14
14
|
export { GET, POST, PUT, PATCH, DELETE, WS } from "#channel/routes.js";
|
|
15
|
-
export type { CancelFn, CancelOptions, HttpRouteDefinition, RouteDefinition, RouteHandlerArgs, SendFn, SendOptions, SendPayload, ResolveActiveSessionFn, GetSessionFn, WebSocketMessage, WebSocketPeer, WebSocketRouteDefinition, WebSocketRouteHandler, WebSocketRouteHooks, WebSocketUpgradeRequest, WebSocketUpgradeResult, } from "#channel/routes.js";
|
|
15
|
+
export type { CancelFn, CancelOptions, ResetFn, ResetOptions, ResetResult, HttpRouteDefinition, RouteDefinition, RouteHandlerArgs, SendFn, SendOptions, SendPayload, ResolveActiveSessionFn, GetSessionFn, WebSocketMessage, WebSocketPeer, WebSocketRouteDefinition, WebSocketRouteHandler, WebSocketRouteHooks, WebSocketUpgradeRequest, WebSocketUpgradeResult, } from "#channel/routes.js";
|
|
16
16
|
/**
|
|
17
17
|
* HTTP method a route handles. Defaults to `"POST"` — almost every route
|
|
18
18
|
* is a webhook. Override only when authoring a non-webhook route such as a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname,join,relative}from"node:path";import{mkdir,readFile,writeFile}from"node:fs/promises";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{findClosestLinkedVercelDirectory,findClosestVercelOutputDirectory}from"#shared/vercel-output-directory.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,VERCEL_OUTPUT_CONFIG_FILE_NAME=`.vercel/output/config.json`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasServices(e){return e!==void 0&&Object.keys(createServiceConfigRecord(e)).length>0}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function resolveRelativeEntrypoint(e,t){let r=relative(e,t);return r.length===0?`.`:r.replaceAll(`\\`,`/`)}function quoteShellArgument(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function createGeneratedServiceBuild(e){let n=join(e.nextRoot,`.eve/vercel-services`,e.serviceName),
|
|
1
|
+
import{dirname,join,relative}from"node:path";import{EVE_PUBLIC_ROUTE_PREFIX_ENV,normalizePublicRoutePrefix}from"#shared/public-route-prefix.js";import{mkdir,readFile,writeFile}from"node:fs/promises";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{findClosestLinkedVercelDirectory,findClosestVercelOutputDirectory}from"#shared/vercel-output-directory.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,VERCEL_OUTPUT_CONFIG_FILE_NAME=`.vercel/output/config.json`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasServices(e){return e!==void 0&&Object.keys(createServiceConfigRecord(e)).length>0}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function resolveRelativeEntrypoint(e,t){let r=relative(e,t);return r.length===0?`.`:r.replaceAll(`\\`,`/`)}function quoteShellArgument(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function createGeneratedServiceBuild(e){let n=join(e.nextRoot,`.eve/vercel-services`,e.serviceName),a=join(n,`.vercel`,`output`),o=resolveRelativeEntrypoint(n,e.agent.appRoot),s=resolveRelativeEntrypoint(e.agent.appRoot,a),u=resolveRelativeEntrypoint(e.agent.appRoot,e.hostOutputDirectory),d=normalizePublicRoutePrefix(e.agent.publicRoutePrefix),f=d===void 0?``:` && export ${EVE_PUBLIC_ROUTE_PREFIX_ENV}=${quoteShellArgument(d)}`;return{buildCommand:`cd ${quoteShellArgument(o)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(s)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(u)}${f} && ${e.agent.buildCommand}`,root:resolveRelativeEntrypoint(e.nextRoot,n),rootDirectory:n}}async function resolveVercelOutputConfigLocation(n){let r=await findClosestLinkedVercelDirectory(n),i=r===void 0?n:dirname(r),a=await findClosestVercelOutputDirectory(n);return a===void 0?r===void 0?{canWriteGeneratedOutput:!!process.env.VERCEL,outputConfigPath:join(n,VERCEL_OUTPUT_CONFIG_FILE_NAME),projectRoot:i}:{canWriteGeneratedOutput:!0,outputConfigPath:join(r,`output`,`config.json`),projectRoot:i}:{canWriteGeneratedOutput:!0,outputConfigPath:join(a,`config.json`),projectRoot:i}}function normalizeVercelServicesConfig(e,t){if(!isRecord(e))throw Error(`${t} must contain a JSON object.`);let n=e.services;if(n!==void 0&&!isRecord(n)&&!(Array.isArray(n)&&n.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${t} services must be a JSON object or named service array.`);let r=e.routes;if(r!==void 0&&!Array.isArray(r))throw Error(`${t} routes must be an array.`);return e}async function readVercelServicesConfig(e,t){try{return normalizeVercelServicesConfig(JSON.parse(await readFile(e,`utf8`)),t)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findServiceEntryByFramework(e,t){return Object.entries(e).map(([e,t])=>({name:e,service:t})).find(e=>e.service.framework===t)}function findServiceEntryByName(e,t){let n=e[t];return n===void 0?void 0:{name:t,service:n}}function resolveServicePrefix(e){if(e!==void 0){if(typeof e.routePrefix==`string`&&e.routePrefix.trim().length>0)return e.routePrefix.trim();if(typeof e.mount==`string`&&e.mount.trim().length>0)return e.mount.trim();if(isRecord(e.mount)&&typeof e.mount.path==`string`&&e.mount.path.trim().length>0)return e.mount.path.trim()}}function resolveConfiguredServicePrefix(e){let t=findConfiguredEveServiceEntry(e.services,e.agent)?.service;return resolveServicePrefix(t)??e.agent.servicePrefix}function findConfiguredEveServiceEntry(e,t){if(t.name!==void 0){let n=findServiceEntryByName(e,createEveServiceName(t.name));if(n?.service.framework===`eve`)return n}return t.name===void 0?findServiceEntryByFramework(e,`eve`):void 0}function assertRootServicesIncludeEve(e){let t=[];for(let n of e.agents){let r=findConfiguredEveServiceEntry(e.services,n)?.service;if(r===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so withEve cannot add generated eve services through ${VERCEL_OUTPUT_CONFIG_FILE_NAME}. Add the eve service for ${n.name??`the default agent`} to ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`);t.push({name:n.name,servicePrefix:resolveServicePrefix(r)??n.servicePrefix})}return t}function createEveServiceRouteSrc(e){return e.length===0?`^/eve/v1/(.*)$`:`^${escapeRegExp(e.startsWith(`/`)?e:`/${e}`)}/eve/v1/(.*)$`}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function createEveServiceName(e){return e===void 0?`eve`:`eve-${e}`}function isEveServiceRoute(e,t,n){let r=e.destination;return e.src===n&&isRecord(r)&&r.type===`service`&&r.service===t}function createEveServiceRoute(e,t){return{destination:{service:e,type:`service`},src:t}}function isEveServiceRequestPathRoute(e,t){return e.src===t}function createEveServiceRequestPathRoute(e){return{src:e,transforms:[{args:`/eve/v1/$1`,op:`set`,type:`request.path`}]}}function insertEveServiceRequestPathRoute(e,t){let n=(e??[]).filter(e=>!isEveServiceRequestPathRoute(e,t));return[createEveServiceRequestPathRoute(t),...n]}function insertEveServiceRoutes(e,t){let n=e.filter(e=>!t.some(t=>isEveServiceRoute(e,t.serviceName,t.routeSrc))),r=n.findIndex(e=>e.handle===`filesystem`),i=t.map(e=>createEveServiceRoute(e.serviceName,e.routeSrc));return r===-1?[...i,...n]:[...n.slice(0,r),...i,...n.slice(r)]}async function ensureEveVercelOutputConfig(n){let{canWriteGeneratedOutput:r,outputConfigPath:i,projectRoot:o}=await resolveVercelOutputConfigLocation(n.nextRoot),c=(await readVercelServicesConfig(join(o,VERCEL_JSON_FILE_NAME),VERCEL_JSON_FILE_NAME)).services;if(hasServices(c))return{agents:assertRootServicesIncludeEve({agents:n.agents,services:createServiceConfigRecord(c)})};let l=await readVercelServicesConfig(i,VERCEL_OUTPUT_CONFIG_FILE_NAME),u=createServiceConfigRecord(l.services),d=n.agents.map(e=>({name:e.name,servicePrefix:resolveConfiguredServicePrefix({agent:e,services:u})}));if(!r)return{agents:d};let p={...u},m=[];for(let t of n.agents){let r=findConfiguredEveServiceEntry(u,t),o=r?.name??createEveServiceName(t.name),s=createEveServiceRouteSrc(t.publicRoutePrefix);if(r===void 0){let r=createGeneratedServiceBuild({agent:t,hostOutputDirectory:dirname(i),nextRoot:n.nextRoot,serviceName:o});await mkdir(r.rootDirectory,{recursive:!0});let c={buildCommand:r.buildCommand,framework:`eve`,routes:insertEveServiceRequestPathRoute(void 0,s),root:r.root};t.publicRoutePrefix.length>0&&(c.routePrefix=t.publicRoutePrefix),p[o]=c}else p[o]={...r.service,routes:insertEveServiceRequestPathRoute(r.service.routes,s)};m.push({routeSrc:s,serviceName:o})}let{services:h,...g}=l,_={...g,routes:insertEveServiceRoutes(l.routes??[],m),services:p,version:3};return JSON.stringify(l)!==JSON.stringify(_)&&(await mkdir(dirname(i),{recursive:!0}),await writeFile(i,`${JSON.stringify(_,null,2)}\n`)),{agents:d}}export{ensureEveVercelOutputConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolvePackageSourceFilePath}from"#internal/application/package.js";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{getRuntimeCompiledArtifactsCacheKey}from"#runtime/compiled-artifacts-source.js";import{loadCompiledManifest}from"#runtime/loaders/manifest.js";import{resolveRuntimeAgentGraph}from"#runtime/resolve-agent-graph.js";import{pathToFileURL}from"node:url";import{loadCompiledModuleMap}from"#runtime/loaders/module-map.js";import{getActiveRuntimeSession}from"#runtime/sessions/runtime-session.js";import{
|
|
1
|
+
import{resolvePackageSourceFilePath}from"#internal/application/package.js";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{getRuntimeCompiledArtifactsCacheKey}from"#runtime/compiled-artifacts-source.js";import{loadCompiledManifest}from"#runtime/loaders/manifest.js";import{resolveRuntimeAgentGraph}from"#runtime/resolve-agent-graph.js";import{resolveRuntimeCompiledArtifactsVersionedCacheKey}from"#runtime/cache-key.js";import{pathToFileURL}from"node:url";import{loadCompiledModuleMap}from"#runtime/loaders/module-map.js";import{getActiveRuntimeSession}from"#runtime/sessions/runtime-session.js";import{createRuntimeAdapterRegistry}from"#runtime/channels/registry.js";const isCacheDisabled=process.env.EVE_DISABLE_AGENT_CACHE===`1`;function isDevelopmentRuntimeSnapshotRoot(e){return e.replaceAll(`\\`,`/`).includes(`/.eve/dev-runtime/snapshots/`)}function normalizeCompiledArtifactsSource(t){return t.kind!==`disk`||t.moduleMapLoaderPath!==void 0||!isDevelopmentRuntimeSnapshotRoot(t.appRoot)?t:{...t,moduleMapLoaderPath:resolvePackageSourceFilePath(`src/internal/authored-module-map-loader.ts`)}}async function loadFullBundle(e){let t=normalizeCompiledArtifactsSource(e),[n,a]=await Promise.all([loadCompiledManifest({compiledArtifactsSource:t}),loadRuntimeCompiledModuleMap(t)]),o=await resolveRuntimeAgentGraph({manifest:n,moduleMap:a}),s=o.root;return{adapterRegistry:createRuntimeAdapterRegistry({channels:collectResolvedChannels(o)}),compiledArtifactsSource:t,graph:o,hookRegistry:s.hookRegistry,moduleMap:a,resolvedAgent:s.agent,subagentRegistry:s.subagentRegistry,toolRegistry:s.toolRegistry,turnAgent:s.turnAgent}}async function loadRuntimeCompiledModuleMap(e){return e.kind===`disk`&&e.moduleMapLoaderPath!==void 0?await loadAuthoredSourceCompiledModuleMap(e):await loadCompiledModuleMap({compiledArtifactsSource:e})}async function loadAuthoredSourceCompiledModuleMap(e){if(e.moduleMapLoaderPath===void 0)throw Error(`Authored-source module map loading requires "moduleMapLoaderPath" in the compiled artifacts source.`);return await(await import(pathToFileURL(e.moduleMapLoaderPath).href)).loadCompiledModuleMapFromAuthoredSource({compiledArtifactsSource:e})}async function getOrLoadFullBundle(e){let t=normalizeCompiledArtifactsSource(e);if(isCacheDisabled)return loadFullBundle(t);let r=getActiveRuntimeSession(),i=getRuntimeCompiledArtifactsCacheKey(t),o=await resolveRuntimeCompiledArtifactsVersionedCacheKey(t),s=r.bundleCacheKeyBySourceKey.get(i);s!==void 0&&s!==o&&r.bundleCache.delete(s),r.bundleCacheKeyBySourceKey.set(i,o);let c=r.bundleCache.get(o);if(c!==void 0)return c;let l=loadFullBundle(t).catch(e=>{throw r.bundleCache.delete(o),r.bundleCacheKeyBySourceKey.get(i)===o&&r.bundleCacheKeyBySourceKey.delete(i),e});return r.bundleCache.set(o,l),l}async function getCompiledRuntimeAgentBundle(e){let n=await getOrLoadFullBundle(e.compiledArtifactsSource);if(e.nodeId===void 0)return n;let r=getResolvedRuntimeAgentNode(n.graph,e.nodeId);return{adapterRegistry:n.adapterRegistry,compiledArtifactsSource:n.compiledArtifactsSource,graph:{nodesByNodeId:n.graph.nodesByNodeId,root:r},hookRegistry:r.hookRegistry,moduleMap:n.moduleMap,nodeId:e.nodeId,resolvedAgent:r.agent,subagentRegistry:r.subagentRegistry,toolRegistry:r.toolRegistry,turnAgent:r.turnAgent}}function clearCompiledRuntimeAgentBundleCache(){let e=getActiveRuntimeSession();e.bundleCache.clear(),e.bundleCacheKeyBySourceKey.clear()}function collectResolvedChannels(e){let t=new Map;for(let n of e.nodesByNodeId.values())for(let e of n.channels)t.set(`${e.sourceId}:${e.name}`,e);return[...t.values()]}export{clearCompiledRuntimeAgentBundleCache,getCompiledRuntimeAgentBundle};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { detectPackageManager } from "#setup/package-manager.js";
|
|
2
|
-
import { spawnPackageManager } from "#setup/primitives/index.js";
|
|
2
|
+
import { runVercel, spawnPackageManager } from "#setup/primitives/index.js";
|
|
3
3
|
import { getVercelAuthStatus } from "#setup/vercel-project.js";
|
|
4
4
|
import type { Prompter } from "../prompter.js";
|
|
5
5
|
export type InstallVercelCliResult =
|
|
@@ -14,6 +14,7 @@ export type InstallVercelCliResult =
|
|
|
14
14
|
/** The install exited non-zero, or the CLI still isn't on PATH afterward. */
|
|
15
15
|
| {
|
|
16
16
|
kind: "failed";
|
|
17
|
+
reason?: string;
|
|
17
18
|
}
|
|
18
19
|
/** The user interrupted (Ctrl-C / Esc) before the install finished. */
|
|
19
20
|
| {
|
|
@@ -23,6 +24,7 @@ export type InstallVercelCliResult =
|
|
|
23
24
|
export interface InstallVercelCliDeps {
|
|
24
25
|
getVercelAuthStatus: typeof getVercelAuthStatus;
|
|
25
26
|
detectPackageManager: typeof detectPackageManager;
|
|
27
|
+
runVercel: typeof runVercel;
|
|
26
28
|
spawnPackageManager: typeof spawnPackageManager;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
@@ -32,11 +34,15 @@ export interface InstallVercelCliDeps {
|
|
|
32
34
|
* global install with the project's package manager, streaming output to the
|
|
33
35
|
* rail, then re-probes. A global install can exit clean yet leave the binary
|
|
34
36
|
* off PATH (pnpm/yarn global bins commonly aren't), so success is confirmed by
|
|
35
|
-
* the re-probe, not the exit code alone.
|
|
37
|
+
* the re-probe, not the exit code alone. `upgrade` invokes the active Vercel
|
|
38
|
+
* CLI's native upgrader so it can update the installation that owns that
|
|
39
|
+
* executable, independent of the project's package manager.
|
|
36
40
|
*/
|
|
37
41
|
export declare function runInstallVercelCliFlow(input: {
|
|
38
42
|
appRoot: string;
|
|
39
43
|
prompter: Prompter;
|
|
44
|
+
/** Reinstall the latest CLI even when an existing binary resolves. */
|
|
45
|
+
upgrade?: boolean;
|
|
40
46
|
signal?: AbortSignal;
|
|
41
47
|
deps?: Partial<InstallVercelCliDeps>;
|
|
42
48
|
}): Promise<InstallVercelCliResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{withSpinner}from"../with-spinner.js";import{detectPackageManager}from"#setup/package-manager.js";import{spawnPackageManager}from"#setup/primitives/index.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";const defaultDeps={getVercelAuthStatus,detectPackageManager,spawnPackageManager};function globalInstallArguments(e){switch(e){case`npm`:return[`install`,`-g`,`vercel@latest`];case`yarn`:return[`global`,`add`,`vercel@latest`];case`pnpm`:case`bun`:return[`add`,`-g`,`vercel@latest`]}}async function runInstallVercelCliFlow(t){let{appRoot:n,prompter:r,signal:i}=t,a={...defaultDeps,...t.deps},o=createPromptCommandOutput(r.log),probe=async()=>await a.getVercelAuthStatus(n,{signal:i})!==`cli-missing`;if(await withSpinner(r,`Checking for the Vercel CLI…`,probe))return i?.throwIfAborted(),{kind:`already`};i?.throwIfAborted();let s=await a.
|
|
1
|
+
import{withSpinner}from"../with-spinner.js";import{detectPackageManager}from"#setup/package-manager.js";import{runVercel,spawnPackageManager}from"#setup/primitives/index.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";const defaultDeps={getVercelAuthStatus,detectPackageManager,runVercel,spawnPackageManager};function globalInstallArguments(e){switch(e){case`npm`:return[`install`,`-g`,`vercel@latest`];case`yarn`:return[`global`,`add`,`vercel@latest`];case`pnpm`:case`bun`:return[`add`,`-g`,`vercel@latest`]}}function summarizeUpgradeFailure(e){let t=e.map(e=>e.trim().replace(/\s+/gu,` `)).filter(e=>e!==``&&e!==`}`&&!e.startsWith(`at `)&&!/^vercel upgrade exited with code \d+\.$/u.test(e)),n=t.find(e=>/^(?:error\b|err_|.*\b(?:cannot|failed|could not)\b)/iu.test(e))??t.at(-1);if(n!==void 0)return n.length<=240?n:`${n.slice(0,239)}…`}async function runInstallVercelCliFlow(t){let{appRoot:n,prompter:r,signal:i}=t,a={...defaultDeps,...t.deps},o=createPromptCommandOutput(r.log),probe=async()=>await a.getVercelAuthStatus(n,{signal:i})!==`cli-missing`;if(!t.upgrade&&await withSpinner(r,`Checking for the Vercel CLI…`,probe))return i?.throwIfAborted(),{kind:`already`};i?.throwIfAborted();let s,c;if(t.upgrade){let t=[];s=await withSpinner(r,`Upgrading the Vercel CLI…`,async()=>{let e=await a.runVercel([`upgrade`],{cwd:n,onOutput:e=>{o(e),e.stream===`stderr`&&t.push(e.text)},signal:i,nonInteractive:!0});return e||(c=summarizeUpgradeFailure(t)),e})}else{let t=await a.detectPackageManager(n);s=await withSpinner(r,`Installing the Vercel CLI with ${t.kind}…`,()=>a.spawnPackageManager(t.kind,n,globalInstallArguments(t.kind),{onOutput:o,signal:i,nonInteractive:!0}))}if(i?.aborted===!0)return{kind:`cancelled`};if(!s)return c===void 0?{kind:`failed`}:{kind:`failed`,reason:c};let l=await withSpinner(r,`Verifying the Vercel CLI…`,probe);return i?.throwIfAborted(),l?{kind:`installed`}:t.upgrade?{kind:`failed`,reason:`The Vercel CLI could not be found after the upgrade completed.`}:{kind:`failed`}}export{runInstallVercelCliFlow};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.34`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.27.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.34`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.27.4`,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){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).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__",
|
|
@@ -24,7 +24,7 @@ export interface VercelProjectSearchPage {
|
|
|
24
24
|
export declare function parseVercelJson(stdout: string, description: string): unknown;
|
|
25
25
|
/** Converts a scoped API denial into the Vercel re-authentication action. */
|
|
26
26
|
export declare function requireVercelTeamAccess(failure: VercelCaptureFailure): never;
|
|
27
|
-
/** Lists
|
|
27
|
+
/** Lists up to the maximum 100 Vercel scopes supported by the CLI. */
|
|
28
28
|
export declare function listTeams(projectRoot: string, options?: VercelProjectOperationOptions): Promise<VercelTeamListEntry[]>;
|
|
29
29
|
/** Lists the 20 most recent Vercel projects in one account scope. */
|
|
30
30
|
export declare function listRecentProjects(projectRoot: string, team: string, options?: VercelProjectOperationOptions): Promise<VercelProjectListEntry[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{array,boolean,number,object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isForbiddenApiFailure}from"./vercel-api-failure.js";import{captureVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";const VERCEL_PROJECT_REQUEST_TIMEOUT_MS=15e3,VercelTeamListEntrySchema=object({name:string(),slug:string(),current:boolean()}),VercelProjectListEntrySchema=object({name:string(),id:string()}),VercelPaginationSchema=object({next:number().int().nonnegative().nullable().optional()}),VercelTeamPageSchema=object({teams:array(VercelTeamListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>
|
|
1
|
+
import{array,boolean,number,object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isForbiddenApiFailure}from"./vercel-api-failure.js";import{captureVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";const VERCEL_PROJECT_REQUEST_TIMEOUT_MS=15e3,VercelTeamListEntrySchema=object({name:string(),slug:string(),current:boolean()}),VercelProjectListEntrySchema=object({name:string(),id:string()}),VercelPaginationSchema=object({next:number().int().nonnegative().nullable().optional()}),VercelTeamPageSchema=object({teams:array(VercelTeamListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>e.teams),VercelProjectPageSchema=object({projects:array(VercelProjectListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.projects,next:e.pagination?.next??void 0}));function parseVercelJson(e,t){try{return JSON.parse(e)}catch{throw Error(`Could not parse ${t} JSON from Vercel CLI output.`)}}function requireVercelTeamAccess(e){let t=e.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-forbidden`,command:`vercel login`,reason:`Vercel denied access to this scope.${t?` ${t}`:``} Re-authenticate (for example to complete a team's SSO) or switch to a team you can access.`})}function isUnsupportedTeamListFailure(e){let t=`${e.stderr}\n${e.stdout}`;return/(?:unknown|unexpected|invalid).*(?:--format|--limit)/iu.test(t)}function requireVercelCliUpgrade(e){throw new HumanActionRequiredError({kind:`vercel-cli-upgrade`,command:`vercel upgrade`,reason:`The installed Vercel CLI does not support the team-list options eve needs. ${e.message} Upgrade it and retry.`})}async function captureTeamPage(e,t,n){let r=await captureVercel(n,{cwd:e,signal:t.signal});if(t.signal?.throwIfAborted(),!r.ok)throw isForbiddenApiFailure(r.failure)&&requireVercelTeamAccess(r.failure),isUnsupportedTeamListFailure(r.failure)&&requireVercelCliUpgrade(r.failure),Error(`Could not list Vercel teams. ${r.failure.message}`);return r.stdout}async function listTeams(e,t={}){let n=await captureTeamPage(e,t,[`teams`,`ls`,`--format`,`json`,`--limit`,`100`]),r=VercelTeamPageSchema.safeParse(parseVercelJson(n,`teams`));if(!r.success)throw Error(`Could not read teams from Vercel CLI JSON output.`);return r.data}async function fetchProjectPage(e,t,n){let r=[`project`,`ls`,`--format`,`json`,`--scope`,t];n.search!==void 0&&r.push(`--filter`,n.search),n.next!==void 0&&r.push(`--next`,String(n.next));let i=await captureVercel(r,{cwd:e,signal:n.signal,timeoutMs:VERCEL_PROJECT_REQUEST_TIMEOUT_MS});if(n.signal?.throwIfAborted(),!i.ok)throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not list Vercel projects in ${t}. ${i.failure.message}`);let s=VercelProjectPageSchema.safeParse(parseVercelJson(i.stdout,`projects`));if(!s.success)throw Error(`Could not read projects from Vercel CLI JSON output.`);return s.data}async function listRecentProjects(e,t,n={}){return(await fetchProjectPage(e,t,n)).items}function projectSearchRank(e,t){let n=e.name.toLowerCase(),r=t.toLowerCase();return n===r?0:n.startsWith(r)?1:2}function rankProjectSearchResults(e,t){let n=t.trim();return[...e].sort((e,t)=>projectSearchRank(e,n)-projectSearchRank(t,n))}async function searchProjects(e,t,n,r={}){let i=n.trim();if(i.length===0)throw Error(`Project search query cannot be empty.`);let a=await fetchProjectPage(e,t,{...r,search:i}),o=rankProjectSearchResults(a.items,i);return a.next===void 0?{projects:o}:{projects:o,next:a.next}}export{VERCEL_PROJECT_REQUEST_TIMEOUT_MS,listRecentProjects,listTeams,parseVercelJson,rankProjectSearchResults,requireVercelTeamAccess,searchProjects};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable naming the public route prefix an eve agent's
|
|
3
|
+
* `/eve/v1/*` transport surface is mounted under on its callback origin.
|
|
4
|
+
*
|
|
5
|
+
* Multi-agent host integrations mount each named agent under
|
|
6
|
+
* `/eve/agents/<name>/eve/v1/*` and strip that prefix before requests reach
|
|
7
|
+
* the eve service, so a running agent cannot recover its own public mount
|
|
8
|
+
* from an inbound request. The integration exports this variable in the
|
|
9
|
+
* generated service build command, the eve CLI resolves it once into the
|
|
10
|
+
* build input, the build bakes it into every emitted Vercel workflow function
|
|
11
|
+
* environment, and callback-URL minting prepends it so framework-owned
|
|
12
|
+
* callbacks resolve to a routable public path.
|
|
13
|
+
*
|
|
14
|
+
* Self-hosted deployments that proxy an agent behind a path prefix can set
|
|
15
|
+
* it directly on the runtime environment.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EVE_PUBLIC_ROUTE_PREFIX_ENV = "EVE_PUBLIC_ROUTE_PREFIX";
|
|
18
|
+
/**
|
|
19
|
+
* Normalizes a public route prefix to `/segment(/segment)*` form: adds the
|
|
20
|
+
* leading slash, strips trailing slashes, and returns `undefined` for
|
|
21
|
+
* values that resolve to the root route (empty, blank, or `/`).
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizePublicRoutePrefix(value: string | undefined): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const EVE_PUBLIC_ROUTE_PREFIX_ENV=`EVE_PUBLIC_ROUTE_PREFIX`;function normalizePublicRoutePrefix(e){let t=e?.trim();if(t===void 0||t.length===0)return;let n=(t.startsWith(`/`)?t:`/${t}`).replace(/\/+$/,``);return n.length===0?void 0:n}export{EVE_PUBLIC_ROUTE_PREFIX_ENV,normalizePublicRoutePrefix};
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.js
CHANGED
package/docs/channels/custom.mdx
CHANGED
|
@@ -48,6 +48,7 @@ Declare routes with the `POST()` and `GET()` helpers. Each route handler receive
|
|
|
48
48
|
|
|
49
49
|
- `send(message, { auth, continuationToken, state?, title? })` starts or resumes a session. `title` overrides the new workflow session's display title without changing the model message. Returns a `Session`.
|
|
50
50
|
- `cancel({ continuationToken, turnId? })` requests cancellation of the active turn on the session that owns the token. See [Cancel a turn](#cancel-a-turn).
|
|
51
|
+
- `reset({ continuationToken, reason? })` retires the session that owns the token so the next `send()` starts a fresh session. See [Reset a session](#reset-a-session).
|
|
51
52
|
- `getSession(sessionId)` looks up an existing session. The returned `Session` exposes `getEventStream({ startIndex? })` for streaming and `cancel({ turnId? })` for session-id-addressed cancellation.
|
|
52
53
|
- `receive(channel, ...)` hands inbound work to a different channel for cross-channel hand-off.
|
|
53
54
|
- `params` holds route parameters extracted from the path pattern.
|
|
@@ -85,6 +86,40 @@ Semantics:
|
|
|
85
86
|
|
|
86
87
|
When you already hold a `Session` — returned by `send()` or `getSession(sessionId)` — call `session.cancel({ turnId? })` to request the same cancellation addressed by session id.
|
|
87
88
|
|
|
89
|
+
## Reset a session
|
|
90
|
+
|
|
91
|
+
Identity-addressed channels can consume commands such as `/new` in their route, without sending the command to the model. Call `reset` with the same channel-local continuation token used by `send()`:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { defineChannel, POST } from "eve/channels";
|
|
95
|
+
|
|
96
|
+
export default defineChannel({
|
|
97
|
+
routes: [
|
|
98
|
+
POST("/messages", async (request, { reset, send }) => {
|
|
99
|
+
const body = await request.json();
|
|
100
|
+
|
|
101
|
+
if (body.message.trim().toLowerCase() === "/new") {
|
|
102
|
+
await reset({
|
|
103
|
+
continuationToken: body.conversationId,
|
|
104
|
+
reason: "User requested /new",
|
|
105
|
+
});
|
|
106
|
+
return Response.json({ message: "Started a new conversation." });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const session = await send(body.message, {
|
|
110
|
+
auth: null,
|
|
111
|
+
continuationToken: body.conversationId,
|
|
112
|
+
});
|
|
113
|
+
return Response.json({ sessionId: session.id });
|
|
114
|
+
}),
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`reset` returns `{ status: "reset", previousSessionId }` when it observed an owner, or `{ status: "no_active_session" }` when the token was already free. Both outcomes are successful. It terminally cancels the observed workflow run and waits until its non-retained continuation hook no longer blocks reuse, so the next `send()` using the same token creates a new session with fresh history and state.
|
|
120
|
+
|
|
121
|
+
The replacement session owns a new session-scoped sandbox. eve initializes it lazily on that session's first sandbox use, so it never reuses the prior session's workspace or sandbox state. Resetting does not clear history in place, roll back tool calls, or delete the previous run or its sandbox; normal retention and backend cleanup policies still apply. Side effects or partial output that were already committed remain committed. Authenticate and deduplicate inbound command webhooks before calling this helper: a delayed duplicate `/new` can otherwise reset a newer session that has already reclaimed the same token.
|
|
122
|
+
|
|
88
123
|
## CORS
|
|
89
124
|
|
|
90
125
|
Custom HTTP channels leave CORS untouched unless you opt in. Pass `cors: true`
|
|
@@ -125,7 +160,7 @@ export default defineChannel({
|
|
|
125
160
|
});
|
|
126
161
|
```
|
|
127
162
|
|
|
128
|
-
`WS()` handlers receive the same helpers as HTTP route handlers: `send`, `cancel`, `getSession`, `receive`, `params`, `waitUntil`, and `requestIp`. The returned hooks are eve-owned structural types compatible with Nitro/H3 websocket routing, including `upgrade`, `open`, `message`, `close`, and `error`.
|
|
163
|
+
`WS()` handlers receive the same helpers as HTTP route handlers: `send`, `cancel`, `reset`, `getSession`, `receive`, `params`, `waitUntil`, and `requestIp`. The returned hooks are eve-owned structural types compatible with Nitro/H3 websocket routing, including `upgrade`, `open`, `message`, `close`, and `error`.
|
|
129
164
|
|
|
130
165
|
### Node upgrade server escape hatch
|
|
131
166
|
|
|
@@ -245,6 +280,8 @@ Custom channels write their own function that joins the identity fields. The fra
|
|
|
245
280
|
|
|
246
281
|
When the identity that should address a session is not known until later, the channel can re-key the parked session by calling `session.setContinuationToken(...)`. Pass the channel-local raw token; the runtime preserves the current channel namespace.
|
|
247
282
|
|
|
283
|
+
Re-keying changes the address of the current session. `reset` is different: it terminally retires the current session and makes its existing address available to a later `send()`. `cancel` is narrower still: it stops only the active turn and leaves the session, history, and continuation-token ownership intact.
|
|
284
|
+
|
|
248
285
|
The `context(state, session)` config option builds the per-step `channel` argument handed to every event handler. It receives the channel's live adapter `state` and a `SessionHandle`, and returns the channel-owned context (thread handles, API clients, late-bound callbacks). The framework injects [`ChannelSessionOps`](#define-a-channel) and passes the result as the second positional argument to each handler. Closing over `session` lets the factory register callbacks that re-key the session later. State mutations made through the returned context are written back to adapter state.
|
|
249
286
|
|
|
250
287
|
```ts
|
package/docs/channels/linear.mdx
CHANGED
|
@@ -88,7 +88,7 @@ Start a session without an inbound webhook with `receive(linear, { target })`. S
|
|
|
88
88
|
|
|
89
89
|
### Attachments
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Markdown images hosted at `https://uploads.linear.app` in Agent Session prompts are fetched with the resolved Linear access token and included as image file parts. eve sends the bearer token only to that exact HTTPS origin; images from other hosts remain markdown text. If a Linear upload fails or returns non-image content, eve preserves its markdown reference and continues the text turn. Other inbound file attachments are not supported on this channel today.
|
|
92
92
|
|
|
93
93
|
### API handle
|
|
94
94
|
|