eve 0.45.2 → 0.46.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 +12 -0
- package/dist/src/channel/types.d.ts +2 -0
- package/dist/src/cli/dev/tui/agent-header.d.ts +5 -14
- package/dist/src/cli/dev/tui/agent-header.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +4 -5
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +3 -3
- package/dist/src/cli/run.js +3 -3
- package/dist/src/compiler/channel-route-plan.d.ts +2 -2
- package/dist/src/compiler/instrumentation-layout-config.d.ts +3 -0
- package/dist/src/compiler/instrumentation-layout-config.js +1 -0
- package/dist/src/compiler/load-binding-namespace.d.ts +5 -3
- package/dist/src/compiler/load-binding-namespace.js +1 -1
- package/dist/src/compiler/manifest.d.ts +2 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/module-lifecycle.d.ts +14 -0
- package/dist/src/compiler/module-lifecycle.js +1 -0
- package/dist/src/compiler/module-map.d.ts +2 -2
- package/dist/src/compiler/module-map.js +2 -2
- package/dist/src/compiler/node-source-state.d.ts +6 -3
- package/dist/src/compiler/node-source-state.js +1 -1
- package/dist/src/compiler/normalize-agent-config.d.ts +2 -2
- package/dist/src/compiler/normalize-helpers.d.ts +4 -4
- package/dist/src/compiler/normalize-manifest-helpers.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/remote-agent-node.js +1 -1
- package/dist/src/compiler/source-graph.d.ts +12 -2
- package/dist/src/compiler/source-graph.js +1 -1
- package/dist/src/compiler/validate-artifact.js +1 -1
- package/dist/src/context/keys.d.ts +2 -0
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/framework/sources/registry.js +1 -1
- package/dist/src/harness/channel-delivery-instrumentation.js +1 -1
- package/dist/src/harness/instrumentation/content-policy.d.ts +3 -2
- package/dist/src/harness/instrumentation/content-policy.js +1 -1
- package/dist/src/harness/instrumentation/content.d.ts +11 -0
- package/dist/src/harness/instrumentation/content.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/internal/application/compiled-artifacts.d.ts +7 -7
- package/dist/src/internal/application/compiled-artifacts.js +2 -3
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-asset-import-plugin.d.ts +6 -2
- package/dist/src/internal/authored-asset-import-plugin.js +1 -1
- package/dist/src/internal/authored-module-loader.js +3 -3
- package/dist/src/internal/authored-module-map-loader.js +1 -1
- package/dist/src/internal/authored-runtime-modules.d.ts +15 -0
- package/dist/src/internal/authored-runtime-modules.js +1 -0
- package/dist/src/internal/materialized-authored-modules.d.ts +2 -18
- package/dist/src/internal/materialized-authored-modules.js +1 -1
- package/dist/src/internal/nitro/development-generation.js +1 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
- package/dist/src/public/channels/slack/inbound-content.js +2 -2
- package/dist/src/public/instrumentation/otel.d.ts +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/shared/instrumentation-content.d.ts +6 -0
- package/dist/src/shared/instrumentation-content.js +1 -0
- package/dist/src/shared/instrumentation-decision.d.ts +8 -0
- package/dist/src/shared/instrumentation-decision.js +1 -0
- package/dist/src/tracing/agent-trace-context-store.d.ts +3 -3
- package/dist/src/tracing/agent-trace-context-store.js +1 -1
- package/dist/src/tracing/otel-declaration.d.ts +14 -3
- package/dist/src/tracing/sampled-trace.d.ts +8 -1
- package/dist/src/tracing/sampled-trace.js +1 -1
- package/docs/agent-config.md +2 -0
- package/docs/channels/slack.mdx +2 -0
- package/docs/guides/dynamic-capabilities.md +2 -0
- package/docs/instructions.mdx +3 -1
- package/docs/reference/typescript-api.md +25 -0
- package/docs/schedules.mdx +2 -0
- package/docs/skills.mdx +2 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{formatSlackLink}from"#compiled/@chat-adapter/slack/format.js";function resolveSlackInboundMrkdwn(e,t){try{return resolveSlackInboundMrkdwnUnsafe(e,t)}catch{return e}}function resolveSlackInboundMrkdwnUnsafe(e,t){let n=extractSlackStructuredMrkdwn(t.blocks,t.attachments),r=e.trim();if(!r)return n;if(!n||normalizeComparableText(n)===normalizeComparableText(r))return e;let i=normalizeComparableText(n),a=normalizeComparableText(r);return n.length>r.length&&i.includes(a)?n:n.length>=r.length*2?Array.isArray(t.attachments)&&t.attachments.length>0&&!i.includes(a)?`${e}\n${n}`:n:e}function extractSlackStructuredMrkdwn(e,t){return[...extractBlockKitLines(e),...extractLegacyAttachmentLines(t)].join(`
|
|
2
|
-
`).trim()}function extractBlockKitLines(t){if(!Array.isArray(t))return[];let n=[];for(let r of t)if(isObject(r))switch(r.type){case`section`:appendTextObjectLine(n,r.text),appendFieldLines(n,r.fields),appendSectionAccessoryLine(n,r.accessory);break;case`header`:appendTextObjectLine(n,r.text);break;case`video`:appendTextObjectLine(n,r.title),appendTextObjectLine(n,r.description);break;case`markdown`:typeof r.text==`string`&&r.text.length>0&&n.push(r.text);break;case`table`:case`data_table`:appendTableLines(n,r);break;case`card`:appendCardLines(n,r);break;case`carousel`:if(Array.isArray(r.elements))for(let t of r.elements)isObject(t)&&appendCardLines(n,t);break;case`container`:appendTextObjectLine(n,r.title),appendTextObjectLine(n,r.subtitle),n.push(...extractBlockKitLines(r.child_blocks));break;case`context`:appendElementLines(n,r.elements);break;case`actions`:appendActionsLine(n,r.elements);break;case`rich_text`:appendRichTextLine(n,r.elements);break;case`image`:typeof r.alt_text==`string`&&r.alt_text.length>0&&n.push(r.alt_text),typeof r.title==`object`&&r.title!==null&&appendTextObjectLine(n,r.title);break;default:break}return n}function extractLegacyAttachmentLines(t){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!isObject(r))continue;let t=n.length;typeof r.pretext==`string`&&r.pretext.length>0&&n.push(r.pretext),typeof r.title==`string`&&r.title.length>0&&n.push(r.title),typeof r.text==`string`&&r.text.length>0&&n.push(r.text),appendLegacyFieldLines(n,r.fields),typeof r.footer==`string`&&r.footer.length>0&&n.push(r.footer),n.push(...extractBlockKitLines(r.blocks)),n.length===t&&typeof r.fallback==`string`&&r.fallback.length>0&&n.push(r.fallback)}return n}function appendTextObjectLine(e,t){let n=readSlackTextObject(t);n&&e.push(n)}function appendFieldLines(e,t){if(Array.isArray(t))for(let n of t)appendTextObjectLine(e,n)}function appendElementLines(t,n){if(Array.isArray(n)){for(let r of n)if(isObject(r)){if(r.type===`image`){typeof r.alt_text==`string`&&r.alt_text.length>0&&t.push(r.alt_text);continue}appendTextObjectLine(t,r)}}}function appendSectionAccessoryLine(t,n){isObject(n)&&n.type===`button`&&appendActionsLine(t,[n])}function appendCardLines(e,t){appendTextObjectLine(e,t.title),appendTextObjectLine(e,t.subtitle),appendTextObjectLine(e,t.body),appendTextObjectLine(e,t.subtext),appendActionsLine(e,t.actions)}function appendTableLines(e,t){if(appendTextObjectLine(e,t.caption),Array.isArray(t.rows))for(let n of t.rows){if(!Array.isArray(n))continue;let t=n.map(tableCellToPlain);t.some(e=>e.length>0)&&e.push(t.join(` | `))}}function tableCellToPlain(t){return isObject(t)?t.type===`rich_text`?richTextPartsToPlain(t.elements):typeof t.text==`string`?t.text:typeof t.value==`number`||typeof t.value==`string`?String(t.value):``:``}function appendActionsLine(t,n){if(!Array.isArray(n))return;let r=n.map(t=>isObject(t)?readSlackTextObject(t.text):``).filter(e=>e.length>0);r.length>0&&t.push(r.map(e=>`[${e}]`).join(` `))}function appendLegacyFieldLines(t,n){if(Array.isArray(n))for(let r of n){if(!isObject(r))continue;let n=typeof r.title==`string`?r.title.trim():``,i=typeof r.value==`string`?r.value.trim():``;n&&i?t.push(`${n}: ${i}`):i?t.push(i):n&&t.push(n)}}function appendRichTextLine(e,t){let n=richTextPartsToPlain(t);n&&e.push(n)}function richTextPartsToPlain(t){return Array.isArray(t)?t.map(t=>isObject(t)?richTextPartToPlain(t):``).filter(e=>e.length>0).join(`
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{formatSlackLink}from"#compiled/@chat-adapter/slack/format.js";function resolveSlackInboundMrkdwn(e,t){try{return resolveSlackInboundMrkdwnUnsafe(e,t)}catch{return e}}function resolveSlackInboundMrkdwnUnsafe(e,t){let n=extractSlackStructuredMrkdwn(t.blocks,t.attachments),r=e.trim();if(!r)return n;if(!n||normalizeComparableText(n)===normalizeComparableText(r))return e;let i=normalizeComparableText(n),a=normalizeComparableText(r);return n.length>r.length&&i.includes(a)?n:hasSharedMessageAttachment(t.attachments)?a.includes(i)?e:`${e}\n${n}`:n.length>=r.length*2?Array.isArray(t.attachments)&&t.attachments.length>0&&!i.includes(a)?`${e}\n${n}`:n:e}function extractSlackStructuredMrkdwn(e,t){return[...extractBlockKitLines(e),...extractLegacyAttachmentLines(t)].join(`
|
|
2
|
+
`).trim()}function extractBlockKitLines(t){if(!Array.isArray(t))return[];let n=[];for(let r of t)if(isObject(r))switch(r.type){case`section`:appendTextObjectLine(n,r.text),appendFieldLines(n,r.fields),appendSectionAccessoryLine(n,r.accessory);break;case`header`:appendTextObjectLine(n,r.text);break;case`video`:appendTextObjectLine(n,r.title),appendTextObjectLine(n,r.description);break;case`markdown`:typeof r.text==`string`&&r.text.length>0&&n.push(r.text);break;case`table`:case`data_table`:appendTableLines(n,r);break;case`card`:appendCardLines(n,r);break;case`carousel`:if(Array.isArray(r.elements))for(let t of r.elements)isObject(t)&&appendCardLines(n,t);break;case`container`:appendTextObjectLine(n,r.title),appendTextObjectLine(n,r.subtitle),n.push(...extractBlockKitLines(r.child_blocks));break;case`context`:appendElementLines(n,r.elements);break;case`actions`:appendActionsLine(n,r.elements);break;case`rich_text`:appendRichTextLine(n,r.elements);break;case`image`:typeof r.alt_text==`string`&&r.alt_text.length>0&&n.push(r.alt_text),typeof r.title==`object`&&r.title!==null&&appendTextObjectLine(n,r.title);break;default:break}return n}function extractLegacyAttachmentLines(t){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!isObject(r))continue;let t=n.length;typeof r.pretext==`string`&&r.pretext.length>0&&n.push(r.pretext),typeof r.title==`string`&&r.title.length>0&&n.push(r.title),typeof r.text==`string`&&r.text.length>0&&n.push(r.text),appendLegacyFieldLines(n,r.fields),typeof r.footer==`string`&&r.footer.length>0&&n.push(r.footer),n.push(...extractBlockKitLines(r.blocks)),n.push(...extractSlackMessageUnfurlLines(r.message_blocks)),n.length===t&&typeof r.fallback==`string`&&r.fallback.length>0&&n.push(r.fallback)}return n}function hasSharedMessageAttachment(t){return Array.isArray(t)?t.some(t=>isObject(t)&&(Array.isArray(t.message_blocks)||t.is_share===!0||t.is_msg_unfurl===!0||t.is_reply_unfurl===!0)):!1}function extractSlackMessageUnfurlLines(t){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!isObject(r)||!isObject(r.message))continue;let t=extractBlockKitLines(r.message.blocks);t.length>0?n.push(...t):typeof r.message.text==`string`&&r.message.text.length>0&&n.push(r.message.text)}return n}function appendTextObjectLine(e,t){let n=readSlackTextObject(t);n&&e.push(n)}function appendFieldLines(e,t){if(Array.isArray(t))for(let n of t)appendTextObjectLine(e,n)}function appendElementLines(t,n){if(Array.isArray(n)){for(let r of n)if(isObject(r)){if(r.type===`image`){typeof r.alt_text==`string`&&r.alt_text.length>0&&t.push(r.alt_text);continue}appendTextObjectLine(t,r)}}}function appendSectionAccessoryLine(t,n){isObject(n)&&n.type===`button`&&appendActionsLine(t,[n])}function appendCardLines(e,t){appendTextObjectLine(e,t.title),appendTextObjectLine(e,t.subtitle),appendTextObjectLine(e,t.body),appendTextObjectLine(e,t.subtext),appendActionsLine(e,t.actions)}function appendTableLines(e,t){if(appendTextObjectLine(e,t.caption),Array.isArray(t.rows))for(let n of t.rows){if(!Array.isArray(n))continue;let t=n.map(tableCellToPlain);t.some(e=>e.length>0)&&e.push(t.join(` | `))}}function tableCellToPlain(t){return isObject(t)?t.type===`rich_text`?richTextPartsToPlain(t.elements):typeof t.text==`string`?t.text:typeof t.value==`number`||typeof t.value==`string`?String(t.value):``:``}function appendActionsLine(t,n){if(!Array.isArray(n))return;let r=n.map(t=>isObject(t)?readSlackTextObject(t.text):``).filter(e=>e.length>0);r.length>0&&t.push(r.map(e=>`[${e}]`).join(` `))}function appendLegacyFieldLines(t,n){if(Array.isArray(n))for(let r of n){if(!isObject(r))continue;let n=typeof r.title==`string`?r.title.trim():``,i=typeof r.value==`string`?r.value.trim():``;n&&i?t.push(`${n}: ${i}`):i?t.push(i):n&&t.push(n)}}function appendRichTextLine(e,t){let n=richTextPartsToPlain(t);n&&e.push(n)}function richTextPartsToPlain(t){return Array.isArray(t)?t.map(t=>isObject(t)?richTextPartToPlain(t):``).filter(e=>e.length>0).join(`
|
|
3
3
|
`):``}function richTextPartToPlain(e){switch(e.type){case`rich_text_section`:case`rich_text_preformatted`:case`rich_text_quote`:return richTextInlineToPlain(e.elements);case`rich_text_list`:return richTextListToPlain(e);default:return``}}function richTextInlineToPlain(t){if(!Array.isArray(t))return``;let n=[];for(let r of t)if(isObject(r))switch(r.type){case`text`:typeof r.text==`string`&&n.push(r.text);break;case`link`:typeof r.url==`string`&&typeof r.text==`string`?n.push(formatInboundRichTextLink(r.url,r.text)):typeof r.text==`string`?n.push(r.text):typeof r.url==`string`&&n.push(r.url);break;case`emoji`:typeof r.name==`string`&&n.push(`:${r.name}:`);break;case`user`:typeof r.user_id==`string`&&n.push(`<@${r.user_id}>`);break;case`channel`:typeof r.channel_id==`string`&&n.push(`<#${r.channel_id}>`);break;case`usergroup`:typeof r.usergroup_id==`string`&&n.push(`<!subteam^${r.usergroup_id}>`);break;case`broadcast`:typeof r.range==`string`&&n.push(`<!${r.range}>`);break;case`date`:typeof r.fallback==`string`&&n.push(r.fallback);break;default:break}return n.join(``)}function richTextListToPlain(t){return Array.isArray(t.elements)?t.elements.map(t=>isObject(t)?richTextInlineToPlain(t.elements):``).filter(e=>e.length>0).join(`
|
|
4
4
|
`):``}function readSlackTextObject(t){return isObject(t)&&typeof t.text==`string`?t.text:``}function normalizeComparableText(e){return e.replace(/\s+/gu,` `).trim()}function formatInboundRichTextLink(e,n){try{return formatSlackLink(e,n)}catch(t){if(t instanceof TypeError)return`${n} (${e})`;throw t}}export{readSlackTextObject,resolveSlackInboundMrkdwn};
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* off nothing discovers that directory, so these compile but never run.
|
|
10
10
|
*/
|
|
11
11
|
import { type ManagedTraceOptions, type OtelIntegration } from "#tracing/otel-declaration.js";
|
|
12
|
-
export { isOtelDeclaration, isOtelIntegration, otel, otelIntegration, composeSpanExportPolicies, redactSpanInputs, redactSpanOutputs, type ContentOptions, type OtelDeclaration, type OtelIntegration, type OtelIntegrationOptions, type OtelOptions, type ManagedTraceOptions, type SpanAttributeDecision, type SpanExportAttributeValue, type SpanExportContext, type SpanExportPolicy, type SpanExportPredicate, type TraceCaptureContext, type TraceCapturePolicy, } from "#tracing/otel-declaration.js";
|
|
12
|
+
export { isOtelDeclaration, isOtelIntegration, otel, otelIntegration, composeSpanExportPolicies, redactSpanInputs, redactSpanOutputs, type ContentOptions, type OtelDeclaration, type OtelIntegration, type OtelIntegrationOptions, type OtelOptions, type ManagedTraceOptions, type SpanAttributeDecision, type SpanExportAttributeValue, type SpanExportContext, type SpanExportPolicy, type SpanExportPredicate, type TraceCaptureContext, type TraceCapturePolicy, type TracePolicyDecision, } from "#tracing/otel-declaration.js";
|
|
13
13
|
export type { SpanExporter, SpanProcessor } from "#compiled/@vercel/otel/index.js";
|
|
14
14
|
/**
|
|
15
15
|
* Vercel Agent Runs, enabled by default in production.
|
|
@@ -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{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.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.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`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{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.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.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.46.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{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,n){let r=parseChatGptModelSelection(e);return r===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(r)}),\n${reasoningTemplateLine(n)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,n){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(n.model)!==void 0?renderAgentTemplate(n.model,n.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,n.appName).replaceAll(`__EVE_INIT_MODEL__`,n.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(n.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(n.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(n.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,n.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,n.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,n.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,n.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,n.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,n.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__",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChannelAudience } from "#shared/channel-audience.js";
|
|
2
|
+
import type { InstrumentationDecision } from "#shared/instrumentation-decision.js";
|
|
3
|
+
/** Hosted instrumentation records conversation content only for known-public channels. */
|
|
4
|
+
export declare function shouldCaptureInstrumentationContent(audience: ChannelAudience): boolean;
|
|
5
|
+
/** Per-delivery audience is a hard ceiling over the session-level trace decision. */
|
|
6
|
+
export declare function applyAudienceCeiling(decision: InstrumentationDecision, audience: ChannelAudience): InstrumentationDecision;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isEveDevEnvironment}from"#internal/application/dev-environment.js";function shouldCaptureInstrumentationContent(t){return t===`public`||t===`unknown`&&isEveDevEnvironment()}function applyAudienceCeiling(e,t){return e.action===`drop`||shouldCaptureInstrumentationContent(t)?e:{action:`record`,recordInputs:!1,recordOutputs:!1}}export{applyAudienceCeiling,shouldCaptureInstrumentationContent};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const DROP_INSTRUMENTATION={action:`drop`};export{DROP_INSTRUMENTATION};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SessionTraceContext } from "#channel/types.js";
|
|
2
2
|
import type { AgentActionTraceState, AgentSessionTraceState, AgentTraceStateStore, AgentTurnTraceState } from "#tracing/agent-trace-state.js";
|
|
3
3
|
/** Keeps only framework trace state from an interrupted step's context changes. */
|
|
4
4
|
export declare function preserveSerializedAgentTraceState(original: Record<string, unknown>, interrupted: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -7,9 +7,9 @@ export declare function preserveSerializedAgentTraceState(original: Record<strin
|
|
|
7
7
|
* which {@link ContextAgentTraceStateStore} cannot do — its reads are scoped
|
|
8
8
|
* to the ambient session.
|
|
9
9
|
*/
|
|
10
|
-
export declare function readSessionTraceContext(serializedContext: Readonly<Record<string, unknown>>, sessionId: string):
|
|
10
|
+
export declare function readSessionTraceContext(serializedContext: Readonly<Record<string, unknown>>, sessionId: string): SessionTraceContext | undefined;
|
|
11
11
|
/** Reads the durable action span that should parent a dispatched child agent. */
|
|
12
|
-
export declare function readActionTraceContext(serializedContext: Readonly<Record<string, unknown>>, sessionId: string, turnId: string, callId: string):
|
|
12
|
+
export declare function readActionTraceContext(serializedContext: Readonly<Record<string, unknown>>, sessionId: string, turnId: string, callId: string): SessionTraceContext | undefined;
|
|
13
13
|
/** Durable trace state backed by eve's serialized Workflow context. */
|
|
14
14
|
export declare class ContextAgentTraceStateStore implements AgentTraceStateStore {
|
|
15
15
|
deleteAction(idempotencyKey: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeChannelAudience}from"#shared/channel-audience.js";import{contextStorage,loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";const AgentTraceContextKey=new ContextKey(`eve.harness.agentTrace`,{codec:{deserialize:deserializeState,serialize:serializeState}});function preserveSerializedAgentTraceState(e,t){let n=t[AgentTraceContextKey.name];return n===void 0?e:{...e,[AgentTraceContextKey.name]:n}}function readSessionTraceContext(e,t){let n=e[AgentTraceContextKey.name];if(n
|
|
1
|
+
import{normalizeChannelAudience}from"#shared/channel-audience.js";import{SessionTraceSeedKey}from"#context/keys.js";import{contextStorage,loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";const AgentTraceContextKey=new ContextKey(`eve.harness.agentTrace`,{codec:{deserialize:deserializeState,serialize:serializeState}});function preserveSerializedAgentTraceState(e,t){let n=t[AgentTraceContextKey.name];return n===void 0?e:{...e,[AgentTraceContextKey.name]:n}}function readSessionTraceContext(e,t){let n=e[AgentTraceContextKey.name];if(n===void 0)return;let r=deserializeState(n).sessions[t]?.context;return r===void 0?void 0:withTraceDecision(e,r)}function readActionTraceContext(e,t,n,r){let i=e[AgentTraceContextKey.name];if(i===void 0)return;let a=Object.values(deserializeState(i).actions).find(e=>e.sessionId===t&&e.turnId===n&&e.callId===r);if(a!==void 0)return withTraceDecision(e,{isRemote:!1,spanId:a.spanId,traceFlags:a.parent.traceFlags,traceId:a.parent.traceId})}function withTraceDecision(e,n){let r=e[SessionTraceSeedKey.name];return r?.decision===void 0?n:{...n,decision:r.decision}}var ContextAgentTraceStateStore=class{deleteAction(e){updateState(t=>{let n={...t.actions};return delete n[e],{...t,actions:n}})}deleteActions(e,t){updateState(n=>{let r={...n.actions};for(let[n,i]of Object.entries(r))i.sessionId===e&&(t===void 0||i.turnId===t)&&delete r[n];return{...n,actions:r}})}deleteSession(e){updateState(t=>{let n={...t.sessions};return delete n[e],{...t,sessions:n}})}deleteTurn(e,t){updateState(n=>{let r={...n.turns};return delete r[turnKey(e,t)],{...n,turns:r}})}findAction(e,t){return Object.values(contextStorage.getStore()?.get(AgentTraceContextKey)?.actions??{}).find(n=>n.sessionId===e&&n.callId===t)}getAction(e){return contextStorage.getStore()?.get(AgentTraceContextKey)?.actions[e]}getSession(e){return contextStorage.getStore()?.get(AgentTraceContextKey)?.sessions[e]}getTurn(e,t){return contextStorage.getStore()?.get(AgentTraceContextKey)?.turns[turnKey(e,t)]}setAction(e,t){updateState(n=>({...n,actions:{...n.actions,[e]:t}}))}setSession(e,t){updateState(n=>({...n,sessions:{...n.sessions,[e]:t}}))}setTurn(e,t,n){updateState(r=>({...r,turns:{...r.turns,[turnKey(e,t)]:n}}))}};function updateState(e){loadContext().set(AgentTraceContextKey,t=>e(t??{actions:{},sessions:{},turns:{}}))}function turnKey(e,t){return`${e}\0${t}`}function serializeState(e){return{actions:e.actions,sessions:Object.fromEntries(Object.entries(e.sessions).map(([e,t])=>[e,{...t,context:serializeSpanContext(t.context)}])),turns:Object.fromEntries(Object.entries(e.turns).map(([e,t])=>[e,{...t,context:serializeSpanContext(t.context),terminal:t.terminal===void 0?void 0:t.terminal.type===`turn.failed`?{error:serializeError(t.terminal.error),type:t.terminal.type}:{type:t.terminal.type}}]))}}function deserializeState(t){return isRecord(t)?{actions:deserializeRecord(t.actions,deserializeAction),sessions:deserializeRecord(t.sessions,t=>{if(!(!isRecord(t)||!isSpanContext(t.context)))return{agentName:typeof t.agentName==`string`?t.agentName:void 0,channelAudience:normalizeChannelAudience(t.channelAudience),channelKind:typeof t.channelKind==`string`?t.channelKind:void 0,context:t.context,rootSessionId:typeof t.rootSessionId==`string`?t.rootSessionId:``}}),turns:deserializeRecord(t.turns,e=>{if(!(!isRecord(e)||!isSpanContext(e.context))&&!(typeof e.parentSpanId!=`string`||typeof e.startTimeMs!=`number`))return{context:e.context,parentIsRemote:typeof e.parentIsRemote==`boolean`?e.parentIsRemote:void 0,parentSpanId:e.parentSpanId,rootSessionId:typeof e.rootSessionId==`string`?e.rootSessionId:``,sequence:typeof e.sequence==`number`?e.sequence:0,startTimeMs:e.startTimeMs,subagentName:typeof e.subagentName==`string`?e.subagentName:void 0,terminal:deserializeTerminal(e.terminal)}})}:{actions:{},sessions:{},turns:{}}}function deserializeAction(t){if(!(!isRecord(t)||typeof t.attemptIndex!=`number`||typeof t.callId!=`string`||!isActionKind(t.kind)||typeof t.name!=`string`||!isSpanContext(t.parent)||typeof t.rootSessionId!=`string`||typeof t.sessionId!=`string`||typeof t.spanId!=`string`||typeof t.startTimeMs!=`number`||typeof t.stepIndex!=`number`||typeof t.turnId!=`string`))return{attemptIndex:t.attemptIndex,callId:t.callId,channelAudience:normalizeChannelAudience(t.channelAudience),inputAttribute:typeof t.inputAttribute==`string`?t.inputAttribute:void 0,kind:t.kind,name:t.name,parent:t.parent,rootSessionId:t.rootSessionId,sessionId:t.sessionId,spanId:t.spanId,startTimeMs:t.startTimeMs,stepIndex:t.stepIndex,turnId:t.turnId}}function isActionKind(e){return e===`load-skill`||e===`remote-agent-call`||e===`subagent-call`||e===`tool-call`}function deserializeRecord(e,t){if(!isRecord(e))return{};let n={};for(let[r,i]of Object.entries(e)){let e=t(i);e!==void 0&&(n[r]=e)}return n}function deserializeTerminal(e){if(!isRecord(e)||typeof e.type!=`string`)return;let t=e.type;if(isTurnTerminalType(t))return t===`turn.failed`?{error:deserializeError(e.error),type:t}:{type:t}}function serializeSpanContext(e){return{isRemote:e.isRemote,spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function isSpanContext(e){return isRecord(e)&&typeof e.spanId==`string`&&typeof e.traceFlags==`number`&&typeof e.traceId==`string`}function serializeError(e){return e instanceof Error?{message:e.message,name:e.name,stack:e.stack}:void 0}function deserializeError(e){if(!isRecord(e)||typeof e.message!=`string`)return;let t=Error(e.message);return typeof e.name==`string`&&(t.name=e.name),typeof e.stack==`string`&&(t.stack=e.stack),t}function isTurnTerminalType(e){return e===`turn.cancelled`||e===`turn.completed`||e===`turn.failed`}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{ContextAgentTraceStateStore,preserveSerializedAgentTraceState,readActionTraceContext,readSessionTraceContext};
|
|
@@ -33,8 +33,12 @@ export interface OtelOptions {
|
|
|
33
33
|
*/
|
|
34
34
|
readonly traceChannelRequests?: boolean;
|
|
35
35
|
/**
|
|
36
|
-
* Process-wide
|
|
37
|
-
*
|
|
36
|
+
* Process-wide trace and content decision. Boolean returns preserve the
|
|
37
|
+
* existing audience-aware behavior; explicit decisions can disable emission
|
|
38
|
+
* or select input and output capture independently. Defaults to emitting
|
|
39
|
+
* every audience, with content only for public conversations. The result is a capture ceiling:
|
|
40
|
+
* per-delivery audience and destination settings can only narrow it. A thrown
|
|
41
|
+
* error rejects trace production without silencing lifecycle providers.
|
|
38
42
|
*/
|
|
39
43
|
readonly tracePolicy?: TraceCapturePolicy;
|
|
40
44
|
/**
|
|
@@ -79,7 +83,14 @@ export interface TraceCaptureContext {
|
|
|
79
83
|
readonly audience: ChannelAudience;
|
|
80
84
|
readonly channelType?: string;
|
|
81
85
|
}
|
|
82
|
-
export type
|
|
86
|
+
export type TracePolicyDecision = {
|
|
87
|
+
readonly emit: false;
|
|
88
|
+
} | {
|
|
89
|
+
readonly emit: true;
|
|
90
|
+
readonly recordInputs: boolean;
|
|
91
|
+
readonly recordOutputs: boolean;
|
|
92
|
+
};
|
|
93
|
+
export type TraceCapturePolicy = (trace: TraceCaptureContext) => TracePolicyDecision | boolean;
|
|
83
94
|
/** Where one `otelIntegration()` sends spans. */
|
|
84
95
|
export interface OtelIntegrationOptions extends ContentOptions {
|
|
85
96
|
/** Merged into the pipeline in declaration order. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChannelAudience } from "#shared/channel-audience.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type InstrumentationDecision } from "#shared/instrumentation-decision.js";
|
|
3
|
+
import type { TraceCapturePolicy, TracePolicyDecision } from "#tracing/otel-declaration.js";
|
|
3
4
|
export declare function isSampledTrace(context: {
|
|
4
5
|
readonly traceFlags: number;
|
|
5
6
|
}): boolean;
|
|
@@ -8,3 +9,9 @@ export declare function evaluateTracePolicy(policy: TraceCapturePolicy | undefin
|
|
|
8
9
|
readonly audience: ChannelAudience;
|
|
9
10
|
readonly channelType?: string;
|
|
10
11
|
}): boolean;
|
|
12
|
+
export declare function resolveTracePolicy(policy: TraceCapturePolicy | undefined, trace: {
|
|
13
|
+
readonly agentName?: string;
|
|
14
|
+
readonly audience: ChannelAudience;
|
|
15
|
+
readonly channelType?: string;
|
|
16
|
+
}): InstrumentationDecision;
|
|
17
|
+
export declare function resolveTracePolicyDecision(decision: TracePolicyDecision | boolean, audience: ChannelAudience): InstrumentationDecision;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function isSampledTrace(e){return(e.traceFlags&1)==1}function evaluateTracePolicy(e,t){try{
|
|
1
|
+
import{shouldCaptureInstrumentationContent}from"#shared/instrumentation-content.js";import{DROP_INSTRUMENTATION}from"#shared/instrumentation-decision.js";function isSampledTrace(e){return(e.traceFlags&1)==1}function evaluateTracePolicy(e,t){return resolveTracePolicy(e,t).action===`record`}function resolveTracePolicy(e,n){try{let t=e?.({agentName:n.agentName,audience:n.audience,channelType:n.channelType});return resolveTracePolicyDecision(t??{emit:!0,recordInputs:n.audience===`public`,recordOutputs:n.audience===`public`},n.audience)}catch{return DROP_INSTRUMENTATION}}function resolveTracePolicyDecision(n,r){if(n===!1)return DROP_INSTRUMENTATION;if(n===!0){let t=shouldCaptureInstrumentationContent(r);return{action:`record`,recordInputs:t,recordOutputs:t}}return n.emit?{action:`record`,recordInputs:n.recordInputs,recordOutputs:n.recordOutputs}:DROP_INSTRUMENTATION}export{evaluateTracePolicy,isSampledTrace,resolveTracePolicy,resolveTracePolicyDecision};
|
package/docs/agent-config.md
CHANGED
|
@@ -26,6 +26,8 @@ vision-capable model or [route image inputs to Gemini
|
|
|
26
26
|
Flash](./guides/dynamic-capabilities#route-image-inputs-to-a-vision-model).
|
|
27
27
|
When `agent.ts` is present, `model` is required.
|
|
28
28
|
|
|
29
|
+
A config that selects a static Gateway model is compile-only. A config that contains a dynamic model or a direct-provider `LanguageModel` remains a runtime entry because eve must resolve that authored value while the agent runs. See [Authored module lifecycle](./reference/typescript-api#authored-module-lifecycle).
|
|
30
|
+
|
|
29
31
|
`model` accepts a gateway model id string, which routes through the [Vercel AI Gateway](https://vercel.com/docs/ai-gateway). To call a provider directly and configure the model in code, pass a provider-authored `LanguageModel`.
|
|
30
32
|
|
|
31
33
|
Provider-specific AI SDK packages are regular project dependencies. A fresh `eve init` app includes the core `ai` package, but it does not install every provider package. Install the provider package you import, then set that provider's API key:
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -158,6 +158,8 @@ Only the first available handler runs. A message hook returning `null` drops the
|
|
|
158
158
|
|
|
159
159
|
The model-visible `<slack_message>` includes `sender_id`, `bot_user_id` when available, and the `is_mentioned` value from `ctx.isBotMentioned()`. Its `<content>` keeps `<@USER_ID>` intact while converting other mrkdwn to Markdown; routing is unchanged.
|
|
160
160
|
|
|
161
|
+
When a Slack message shares another Slack message, eve extracts the forwarded message body from Slack's message-unfurl attachment and includes it in `<content>`. The original top-level comment, when present, remains alongside the forwarded content.
|
|
162
|
+
|
|
161
163
|
#### Restrict who can invoke the agent
|
|
162
164
|
|
|
163
165
|
A valid Slack signature proves that Slack sent the event. It does not decide which channel or person your agent should trust. Fail closed in the inbound handler before returning auth, especially when the app is installed in a shared Slack Connect channel:
|
|
@@ -5,6 +5,8 @@ description: "Resolve models, subagents, tools, skills, and instructions at runt
|
|
|
5
5
|
|
|
6
6
|
`defineDynamic` resolves the model, subagents, tools, skills, and instructions at runtime from a session event instead of declaring them up front. Reach for it when the right capability isn't known until the session starts, because it hinges on who the caller is, what tenant they belong to, feature flags, or external data. The [subagents](../subagents), [tools](../tools), [skills](../skills), and [instructions](../instructions) guides each point here for their dynamic form.
|
|
7
7
|
|
|
8
|
+
eve evaluates a dynamic definition module once during compilation to classify and validate it, then retains that module as a runtime entry so its event handlers can run. Its top-level code therefore runs in both phases; keep caller-specific work inside the handlers. See [Authored module lifecycle](../reference/typescript-api#authored-module-lifecycle).
|
|
9
|
+
|
|
8
10
|
## Dynamic models
|
|
9
11
|
|
|
10
12
|
The `model` field in `agent.ts` accepts `defineDynamic({ events })`. Resolvers
|
package/docs/instructions.mdx
CHANGED
|
@@ -42,7 +42,9 @@ export default defineInstructions({
|
|
|
42
42
|
|
|
43
43
|
`role` is either `"system"` or `"user"` and defaults to `"system"`. The legacy `{ markdown: string }` form still creates system-role instructions, but is deprecated; do not combine `markdown` with `content` or `role`. Blank content contributes no context.
|
|
44
44
|
|
|
45
|
-
A module-backed definition runs once at build time. eve stores its resolved content and role in the compiled manifest, so the
|
|
45
|
+
A module-backed definition runs once at build time. eve stores its resolved content and role in the compiled manifest, so the definition is not a runtime entry.
|
|
46
|
+
|
|
47
|
+
This includes its normal ESM and [asset imports](./reference/typescript-api#asset-imports), such as a top-level prompt imported with `?raw`. See [Authored module lifecycle](./reference/typescript-api#authored-module-lifecycle) for the full compile/runtime contract.
|
|
46
48
|
|
|
47
49
|
## System and user roles
|
|
48
50
|
|
|
@@ -59,6 +59,31 @@ Tool-wide authoring helpers such as `defineTool`, `defineDynamic`, and `disableT
|
|
|
59
59
|
|
|
60
60
|
`defineInstructions` accepts `{ content: string, role?: "system" | "user" }`; omitted `role` means `"system"`. Its `eve/instructions` version of `defineDynamic` accepts only `session.started` and `turn.started` handlers returning `defineInstructions(...)` or `null`. The legacy `{ markdown: string }` definition remains available as a deprecated system-role form.
|
|
61
61
|
|
|
62
|
+
## Authored module lifecycle
|
|
63
|
+
|
|
64
|
+
eve evaluates TypeScript definition modules during compilation so it can validate and normalize the agent. Within one agent node, each module namespace loads at most once during that compile. The resolved definition then determines whether the module is also an entry in the runtime bundle:
|
|
65
|
+
|
|
66
|
+
| Lifecycle | Authored definitions |
|
|
67
|
+
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| Compile only | Static instructions and skills, prompt-form TypeScript schedules, static Gateway or default agent config, provider-managed web search, `Workflow` configuration, fully shadowed channels, and a child sandbox that selects its parent's sandbox |
|
|
69
|
+
| Compile and runtime | Dynamic instructions, skills, tools, models, and subagents; executable tools; effective channels; connections; hooks; memory; handler schedules; direct-provider models; independent sandboxes; and remote subagents |
|
|
70
|
+
| Runtime only | Instrumentation modules and extension mount initialization |
|
|
71
|
+
|
|
72
|
+
A compile-only module is not imported when the deployed runtime starts. For example, eve stores the resolved content from a static `instructions.ts` in the compiled manifest. A compile-and-runtime module is evaluated during compilation and imported again when a runtime process loads the module map. Keep module-top-level work deterministic, and put request- or session-specific work in the definition's runtime callbacks.
|
|
73
|
+
|
|
74
|
+
The runtime bundler follows the normal ESM graph from every runtime entry. A helper remains runtime code when a tool or other runtime entry imports it, even if static instructions also import that helper. Lifecycle selection applies to definition entries, not as tree-shaking permission for their ordinary dependencies.
|
|
75
|
+
|
|
76
|
+
### Asset imports
|
|
77
|
+
|
|
78
|
+
Authored modules may import relative non-code assets from anywhere inside their project package, including outside `agent/`:
|
|
79
|
+
|
|
80
|
+
```ts title="agent/tools/read_template.ts"
|
|
81
|
+
import icon from "../../assets/icon.png";
|
|
82
|
+
import template from "../../prompts/template.txt?raw";
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`?raw` embeds the file as UTF-8 text. Other non-code asset imports produce a data URL with an inferred media type. Compilation, local development, and production builds use the same resolution behavior. Imports that escape the project package are rejected; package those files with the application instead.
|
|
86
|
+
|
|
62
87
|
## Runtime context (`ctx`)
|
|
63
88
|
|
|
64
89
|
`ctx` is passed to your tool `execute`, hook handlers, channel event handlers, and connection auth/header resolvers. It is live only while authored code is running, so reaching for it at module top level throws. See [Session context](../guides/session-context) for the full model.
|
package/docs/schedules.mdx
CHANGED
|
@@ -27,6 +27,8 @@ interface ScheduleHandlerArgs {
|
|
|
27
27
|
|
|
28
28
|
`defineSchedule` is a type-level pass-through. The compiler is what enforces the one-of rule.
|
|
29
29
|
|
|
30
|
+
A TypeScript schedule with `markdown` is compile-only because eve stores the prompt in the manifest. A schedule with `run` remains a runtime entry so the handler can execute. See [Authored module lifecycle](./reference/typescript-api#authored-module-lifecycle).
|
|
31
|
+
|
|
30
32
|
`cron` is a standard 5-field string (`minute hour day-of-month month day-of-week`) with minute granularity. On Vercel, each schedule becomes a Vercel Cron Job, and Vercel evaluates the expression in UTC, so `"0 9 * * 1-5"` fires at 09:00 UTC on weekdays. `eve dev` never fires schedules on their cron cadence. A built app served with `eve start` does run production scheduled tasks. To trigger one while iterating in dev, use the dispatch route below.
|
|
31
33
|
|
|
32
34
|
## Markdown form (fire-and-forget)
|
package/docs/skills.mdx
CHANGED
|
@@ -59,6 +59,8 @@ export default defineSkill({
|
|
|
59
59
|
|
|
60
60
|
eve generates `SKILL.md` from `markdown`, and each `files` entry becomes a package-relative sibling. Start with plain markdown and move to `defineSkill` only when you hit its limits.
|
|
61
61
|
|
|
62
|
+
A static `defineSkill` module is evaluated during compilation and its resolved definition is stored in the manifest; a dynamic skill module is also retained as a runtime entry. See [Authored module lifecycle](./reference/typescript-api#authored-module-lifecycle).
|
|
63
|
+
|
|
62
64
|
## Find and install community skills
|
|
63
65
|
|
|
64
66
|
`eve registry search` includes [skills.sh](https://skills.sh) as the built-in `@skills` source. Search by task, review the source, then install the returned skill into your project:
|