eve 0.22.1 → 0.22.3
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 +38 -0
- package/dist/src/chunks/{use-eve-agent-CM24ZUEI.js → use-eve-agent-Cojyfr4X.js} +25 -13
- package/dist/src/chunks/{use-eve-agent-CxcKypLZ.js → use-eve-agent-D-S1TPCW.js} +25 -13
- package/dist/src/cli/commands/init-repl.d.ts +6 -5
- package/dist/src/cli/dev/url.js +1 -1
- package/dist/src/client/client-error.d.ts +5 -1
- package/dist/src/client/client-error.js +1 -1
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/types.d.ts +2 -1
- package/dist/src/client/url.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +6 -4
- package/dist/src/compiled/@workflow/core/create-hook.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/events-consumer.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/private.js +1 -1
- package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +14 -0
- package/dist/src/compiled/@workflow/core/runtime/get-world-lazy.d.ts +3 -12
- package/dist/src/compiled/@workflow/core/runtime/wait-continuation.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/runtime/world-compatibility.d.ts +5 -0
- package/dist/src/compiled/@workflow/core/runtime/world-init.d.ts +16 -41
- package/dist/src/compiled/@workflow/core/runtime/world-target.d.ts +11 -0
- package/dist/src/compiled/@workflow/core/runtime/world.d.ts +21 -9
- package/dist/src/compiled/@workflow/core/runtime.d.ts +2 -1
- package/dist/src/compiled/@workflow/core/runtime.js +3 -141
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow/world-init-stub.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/world/analytics.d.ts +182 -0
- package/dist/src/compiled/@workflow/world/env-config.d.ts +39 -0
- package/dist/src/compiled/@workflow/world/events.d.ts +25 -0
- package/dist/src/compiled/@workflow/world/index.d.ts +6 -3
- package/dist/src/compiled/@workflow/world/interfaces.d.ts +14 -7
- package/dist/src/compiled/@workflow/world/runs.d.ts +9 -1
- package/dist/src/compiled/@workflow/world/shared.d.ts +15 -0
- package/dist/src/compiled/@workflow/world/steps.d.ts +8 -0
- package/dist/src/compiled/@workflow/world-local/LICENSE.md +201 -0
- package/dist/src/compiled/@workflow/world-local/index.js +4 -0
- package/dist/src/compiled/@workflow/world-vercel/LICENSE.md +201 -0
- package/dist/src/compiled/@workflow/world-vercel/index.js +42 -0
- package/dist/src/compiled/_chunks/workflow/attribute-changes-BnKD8Y3m.js +20 -0
- package/dist/src/compiled/_chunks/workflow/{dist-FLIfyJ4Y.js → dist-CttsoN4D.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/dist-DJU_7R9s.js +40 -0
- package/dist/src/compiled/_chunks/workflow/dist-DpDDcpTl.js +3 -0
- package/dist/src/compiled/_chunks/workflow/resume-hook-DjPY9VGg.js +1 -0
- package/dist/src/compiled/_chunks/workflow/run-BSANnUPR.js +1 -0
- package/dist/src/compiled/_chunks/workflow/sleep-phozDCW8.js +1 -0
- package/dist/src/compiled/_chunks/workflow/token-CaY0nA5J.js +1 -0
- package/dist/src/compiled/_chunks/workflow/token-D4VIwGlD.js +1 -0
- package/dist/src/compiled/_chunks/workflow/undici-fb54XL8i.js +95 -0
- package/dist/src/compiler/manifest.d.ts +40 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/module-map.js +2 -2
- package/dist/src/compiler/normalize-extension.d.ts +68 -0
- package/dist/src/compiler/normalize-extension.js +1 -0
- package/dist/src/compiler/normalize-manifest.js +2 -2
- package/dist/src/compiler/workspace-resources.js +1 -1
- package/dist/src/context/dynamic-skill-lifecycle.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/discover/discover-agent.d.ts +14 -1
- package/dist/src/discover/discover-agent.js +1 -1
- package/dist/src/discover/extension-specifier.d.ts +15 -0
- package/dist/src/discover/extension-specifier.js +1 -0
- package/dist/src/discover/extensions.d.ts +109 -0
- package/dist/src/discover/extensions.js +1 -0
- package/dist/src/discover/filesystem.d.ts +1 -1
- package/dist/src/discover/filesystem.js +1 -1
- package/dist/src/discover/grammar.d.ts +27 -0
- package/dist/src/discover/grammar.js +1 -1
- package/dist/src/discover/manifest.d.ts +46 -0
- package/dist/src/discover/manifest.js +1 -1
- package/dist/src/evals/assertions/run.d.ts +3 -2
- package/dist/src/evals/assertions/run.js +2 -2
- package/dist/src/evals/index.d.ts +1 -1
- package/dist/src/evals/loaders/yaml.js +1 -1
- package/dist/src/evals/match.d.ts +11 -6
- package/dist/src/execution/sandbox/bindings/microsandbox-network.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/model-call-error.d.ts +5 -0
- package/dist/src/harness/model-call-error.js +1 -1
- package/dist/src/harness/prompt-cache.d.ts +18 -9
- package/dist/src/harness/prompt-cache.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/compiled-artifacts.d.ts +4 -0
- package/dist/src/internal/application/compiled-artifacts.js +5 -4
- package/dist/src/internal/application/package.d.ts +9 -5
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-module-loader.d.ts +14 -0
- package/dist/src/internal/authored-module-loader.js +2 -2
- package/dist/src/internal/authored-module-map-loader.js +1 -1
- package/dist/src/internal/bundler/extension-scope-plugin.d.ts +37 -0
- package/dist/src/internal/bundler/extension-scope-plugin.js +3 -0
- package/dist/src/internal/helpers/gray-matter.d.ts +25 -0
- package/dist/src/internal/helpers/gray-matter.js +1 -0
- package/dist/src/internal/helpers/markdown.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
- package/dist/src/internal/nitro/host/build-application.js +1 -1
- package/dist/src/internal/nitro/host/build-extension.d.ts +24 -0
- package/dist/src/internal/nitro/host/build-extension.js +4 -0
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +2 -2
- package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
- package/dist/src/internal/nitro/routes/health.d.ts +3 -3
- package/dist/src/internal/workflow/runtime.js +1 -1
- package/dist/src/internal/workflow/validate-world.d.ts +16 -0
- package/dist/src/internal/workflow/validate-world.js +1 -0
- package/dist/src/internal/workflow/world-compatibility.d.ts +1 -12
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/index.js +1 -0
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/parse-name.js +1 -0
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/pluralize.js +1 -0
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/promise.js +1 -0
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/time.js +1 -0
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/workflow-routes.js +1 -0
- package/dist/src/node_modules/.pnpm/@workflow_utils@5.0.0-beta.6/node_modules/@workflow/utils/dist/world-target.js +1 -0
- package/dist/src/node_modules/.pnpm/ms@2.1.3/node_modules/ms/index.js +1 -0
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/slack/action-status.d.ts +19 -0
- package/dist/src/public/channels/slack/action-status.js +1 -0
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +2 -2
- package/dist/src/public/channels/slack/index.d.ts +1 -0
- package/dist/src/public/channels/slack/index.js +1 -1
- package/dist/src/public/channels/slack/mrkdwn.d.ts +0 -2
- package/dist/src/public/channels/slack/mrkdwn.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +1 -1
- package/dist/src/public/definitions/extension.d.ts +68 -0
- package/dist/src/public/definitions/extension.js +1 -0
- package/dist/src/public/extension/index.d.ts +10 -0
- package/dist/src/public/extension/index.js +1 -0
- package/dist/src/public/next/index.d.ts +9 -9
- package/dist/src/public/next/index.js +1 -1
- package/dist/src/public/next/vercel-output-config.js +1 -1
- package/dist/src/runtime/connections/openapi-client.js +1 -1
- package/dist/src/runtime/connections/openapi-spec.js +1 -1
- package/dist/src/runtime/resolve-dynamic-skill.js +1 -1
- package/dist/src/runtime/resolve-dynamic-tool.js +1 -1
- package/dist/src/runtime/types.d.ts +10 -0
- package/dist/src/services/dev-client/vercel-auth-error.d.ts +2 -2
- package/dist/src/services/dev-client/vercel-auth-error.js +3 -3
- package/dist/src/setup/scaffold/create/project.js +4 -4
- 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/agent-config.md +1 -1
- package/docs/channels/custom.mdx +2 -2
- package/docs/channels/github.mdx +35 -2
- package/docs/channels/linear.mdx +36 -6
- package/docs/channels/slack.mdx +5 -3
- package/docs/concepts/context-control.md +1 -1
- package/docs/concepts/execution-model-and-durability.md +1 -1
- package/docs/connections/openapi.mdx +3 -1
- package/docs/evals/assertions.mdx +4 -2
- package/docs/extensions.md +155 -0
- package/docs/guides/client/overview.mdx +1 -1
- package/docs/guides/deployment.md +1 -1
- package/docs/guides/dev-tui.md +4 -0
- package/docs/guides/dynamic-capabilities.md +3 -3
- package/docs/guides/frontend/nextjs.mdx +7 -7
- package/docs/guides/instrumentation.md +1 -1
- package/docs/guides/state.md +3 -3
- package/docs/instructions.mdx +1 -1
- package/docs/meta.json +1 -0
- package/docs/patterns/dynamic-scheduling.md +11 -11
- package/docs/patterns/multi-tenant-approvals.md +6 -6
- package/docs/patterns/multi-tenant-auth.md +13 -13
- package/docs/patterns/multi-tenant-memory.md +9 -9
- package/docs/schedules.mdx +1 -1
- package/docs/subagents.mdx +2 -0
- package/docs/tutorial/guard-the-spend.mdx +2 -2
- package/docs/tutorial/query-sample-data.mdx +1 -1
- package/docs/tutorial/remember-definitions.mdx +2 -2
- package/docs/tutorial/ship-it.mdx +1 -1
- package/package.json +12 -5
- package/dist/src/compiled/_chunks/workflow/attribute-changes-zAifvEhb.js +0 -59
- package/dist/src/compiled/_chunks/workflow/dist-Dxrjttr2.js +0 -3
- package/dist/src/compiled/_chunks/workflow/resume-hook-C15uJ2ik.js +0 -1
- package/dist/src/compiled/_chunks/workflow/run-BJUPZ0Ni.js +0 -1
- package/dist/src/compiled/_chunks/workflow/sleep-C8B-TYir.js +0 -1
- package/dist/src/compiled/_chunks/workflow/token-Bm-WLAUB.js +0 -1
- package/dist/src/compiled/_chunks/workflow/token-J7YP0s9a.js +0 -1
- package/dist/src/internal/workflow/configure-world.d.ts +0 -18
- package/dist/src/internal/workflow/configure-world.js +0 -1
|
@@ -278,6 +278,11 @@ export interface ResolvedDynamicToolResolver extends Readonly<ModuleSourceRef> {
|
|
|
278
278
|
readonly slug: string;
|
|
279
279
|
readonly eventNames: readonly string[];
|
|
280
280
|
readonly events: Readonly<Record<string, (event: unknown, ctx: unknown) => unknown | Promise<unknown>>>;
|
|
281
|
+
/**
|
|
282
|
+
* Mount namespace when this resolver comes from an extension. Names of tools
|
|
283
|
+
* the resolver produces are prefixed with `${extensionNamespace}__`.
|
|
284
|
+
*/
|
|
285
|
+
readonly extensionNamespace?: string;
|
|
281
286
|
}
|
|
282
287
|
/**
|
|
283
288
|
* Runtime resolver for dynamic skills declared via `defineDynamic({ events })`
|
|
@@ -288,6 +293,11 @@ export interface ResolvedDynamicSkillResolver extends Readonly<ModuleSourceRef>
|
|
|
288
293
|
readonly slug: string;
|
|
289
294
|
readonly eventNames: readonly string[];
|
|
290
295
|
readonly events: Readonly<Record<string, (event: unknown, ctx: unknown) => unknown | Promise<unknown>>>;
|
|
296
|
+
/**
|
|
297
|
+
* Mount namespace when this resolver comes from an extension. Names of skills
|
|
298
|
+
* a map resolver produces are prefixed with `${extensionNamespace}__`.
|
|
299
|
+
*/
|
|
300
|
+
readonly extensionNamespace?: string;
|
|
291
301
|
}
|
|
292
302
|
/**
|
|
293
303
|
* Runtime resolver for dynamic instructions declared via
|
|
@@ -17,10 +17,10 @@ import type { DevelopmentOidcTokenFailure } from "#services/dev-client/request-h
|
|
|
17
17
|
/** Returns the stable Trusted Sources code embedded in a Vercel error message. */
|
|
18
18
|
export declare function vercelTrustedSourcesErrorCode(message: string): string | undefined;
|
|
19
19
|
/**
|
|
20
|
-
* Returns `true` for
|
|
20
|
+
* Returns `true` for a Vercel Deployment Protection challenge.
|
|
21
21
|
*
|
|
22
22
|
* Accepts both real {@link ClientError} instances and structurally
|
|
23
|
-
* compatible duck-typed errors (`{ status
|
|
23
|
+
* compatible duck-typed errors (`{ status, body, headers }`)
|
|
24
24
|
* so callers can detect the challenge regardless of whether the
|
|
25
25
|
* error survived a network/IPC boundary.
|
|
26
26
|
*/
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import{isObject}from"#shared/guards.js";import{ClientError}from"#client/client-error.js";const VERCEL_AUTH_CHALLENGE_MARKERS=[`vercel.com/sso-api`,`<title>Authentication Required</title>`],TRUSTED_SOURCES_ERROR_CODE=/^TRUSTED_SOURCES_[A-Z0-9_]+$/u;function vercelTrustedSourcesErrorCode(e){for(let t of e.replaceAll(`\r
|
|
2
2
|
`,`
|
|
3
3
|
`).trim().split(`
|
|
4
|
-
`)){let e=t.trim();if(TRUSTED_SOURCES_ERROR_CODE.test(e))return e}}function bodyLooksLikeVercelAuthChallenge(e){return e.length>0&&VERCEL_AUTH_CHALLENGE_MARKERS.every(t=>e.includes(t))}function
|
|
4
|
+
`)){let e=t.trim();if(TRUSTED_SOURCES_ERROR_CODE.test(e))return e}}function bodyLooksLikeVercelAuthChallenge(e){return e.length>0&&VERCEL_AUTH_CHALLENGE_MARKERS.every(t=>e.includes(t))}function isVercelSsoUrl(e){let t=URL.parse(e);return t?.origin===`https://vercel.com`&&t.pathname===`/sso-api`&&t.searchParams.has(`url`)}function isVercelSsoRedirect(e,t){if(e<300||e>=400||t===void 0)return!1;for(let[e,n]of Object.entries(t))if(e.toLowerCase()===`location`&&typeof n==`string`)return isVercelSsoUrl(n);return!1}function isVercelUnauthorized(e,t){if(e!==401||t===void 0)return!1;for(let[e,n]of Object.entries(t))if(e.toLowerCase()===`x-vercel-error`&&n===`UNAUTHORIZED`)return!0;return!1}function bodyLooksLikeStructuredVercelAuthChallenge(t){let n;try{n=JSON.parse(t)}catch{return!1}if(!isObject(n)||!isObject(n.error)||!isObject(n.protection))return!1;let r=n.error.code,i=n.protection.vercel_auth_callback;return(r===401||r===`401`)&&n.error.message===`Protected deployment`&&typeof i==`string`&&isVercelSsoUrl(i)}function isVercelAuthChallenge(n){let r=n instanceof ClientError||isObject(n)?n:void 0;if(r===void 0||typeof r.status!=`number`||typeof r.body!=`string`)return!1;let i=isObject(r.headers)?r.headers:void 0;return isVercelSsoRedirect(r.status,i)||isVercelUnauthorized(r.status,i)||r.status===401&&(bodyLooksLikeVercelAuthChallenge(r.body)||bodyLooksLikeStructuredVercelAuthChallenge(r.body))}function formatVercelAuthChallengeMessage(e){let t=[`Vercel Deployment Protection blocked the request to ${e.serverUrl}.`];return e.oidcTokenFailure!==void 0&&t.push(``,formatDevelopmentOidcTokenFailure(e.oidcTokenFailure)),t.push(``,"To access the deployment from `eve dev`, do one of:"," • Run `vercel link` in this project so the CLI can mint an OIDC",` token for the deployment automatically.`,` • Set VERCEL_AUTOMATION_BYPASS_SECRET to a Protection Bypass for`,` Automation token (Project Settings → Deployment Protection).`,` • Disable Deployment Protection on the target deployment.`,``,`Docs: https://vercel.com/docs/deployment-protection`),t.join(`
|
|
5
5
|
`)}function formatDevelopmentOidcTokenFailure(e){switch(e.kind){case`resolution-failed`:return`The local Vercel OIDC token could not be resolved: ${e.message}`;case`malformed-token`:return e.reason===`missing-payload`?`Vercel returned a local OIDC token without a JWT payload.`:`Vercel returned a local OIDC token whose payload is not valid JSON.`;case`invalid-claims`:return`The local Vercel OIDC token has invalid claims: ${e.invalidClaims.join(`, `)}.`;case`target-mismatch`:return`The local Vercel OIDC token does not match the resolved deployment: ${e.mismatchedClaims.join(`, `)}.`;default:return e}}function formatVercelTrustedSourcesFailure(e){let t=e.replaceAll(`\r
|
|
6
6
|
`,`
|
|
7
7
|
`).trim().split(`
|
|
8
|
-
`),n=t.findIndex(e=>TRUSTED_SOURCES_ERROR_CODE.test(e.trim()));if(n<0)return e;let
|
|
9
|
-
`).trim();return
|
|
8
|
+
`),n=t.findIndex(e=>TRUSTED_SOURCES_ERROR_CODE.test(e.trim()));if(n<0)return e;let i=t[n].trim(),a=t.slice(0,n).join(`
|
|
9
|
+
`).trim();return a.length===0?e:`${a}\n\n${i}`}export{formatDevelopmentOidcTokenFailure,formatVercelAuthChallengeMessage,formatVercelTrustedSourcesFailure,isVercelAuthChallenge,vercelTrustedSourcesErrorCode};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.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.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.22.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.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.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.22.3`,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__",
|
|
@@ -44,8 +44,8 @@ You are a helpful assistant.
|
|
|
44
44
|
`,SHARED_TEMPLATE_FILES={"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE,"tsconfig.json":`{
|
|
45
45
|
"compilerOptions": {
|
|
46
46
|
"target": "ES2022",
|
|
47
|
-
"module": "
|
|
48
|
-
"moduleResolution": "
|
|
47
|
+
"module": "esnext",
|
|
48
|
+
"moduleResolution": "bundler",
|
|
49
49
|
"types": ["node"],
|
|
50
50
|
"strict": true,
|
|
51
51
|
"esModuleInterop": true,
|
|
@@ -95,4 +95,4 @@ export default defineAgent({
|
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
97
|
});
|
|
98
|
-
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate({includeRootOnlyFields:e.includeRootOnlyPackageJsonFields,packageManager:e.packageManager})}}async function assertCanCreateInPlace(e,n){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!n){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(o){let s=resolve(o.targetDirectory??process.cwd(),o.projectName),c=o.projectName===`.`,l=o.overwriteExisting??!1,u=o.byokProvider??!1,d=o.packageManager??`pnpm`,f=resolveEvePackageContract(o.evePackage),p=pinnedNodeEngineMajor(f.nodeEngine),m=resolve(o.workspaceProbeDirectory??s),h=isPackageManagerWorkspaceMember(d,m);if(c)await assertCanCreateInPlace(s,l);else if(await pathExists(s))throw Error(`Cannot create project because "${s}" already exists.`);let g={appName:basename(s),model:o.model,eveVersion:f.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,o.aiPackageVersion??`^7.0.0`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,o.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,o.zodPackageVersion??`4.4.3`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,o.typescriptPackageVersion??`7.0.
|
|
98
|
+
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate({includeRootOnlyFields:e.includeRootOnlyPackageJsonFields,packageManager:e.packageManager})}}async function assertCanCreateInPlace(e,n){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!n){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(o){let s=resolve(o.targetDirectory??process.cwd(),o.projectName),c=o.projectName===`.`,l=o.overwriteExisting??!1,u=o.byokProvider??!1,d=o.packageManager??`pnpm`,f=resolveEvePackageContract(o.evePackage),p=pinnedNodeEngineMajor(f.nodeEngine),m=resolve(o.workspaceProbeDirectory??s),h=isPackageManagerWorkspaceMember(d,m);if(c)await assertCanCreateInPlace(s,l);else if(await pathExists(s))throw Error(`Cannot create project because "${s}" already exists.`);let g={appName:basename(s),model:o.model,eveVersion:f.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,o.aiPackageVersion??`^7.0.0`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,o.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,o.zodPackageVersion??`4.4.3`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,o.typescriptPackageVersion??`7.0.2`),nodeTypesVersion:p,nodeEngine:p};await mkdir(s,{recursive:!0});for(let[e,r]of Object.entries(templateFiles({byokProvider:u,includeRootOnlyPackageJsonFields:!h,packageManager:d}))){let i=`${s}/${e}`,a=await pathExists(i);await writeTextFile(i,renderTemplate(r,g),{force:c&&l}),a&&await o.onOverwriteFile?.(i)}return await applyPackageManagerWorkspaceConfiguration({packageManager:d,projectRoot:s,workspaceProbeRoot:m,onWorkspaceRootMutation:o.onWorkspaceRootMutation}),await patchWorkspaceRootPackageJson(d,m,{aiPackageVersion:g.aiPackageVersion,nodeEngineRequirement:f.nodeEngine,onWorkspaceRootMutation:o.onWorkspaceRootMutation}),s}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.js
CHANGED
package/docs/agent-config.md
CHANGED
|
@@ -191,7 +191,7 @@ pnpm add @workflow/world-postgres@5.0.0-beta.x
|
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
The npm `latest` tag can lag behind that line, so an unpinned install may pull
|
|
194
|
-
an incompatible
|
|
194
|
+
an incompatible protocol version that the Workflow SDK rejects during initialization.
|
|
195
195
|
|
|
196
196
|
Put credentials and host-specific options in runtime environment variables read
|
|
197
197
|
by the world package, not in `agent.ts`. For the Postgres world, that means
|
package/docs/channels/custom.mdx
CHANGED
|
@@ -121,7 +121,7 @@ Route handlers can start a session on a different channel via `args.receive(chan
|
|
|
121
121
|
|
|
122
122
|
```ts
|
|
123
123
|
import { defineChannel, POST } from "eve/channels";
|
|
124
|
-
import slack from "./slack
|
|
124
|
+
import slack from "./slack";
|
|
125
125
|
|
|
126
126
|
export default defineChannel({
|
|
127
127
|
routes: [
|
|
@@ -220,7 +220,7 @@ The `context(state, session)` config option builds the per-step `channel` argume
|
|
|
220
220
|
```ts
|
|
221
221
|
import { defineChannel } from "eve/channels";
|
|
222
222
|
|
|
223
|
-
import { mintRef } from "./refs
|
|
223
|
+
import { mintRef } from "./refs";
|
|
224
224
|
|
|
225
225
|
defineChannel<{ ref: string | null }>({
|
|
226
226
|
state: { ref: null },
|
package/docs/channels/github.mdx
CHANGED
|
@@ -1,13 +1,46 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "GitHub"
|
|
3
|
-
description: "Reach your agent from GitHub App webhooks, with @mention dispatch, PR diff context, and
|
|
3
|
+
description: "Reach your agent from GitHub App webhooks, with @mention dispatch, PR diff context, sandbox checkout, and Vercel Connect credentials."
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The GitHub channel lets the agent work directly on a repository. Someone `@mentions` it in an issue, PR, or review comment, and the agent answers right there in the thread, with the PR diff already in context and the repo checked out into the sandbox. It takes GitHub App webhooks at `/eve/v1/github`, checks the signature, derives auth from whoever triggered the event, and replies on the native surface. See [Channels](./overview) for the contract this builds on.
|
|
7
|
+
The GitHub channel lets the agent work directly on a repository. Someone `@mentions` it in an issue, PR, or review comment, and the agent answers right there in the thread, with the PR diff already in context and the repo checked out into the sandbox. It takes GitHub App webhooks at `/eve/v1/github`, checks the signature, derives auth from whoever triggered the event, and replies on the native surface. Credentials can run through [Vercel Connect](../guides/auth-and-route-protection), which manages the GitHub App, the installation token, and inbound webhook verification, so there's no app private key or webhook secret for you to hold. See [Channels](./overview) for the contract this builds on.
|
|
8
|
+
|
|
9
|
+
## Set up Connect
|
|
10
|
+
|
|
11
|
+
Create a GitHub Connect client and copy its UID (e.g. `github/my-agent`), then attach this project as the trigger destination at eve's GitHub route:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g vercel@latest
|
|
15
|
+
vercel connect create github --triggers
|
|
16
|
+
vercel connect detach <uid> --yes
|
|
17
|
+
vercel connect attach <uid> --triggers --trigger-path /eve/v1/github --yes
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The `create` step provisions the GitHub App and a trigger destination at the default Connect path. `detach` then `attach --trigger-path /eve/v1/github` re-points the trigger at the eve GitHub route, since eve does not serve the default Connect path. `--triggers` makes Connect receive the App's webhooks, verify them, and forward them to your deployment. During registration, subscribe to `issue_comment` and `pull_request_review_comment` for mention-driven turns — the managed App defaults to `pull_request` only — and add `issues`, `pull_request`, `check_suite`, `check_run`, or `workflow_run` if you wire up their opt-in hooks. You can also create the client from the [Connect dashboard](https://vercel.com/d?to=/%5Bteam%5D/~/connect&title=Go+to+Connect).
|
|
8
21
|
|
|
9
22
|
## Add the channel
|
|
10
23
|
|
|
24
|
+
```bash
|
|
25
|
+
npm install @vercel/connect
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts title="agent/channels/github.ts"
|
|
29
|
+
import { connectGitHubCredentials } from "@vercel/connect/eve";
|
|
30
|
+
import { githubChannel } from "eve/channels/github";
|
|
31
|
+
|
|
32
|
+
export default githubChannel({
|
|
33
|
+
botName: "my-agent",
|
|
34
|
+
credentials: connectGitHubCredentials("github/my-agent"),
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`connectGitHubCredentials` returns `{ installationToken, webhookVerifier }`: eve uses the Connect-managed installation token directly for GitHub API calls, skipping its native App JWT exchange, and verifies Connect-forwarded webhooks by their Vercel OIDC signature instead of a GitHub webhook secret. Token rotation, refresh, and multi-installation tenancy stay inside Connect, so there is no `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`, or `GITHUB_WEBHOOK_SECRET` to manage.
|
|
39
|
+
|
|
40
|
+
### Bring your own GitHub App
|
|
41
|
+
|
|
42
|
+
To run a GitHub App you manage yourself, pass its credentials directly instead:
|
|
43
|
+
|
|
11
44
|
```ts title="agent/channels/github.ts"
|
|
12
45
|
import { githubChannel } from "eve/channels/github";
|
|
13
46
|
|
package/docs/channels/linear.mdx
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Linear"
|
|
3
|
-
description: "Reach your agent through Linear Agent Sessions, with native Agent Activities for progress, questions, and responses."
|
|
3
|
+
description: "Reach your agent through Linear Agent Sessions, with native Agent Activities for progress, questions, and responses, and Vercel Connect credentials."
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Linear channel uses Linear's Agent Session surface rather than ordinary comments. Users delegate work to the agent from Linear, eve receives `AgentSessionEvent` webhooks at `/eve/v1/linear`, and the channel replies with native Agent Activities, including `thought`, `action`, `elicitation`, `response`, and `error`. See [Channels](./overview) for the contract this builds on.
|
|
7
|
+
The Linear channel uses Linear's Agent Session surface rather than ordinary comments. Users delegate work to the agent from Linear, eve receives `AgentSessionEvent` webhooks at `/eve/v1/linear`, and the channel replies with native Agent Activities, including `thought`, `action`, `elicitation`, `response`, and `error`. Credentials can run through [Vercel Connect](../guides/auth-and-route-protection), which manages the Linear app, its access token, and inbound webhook verification, so there's no API key or webhook secret for you to hold. See [Channels](./overview) for the contract this builds on.
|
|
8
|
+
|
|
9
|
+
## Set up Connect
|
|
10
|
+
|
|
11
|
+
Create a Linear Connect client and copy its UID (e.g. `linear/my-agent`), then attach this project as the trigger destination at eve's Linear route:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g vercel@latest
|
|
15
|
+
vercel connect create linear --triggers
|
|
16
|
+
vercel connect detach <uid> --yes
|
|
17
|
+
vercel connect attach <uid> --triggers --trigger-path /eve/v1/linear --yes
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The `create` step provisions the Linear app — with the `app:assignable` and `app:mentionable` scopes the agent surface needs — and a trigger destination at the default Connect path. `detach` then `attach --trigger-path /eve/v1/linear` re-points the trigger at the eve Linear route, since eve does not serve the default Connect path. `--triggers` makes Connect receive Linear's webhooks, verify them, and forward them to your deployment. During registration, subscribe to the `AgentSessionEvent` webhook category — the managed app defaults to `Comment` and `Issue` — so Linear sends `created` events when the agent is delegated or mentioned and `prompted` events when the user continues the session. You can also create the client from the [Connect dashboard](https://vercel.com/d?to=/%5Bteam%5D/~/connect&title=Go+to+Connect).
|
|
8
21
|
|
|
9
22
|
## Add the channel
|
|
10
23
|
|
|
24
|
+
```bash
|
|
25
|
+
npm install @vercel/connect
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts title="agent/channels/linear.ts"
|
|
29
|
+
import { connectLinearCredentials } from "@vercel/connect/eve";
|
|
30
|
+
import { linearChannel } from "eve/channels/linear";
|
|
31
|
+
|
|
32
|
+
export default linearChannel({
|
|
33
|
+
credentials: connectLinearCredentials("linear/my-agent"),
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`connectLinearCredentials` returns `{ accessToken, webhookVerifier }`: eve uses the Connect-managed app token for Linear GraphQL calls and verifies Connect-forwarded webhooks by their Vercel OIDC signature instead of a Linear webhook secret. Token rotation, refresh, and multi-workspace tenancy stay inside Connect, so there is no `LINEAR_AGENT_ACCESS_TOKEN` or `LINEAR_WEBHOOK_SECRET` to manage.
|
|
38
|
+
|
|
39
|
+
### Bring your own Linear app
|
|
40
|
+
|
|
41
|
+
To run a Linear OAuth app you manage yourself, pass its credentials directly instead:
|
|
42
|
+
|
|
11
43
|
```ts title="agent/channels/linear.ts"
|
|
12
44
|
import { linearChannel } from "eve/channels/linear";
|
|
13
45
|
|
|
@@ -26,9 +58,7 @@ LINEAR_WEBHOOK_SECRET=... # verifies Linear-Signature
|
|
|
26
58
|
|
|
27
59
|
The sample passes credentials explicitly. To rely on env vars instead, drop the `credentials` block: the access token falls back to `LINEAR_AGENT_ACCESS_TOKEN`, `LINEAR_ACCESS_TOKEN`, `LINEAR_API_KEY`, or `LINEAR_API_TOKEN`, and the webhook secret falls back to `LINEAR_WEBHOOK_SECRET`. Both fields also accept lazy resolver functions.
|
|
28
60
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Create a Linear OAuth app, enable Agent Session events, and point the webhook URL at:
|
|
61
|
+
Create the Linear OAuth app, enable Agent Session events, and point the webhook URL at:
|
|
32
62
|
|
|
33
63
|
```text
|
|
34
64
|
https://<deployment>/eve/v1/linear
|
|
@@ -134,7 +164,7 @@ Use the channel's `receive` target to continue an existing Agent Session or crea
|
|
|
134
164
|
```ts
|
|
135
165
|
import { defineSchedule } from "eve/schedules";
|
|
136
166
|
|
|
137
|
-
import linear from "../channels/linear
|
|
167
|
+
import linear from "../channels/linear";
|
|
138
168
|
|
|
139
169
|
export default defineSchedule({
|
|
140
170
|
cron: "0 14 * * 1",
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -11,13 +11,13 @@ The Slack channel puts your agent inside a workspace. It answers `@mentions` and
|
|
|
11
11
|
Create a Slack Connect client and copy its UID (e.g. `slack/my-agent`), then attach this project as the trigger destination at eve's Slack route:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install -g vercel@latest
|
|
14
|
+
npm install -g vercel@latest
|
|
15
15
|
vercel connect create slack --triggers
|
|
16
16
|
vercel connect detach <uid> --yes
|
|
17
17
|
vercel connect attach <uid> --triggers --trigger-path /eve/v1/slack --yes
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
The `create` step provisions a destination at the default Connect path. `detach` then `attach --trigger-path /eve/v1/slack` re-points the trigger at the eve Slack route, since eve does not serve the default Connect path. `--triggers` turns on Slack Event Subscriptions; without it, Slack never delivers `app_mention` or `message.im`. You can also create the client from the [Connect dashboard](https://vercel.com/d?to=/%5Bteam%5D/~/connect&title=Go+to+Connect).
|
|
21
21
|
|
|
22
22
|
## Add the channel
|
|
23
23
|
|
|
@@ -99,7 +99,9 @@ when you need the bearer token itself.
|
|
|
99
99
|
|
|
100
100
|
### Delivery
|
|
101
101
|
|
|
102
|
-
The default handlers reply in-thread and show progress. Typing indicators post automatically: `Thinking…` on inbound, `Working…` on `turn.started`, a truncated reasoning snippet on `reasoning.appended`, and
|
|
102
|
+
The default handlers reply in-thread and show progress. Typing indicators post automatically: `Thinking…` on inbound, `Working…` on `turn.started`, a truncated reasoning snippet on `reasoning.appended`, and an action label on `actions.requested` — the tool name plus its most telling argument (`grep useEveAgent`, `read_file agent/agent.ts`), the subagent or remote-agent name for dispatched calls, and `+N more` when the model requests several actions at once. The model's own pre-tool narration, when present, takes precedence over the derived label. Reasoning snippets build progressively: extensions of at least four characters appear immediately, while smaller streamed deltas use the five-second refresh interval to avoid one Slack request per token. Override `events["reasoning.appended"]` if you prefer generic wording. Override `onAppMention` or the `events` handlers to customize.
|
|
103
|
+
|
|
104
|
+
Outbound text preserves bare `@` tokens as literal text. To mention a user, embed Slack's `<@USER_ID>` syntax directly or use `channel.thread.mentionUser(userId)`.
|
|
103
105
|
|
|
104
106
|
When a session starts without a `threadTs` (say, from a schedule or `receive(slack, ...)`), eve gives it a unique temporary continuation token. The first agent post anchors the session to the Slack message timestamp, and later posts and mentions resume that same session. Pass `initialMessage` with a `Card` to land a structured anchor first instead. `threadTs` and `initialMessage` are mutually exclusive.
|
|
105
107
|
|
|
@@ -22,7 +22,7 @@ To build the instructions prompt from typed helpers, lib code, or environment-de
|
|
|
22
22
|
|
|
23
23
|
```ts title="agent/instructions.ts"
|
|
24
24
|
import { defineInstructions } from "eve/instructions";
|
|
25
|
-
import { buildInstructionsPrompt } from "./lib/prompts
|
|
25
|
+
import { buildInstructionsPrompt } from "./lib/prompts";
|
|
26
26
|
|
|
27
27
|
export default defineInstructions({
|
|
28
28
|
markdown: buildInstructionsPrompt(),
|
|
@@ -36,7 +36,7 @@ export default defineAgent({
|
|
|
36
36
|
});
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
The world package backs workflow state, queues, hooks, and streams. Keep secrets and deployment-specific options in runtime environment variables read by that package, not in `agent.ts`.
|
|
39
|
+
The world package backs workflow state, queues, hooks, and streams. Keep secrets and deployment-specific options in runtime environment variables read by that package, not in `agent.ts`. Custom worlds must implement the runtime protocol expected by eve's vendored `@workflow/*` packages (currently the `5.0.0-beta` line); the Workflow SDK rejects incompatible protocol versions during initialization. See the [deployment guide](../guides/deployment#8-deploy-without-vercel) for the install command, plus [agent.ts](../agent-config#workflow-world) and [Workflow Worlds](https://workflow-sdk.dev/worlds).
|
|
40
40
|
|
|
41
41
|
## Resuming after a crash
|
|
42
42
|
|
|
@@ -23,7 +23,7 @@ export default defineOpenAPIConnection({
|
|
|
23
23
|
|
|
24
24
|
Each operation becomes `<connection>__<operationId>`, for example `petstore__getInventory`. When an operation has no `operationId`, eve derives a deterministic `<method>_<sanitized-path>` name instead.
|
|
25
25
|
|
|
26
|
-
`spec` can be
|
|
26
|
+
`spec` can be a URL that eve fetches at runtime, or an inline parsed OpenAPI object. A spec URL must use `https` (plain `http` is allowed only for loopback hosts such as `localhost` during local development), and eve re-checks the transport after any redirects. Prefer a URL when the provider owns the contract and updates it; prefer an inline object for private APIs, generated specs you pin in source control, or small hand-authored contracts.
|
|
27
27
|
|
|
28
28
|
## Base URL and servers
|
|
29
29
|
|
|
@@ -34,6 +34,8 @@ eve resolves operation paths against `baseUrl` when you provide one. Otherwise,
|
|
|
34
34
|
|
|
35
35
|
Use `baseUrl` when the spec is missing server data, points at the wrong environment, uses a relative server URL you do not want, or needs to be pinned for this agent.
|
|
36
36
|
|
|
37
|
+
The resolved base URL must use `https` too (loopback hosts may use `http` for local development), since operation calls carry the connection's credentials.
|
|
38
|
+
|
|
37
39
|
```ts title="agent/connections/crm.ts"
|
|
38
40
|
import { defineOpenAPIConnection } from "eve/connections";
|
|
39
41
|
|
|
@@ -77,13 +77,15 @@ Pick the cheapest builder that captures what "correct" means. When exact match i
|
|
|
77
77
|
|
|
78
78
|
## The matcher mini-language
|
|
79
79
|
|
|
80
|
-
`t.calledTool` and `t.calledSubagent` take matcher objects. Tools accept `{ input, output, status, count }`; subagents accept `{ remoteUrl, output, status, count }`. Calls match `status: "completed"` by default; use `"pending"`, `"failed"`, or `"rejected"` explicitly for lifecycle checks. `count`
|
|
80
|
+
`t.calledTool` and `t.calledSubagent` take matcher objects. Tools accept `{ input, output, status, count }`; subagents accept `{ remoteUrl, output, status, count }`. Calls match `status: "completed"` by default; use `"pending"`, `"failed"`, or `"rejected"` explicitly for lifecycle checks. A numeric `count` requires an exact number of calls matching every supplied constraint. Use a predicate for ranges or other custom count requirements; it receives the observed number of matching calls.
|
|
81
81
|
|
|
82
82
|
Matcher values accept a literal (objects partial-deep-match), a RegExp, or a predicate function that returns a boolean:
|
|
83
83
|
|
|
84
84
|
```ts
|
|
85
85
|
t.calledTool("bash", { input: { command: /^pwd/ }, count: 1 });
|
|
86
86
|
|
|
87
|
+
t.calledTool("echo", { count: (count) => count >= 2 });
|
|
88
|
+
|
|
87
89
|
t.calledTool("echo", { output: (value) => String(value).includes(marker) });
|
|
88
90
|
|
|
89
91
|
parked.calledTool("guarded", { status: "pending", count: 1 });
|
|
@@ -108,7 +110,7 @@ const request = session.requireInputRequest({
|
|
|
108
110
|
|
|
109
111
|
Beyond the raw `t.events` stream, the runner derives typed facts the assertions read: tool calls (name, input, output, lifecycle status), subagent calls, and HITL input requests. A turn that leaves the session open for a next message is the normal end state of a successful turn; parking on unanswered HITL input is tracked separately.
|
|
110
112
|
|
|
111
|
-
Typed event matching covers presence, absence,
|
|
113
|
+
Typed event matching covers presence, absence, numeric or predicate counts, partial event data, and ordering:
|
|
112
114
|
|
|
113
115
|
```ts
|
|
114
116
|
turn.notEvent("result.completed");
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Extensions"
|
|
3
|
+
description: "Package tools, connections, skills, and hooks as a reusable package and mount it into an agent."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
An extension packages eve capabilities — tools, connections, skills, instructions, hooks — as a reusable npm or local package. You author it as an agent-shaped directory; a consuming agent mounts it under `agent/extensions/`, and its contributions compose into the agent under a namespace. Nothing is copied — upgrades come through the package manager.
|
|
7
|
+
|
|
8
|
+
## Authoring
|
|
9
|
+
|
|
10
|
+
An extension is an agent-shaped directory without `agent.ts` or `sandbox` (those belong to the consuming agent). Every slot works as it does in an agent, with names derived from paths.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
@acme/crm/
|
|
14
|
+
package.json
|
|
15
|
+
ext/
|
|
16
|
+
extension.ts # the extension declaration — see Configuration
|
|
17
|
+
tools/search.ts
|
|
18
|
+
connections/api.ts
|
|
19
|
+
skills/triage/SKILL.md
|
|
20
|
+
hooks/audit.ts
|
|
21
|
+
lib/http.ts # shared helpers, imported as ../lib/http
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Name tools and connections for what they do (`search`, not `crm_search`) — the mount supplies the namespace. Shared code goes in `ext/lib/`, imported by relative path — eve compiles the source, so relative imports need no `.js` extension.
|
|
25
|
+
|
|
26
|
+
### Configuration
|
|
27
|
+
|
|
28
|
+
Declare the extension in `ext/extension.ts` with `defineExtension`; its default export is the mount factory a consumer calls. Pass `config` — any [Standard Schema](https://standardschema.dev) (a Zod object here), like a tool's `inputSchema` — to accept consumer settings:
|
|
29
|
+
|
|
30
|
+
```ts title="ext/extension.ts"
|
|
31
|
+
import { defineExtension } from "eve/extension";
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
|
|
34
|
+
export default defineExtension({
|
|
35
|
+
config: z.object({
|
|
36
|
+
apiKey: z.string(),
|
|
37
|
+
baseUrl: z.string().default("https://api.acme.example"),
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Config is optional — `defineExtension()` with no schema. Read it off the handle, imported from the declaration; it's typed from the schema:
|
|
43
|
+
|
|
44
|
+
```ts title="ext/tools/search.ts"
|
|
45
|
+
import { defineTool } from "eve/tools";
|
|
46
|
+
|
|
47
|
+
import extension from "../extension";
|
|
48
|
+
|
|
49
|
+
export default defineTool({
|
|
50
|
+
description: "Search the CRM.",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
/* ... */
|
|
53
|
+
},
|
|
54
|
+
async execute({ query }) {
|
|
55
|
+
const { apiKey, baseUrl } = extension.config; // validated, defaults applied
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Config is bound once when the consumer mounts the extension and stays constant for the session; per-request values belong in connection auth instead.
|
|
61
|
+
|
|
62
|
+
### State
|
|
63
|
+
|
|
64
|
+
`defineState` is scoped to the extension's package automatically, so identically-named state never collides with the consuming agent or another extension. Author it exactly as in an agent — `defineState("budget", …)`.
|
|
65
|
+
|
|
66
|
+
## Publishing
|
|
67
|
+
|
|
68
|
+
Point `eve.extension` at the source directory and run `eve build` (wired to `build`/`prepare`):
|
|
69
|
+
|
|
70
|
+
```jsonc title="package.json"
|
|
71
|
+
{
|
|
72
|
+
"name": "@acme/crm",
|
|
73
|
+
"type": "module",
|
|
74
|
+
"eve": { "extension": "./ext" },
|
|
75
|
+
"files": ["ext", "dist"],
|
|
76
|
+
"peerDependencies": { "eve": "^x" },
|
|
77
|
+
"dependencies": { "zod": "^3" },
|
|
78
|
+
"scripts": { "build": "eve build", "prepare": "eve build" },
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Author the source with `moduleResolution: "bundler"` — eve compiles it, so relative imports need no `.js` extension:
|
|
83
|
+
|
|
84
|
+
```jsonc title="tsconfig.json"
|
|
85
|
+
{
|
|
86
|
+
"compilerOptions": {
|
|
87
|
+
"module": "esnext",
|
|
88
|
+
"moduleResolution": "bundler",
|
|
89
|
+
"strict": true,
|
|
90
|
+
"noEmit": true,
|
|
91
|
+
"types": ["node"],
|
|
92
|
+
},
|
|
93
|
+
"include": ["ext/**/*.ts"],
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`eve build` compiles the package's entry points to plain JavaScript with type declarations — the mount factory (`dist/index.mjs`) and the tool re-exports overrides use (`dist/tools`) — and fills the `exports` map so you never hand-list it. Compiling is what lets an installed extension load directly; local and workspace packages also work without publishing.
|
|
98
|
+
|
|
99
|
+
### Dependencies
|
|
100
|
+
|
|
101
|
+
`eve` is a **peer** dependency: one eve lives in the consuming app and the extension's `eve/*` imports resolve to it. Declare the eve versions your extension supports as the peer range (`"eve": "^1"`) — eve enforces it when the extension is mounted, failing the build with a clear error if the app's eve is out of range, rather than surfacing a confusing compile break. Everything else the extension imports (SDKs, `zod`, …) goes in `dependencies`; each extension resolves its own versions. The consumer recompiles the extension's contributions from source, so `files` must ship both `ext/` (that source) and `dist/` (the compiled entry points).
|
|
102
|
+
|
|
103
|
+
Those deps resolve from `node_modules` under `eve dev`/`eve eval` and are bundled into the deployable by `eve build`. A dependency that can't be bundled (a native addon) must be listed in the **consuming agent's** `build.externalDependencies` — an extension can't declare build config, so note it in your README.
|
|
104
|
+
|
|
105
|
+
## Mounting
|
|
106
|
+
|
|
107
|
+
A consuming agent mounts an extension under `agent/extensions/` — a single file, or a directory when it needs [overrides](#overrides). The namespace is the file basename or directory name; contributions compose as `<namespace>__<name>` (`crm__search`, `crm__api`).
|
|
108
|
+
|
|
109
|
+
```ts title="agent/extensions/crm.ts"
|
|
110
|
+
import crm from "@acme/crm";
|
|
111
|
+
|
|
112
|
+
export default crm({ apiKey: process.env.CRM_API_KEY });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
A no-config extension takes no factory call — mount it with a bare re-export:
|
|
116
|
+
|
|
117
|
+
```ts title="agent/extensions/gizmo.ts"
|
|
118
|
+
export { default } from "@acme/gizmo";
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Overrides
|
|
122
|
+
|
|
123
|
+
To override a mounted extension's contributions, author the mount as a directory: the declaration in `extension.ts`, override slots alongside it.
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
agent/extensions/crm/
|
|
127
|
+
extension.ts # export default crm({ apiKey: process.env.CRM_API_KEY })
|
|
128
|
+
tools/search.ts # composes as crm__search, shadowing the extension's own
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
A file in an override slot composes under the mount namespace and wins on a name collision. Name it for the bare contribution name (`search`, not `crm__search`) — the directory supplies the prefix. To tweak the extension's own definition, import and re-define it:
|
|
132
|
+
|
|
133
|
+
```ts title="agent/extensions/crm/tools/search.ts"
|
|
134
|
+
import { search } from "@acme/crm/tools";
|
|
135
|
+
import { defineTool } from "eve/tools";
|
|
136
|
+
import { always } from "eve/tools/approval";
|
|
137
|
+
|
|
138
|
+
export default defineTool({ ...search, approval: always() });
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Or drop it entirely by opting out of the slot with `disableTool()`:
|
|
142
|
+
|
|
143
|
+
```ts title="agent/extensions/crm/tools/search.ts"
|
|
144
|
+
import { disableTool } from "eve/tools";
|
|
145
|
+
|
|
146
|
+
export default disableTool();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
An override targets one slot, matched by name and kind: a static file replaces the extension's static tool, a dynamic file replaces its dynamic resolver, and `disableTool()` removes whichever the extension put there. Because a dynamic tool wins over a same-named static one at runtime, replace or disable a dynamic tool through its own slot — a static file of the same name won't shadow it.
|
|
150
|
+
|
|
151
|
+
Overrides only work here — the `<namespace>__` prefix is reserved, so an agent-root contribution named `crm__…` is a build error and an extension can't be shadowed from outside its mount.
|
|
152
|
+
|
|
153
|
+
## Limits
|
|
154
|
+
|
|
155
|
+
An extension cannot declare a `sandbox`, agent config, schedules, or limits, and cannot mount other extensions — those are the consuming agent's to own (background scheduling, for instance, runs on the agent's deployment under its limits). An extension's tools run within the consuming agent's per-session limits.
|
|
@@ -19,7 +19,7 @@ const client = new Client({
|
|
|
19
19
|
});
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
`host` is the
|
|
22
|
+
`host` is the URL where the eve routes are mounted. In a same-origin browser integration this is often `""`; scripts and backend services usually name the full URL. Any query parameters on `host` are included on every request, including session POSTs and event streams. Request-specific parameters, such as a stream cursor, take precedence when names overlap.
|
|
23
23
|
|
|
24
24
|
## Check health
|
|
25
25
|
|
|
@@ -140,7 +140,7 @@ Eve writes the standard Nitro output under `.output/` instead of Vercel Build Ou
|
|
|
140
140
|
|
|
141
141
|
Self-deployed agents should make the Vercel-specific choices explicit:
|
|
142
142
|
|
|
143
|
-
- Let the Workflow SDK use its default local world, which stores workflow state under `.workflow-data`, configure your host so that directory is on persistent storage, or select another world with `experimental.workflow.world` in the root `agent.ts`. When you select a custom world, install a world package built against the same `@workflow/*` line as your eve release (currently the `5.0.0-beta` line). The npm `latest` tag may lag, so pin the version explicitly, for example `pnpm add @workflow/world-postgres@5.0.0-beta.x`.
|
|
143
|
+
- Let the Workflow SDK use its default local world, which stores workflow state under `.workflow-data`, configure your host so that directory is on persistent storage, or select another world with `experimental.workflow.world` in the root `agent.ts`. When you select a custom world, install a world package built against the same `@workflow/*` line as your eve release (currently the `5.0.0-beta` line). The npm `latest` tag may lag, so pin the version explicitly, for example `pnpm add @workflow/world-postgres@5.0.0-beta.x`. The Workflow SDK rejects worlds with an incompatible runtime protocol during initialization.
|
|
144
144
|
- If you put a reverse proxy or ingress in front of eve, forward **both** `/eve/` and `/.well-known/workflow/`. The workflow world delivers run callbacks to `/.well-known/workflow/v1/flow`; a proxy restricted to `/eve/` lets sessions start but silently stalls runs forever, because the callbacks never reach eve.
|
|
145
145
|
- Install the AI SDK package for your provider, then use a direct provider model object and `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` when you want no Gateway dependency.
|
|
146
146
|
- Use `AI_GATEWAY_API_KEY` if you still want Gateway routing from a non-Vercel host.
|
package/docs/guides/dev-tui.md
CHANGED
|
@@ -136,6 +136,10 @@ eve dev https://user:pass@<your-app>
|
|
|
136
136
|
|
|
137
137
|
For bearer tokens or custom schemes, repeat `-H, --header` to attach request headers.
|
|
138
138
|
|
|
139
|
+
Query parameters in the target URL are preserved on every request, including
|
|
140
|
+
session POSTs and event streams. This also supports deployment-protection URLs
|
|
141
|
+
that carry their bypass credential in the query string.
|
|
142
|
+
|
|
139
143
|
At startup the TUI asks Vercel to resolve the remote origin under the active scope. A resolved response is the authority for a project-scoped OIDC token—refreshing an expired development token when refresh credentials exist—or an automation-bypass secret. An unresolved host is probed anonymously. The TUI then requests `/eve/v1/info`, with a ten-second timeout. A successful response marks the remote ready. An eve OIDC challenge, Vercel Deployment Protection challenge, or `TRUSTED_SOURCES_ENVIRONMENT_MISMATCH` opens `/vc:login` automatically; ordinary network failures and server errors remain remote-availability errors and do not start an authentication flow. Esc or Ctrl-C cancels the authentication flow.
|
|
140
144
|
|
|
141
145
|
In a remote session, `/vc:login` first resolves the deployment's Vercel project from its URL. If the active Vercel scope cannot resolve it, the flow asks for another team and reruns the lookup in that team's scope. If the CLI is logged out, the same panel runs the browser login first. The flow asks before adding any required Trusted Sources rule and requests a project-scoped token through `@vercel/oidc`. It does not relink the directory or modify `.env.local`. Finally, it retries `/eve/v1/info` to prove the credential works. A failure reports any login or Trusted Sources update that completed before it stopped.
|
|
@@ -30,7 +30,7 @@ The example below builds one tool per warehouse table. A map return names each t
|
|
|
30
30
|
```ts title="agent/tools/query.ts"
|
|
31
31
|
import { defineDynamic, defineTool } from "eve/tools";
|
|
32
32
|
import { z } from "zod";
|
|
33
|
-
import { listTables, runReadOnly } from "../lib/warehouse
|
|
33
|
+
import { listTables, runReadOnly } from "../lib/warehouse";
|
|
34
34
|
|
|
35
35
|
export default defineDynamic({
|
|
36
36
|
events: {
|
|
@@ -89,7 +89,7 @@ A single file can declare handlers for several events, and the most recently fir
|
|
|
89
89
|
```ts title="agent/tools/catalog.ts"
|
|
90
90
|
import { defineDynamic, defineTool } from "eve/tools";
|
|
91
91
|
import { z } from "zod";
|
|
92
|
-
import { runReadOnly, searchCatalog } from "../lib/catalog
|
|
92
|
+
import { runReadOnly, searchCatalog } from "../lib/catalog";
|
|
93
93
|
|
|
94
94
|
export default defineDynamic({
|
|
95
95
|
events: {
|
|
@@ -120,7 +120,7 @@ A dynamic skills file resolves which [skill](../skills) a caller can load, keyed
|
|
|
120
120
|
|
|
121
121
|
```ts title="agent/skills/team_playbook.ts"
|
|
122
122
|
import { defineDynamic, defineSkill } from "eve/skills";
|
|
123
|
-
import { PLAYBOOKS } from "../lib/playbooks
|
|
123
|
+
import { PLAYBOOKS } from "../lib/playbooks";
|
|
124
124
|
|
|
125
125
|
export default defineDynamic({
|
|
126
126
|
events: {
|