eve 0.21.1 → 0.22.1
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 +20 -0
- package/dist/src/channel/adapter.d.ts +3 -7
- package/dist/src/channel/types.d.ts +18 -1
- package/dist/src/compiler/manifest.d.ts +16 -26
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/compiler/normalize-hook.d.ts +2 -2
- package/dist/src/compiler/normalize-instructions.d.ts +3 -3
- package/dist/src/compiler/normalize-instructions.js +1 -1
- package/dist/src/compiler/normalize-skill.js +1 -1
- package/dist/src/compiler/normalize-tool.d.ts +2 -2
- package/dist/src/context/container.d.ts +2 -0
- package/dist/src/context/dynamic-model-lifecycle.d.ts +19 -0
- package/dist/src/context/dynamic-model-lifecycle.js +1 -0
- package/dist/src/context/keys.d.ts +13 -1
- package/dist/src/context/keys.js +1 -1
- package/dist/src/discover/manifest.d.ts +8 -0
- package/dist/src/evals/cli/eval.js +2 -2
- package/dist/src/evals/reporters/index.d.ts +1 -0
- package/dist/src/evals/reporters/index.js +1 -1
- package/dist/src/evals/runner/reporters/console.d.ts +10 -11
- package/dist/src/evals/runner/reporters/console.js +1 -1
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/reconcile-session-continuation-token.d.ts +4 -0
- package/dist/src/execution/reconcile-session-continuation-token.js +1 -0
- package/dist/src/execution/sandbox/bindings/microsandbox-options.d.ts +2 -2
- package/dist/src/execution/sandbox/bindings/microsandbox.d.ts +2 -2
- package/dist/src/execution/sandbox/bindings/vercel-credentials.js +1 -1
- package/dist/src/execution/sandbox/ensure.js +1 -1
- package/dist/src/execution/session.js +2 -2
- package/dist/src/execution/subagent-adapter.js +1 -1
- package/dist/src/execution/subagent-event-proxy-step.d.ts +23 -0
- package/dist/src/execution/subagent-event-proxy-step.js +1 -0
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +1 -22
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/emission.d.ts +1 -0
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/input-extraction.d.ts +1 -0
- package/dist/src/harness/input-extraction.js +1 -1
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/step-hooks.d.ts +4 -1
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-call-input-errors.d.ts +8 -0
- package/dist/src/harness/tool-call-input-errors.js +1 -0
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/types.d.ts +9 -0
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/core.js +1 -1
- package/dist/src/internal/authored-definition/schema-backed.js +1 -1
- package/dist/src/internal/nitro/host/types.d.ts +2 -2
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +2 -2
- package/dist/src/internal/nitro/routes/agent-info/load-agent-info-data.d.ts +4 -4
- package/dist/src/internal/runtime-model.d.ts +1 -1
- package/dist/src/protocol/message.d.ts +1 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +1 -1
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
- package/dist/src/public/channels/discord/discordChannel.d.ts +2 -2
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/eve.d.ts +1 -1
- package/dist/src/public/channels/eve.js +1 -1
- package/dist/src/public/channels/github/dispatch.d.ts +1 -1
- package/dist/src/public/channels/github/githubChannel.d.ts +2 -2
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/index.d.ts +2 -2
- package/dist/src/public/channels/index.js +1 -1
- package/dist/src/public/channels/linear/linearChannel.d.ts +1 -1
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/slack/hitl.d.ts +3 -2
- package/dist/src/public/channels/slack/hitl.js +3 -3
- package/dist/src/public/channels/slack/index.d.ts +1 -1
- package/dist/src/public/channels/slack/index.js +1 -1
- package/dist/src/public/channels/slack/interactions.d.ts +1 -1
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/limits.d.ts +18 -0
- package/dist/src/public/channels/slack/limits.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +2 -2
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.d.ts +2 -2
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.d.ts +2 -2
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +2 -2
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/agent.d.ts +1 -1
- package/dist/src/public/definitions/channel.d.ts +99 -0
- package/dist/src/public/definitions/channel.js +1 -1
- package/dist/src/public/definitions/hook.d.ts +3 -10
- package/dist/src/public/definitions/instructions.d.ts +2 -18
- package/dist/src/public/definitions/schedule.d.ts +4 -17
- package/dist/src/public/definitions/tool.d.ts +10 -4
- package/dist/src/public/definitions/tool.js +1 -1
- package/dist/src/public/hooks/index.d.ts +1 -1
- package/dist/src/public/hooks/index.js +1 -1
- package/dist/src/public/index.d.ts +2 -0
- package/dist/src/public/index.js +1 -1
- package/dist/src/public/sandbox/backends/default.d.ts +2 -2
- package/dist/src/public/sandbox/backends/microsandbox.d.ts +2 -2
- package/dist/src/public/sandbox/microsandbox-sandbox.d.ts +1 -1
- package/dist/src/public/sandbox/microsandbox.d.ts +1 -1
- package/dist/src/runtime/agent/bootstrap.d.ts +8 -0
- package/dist/src/runtime/agent/bootstrap.js +1 -1
- package/dist/src/runtime/agent/resolve-model.d.ts +16 -1
- package/dist/src/runtime/agent/resolve-model.js +1 -1
- package/dist/src/runtime/hooks/registry.d.ts +2 -1
- package/dist/src/runtime/prompt/compose.d.ts +2 -2
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/sandbox/keys.d.ts +4 -0
- package/dist/src/runtime/sandbox/keys.js +1 -1
- package/dist/src/runtime/sandbox/template-plan.d.ts +0 -2
- package/dist/src/runtime/schedules/register.d.ts +2 -2
- package/dist/src/runtime/schedules/resolve-schedule.d.ts +4 -4
- package/dist/src/runtime/types.d.ts +7 -4
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/shared/agent-definition.d.ts +30 -7
- package/dist/src/shared/agent-definition.js +1 -1
- package/dist/src/shared/channel-definition.d.ts +92 -0
- package/dist/src/shared/channel-definition.js +1 -0
- package/dist/src/shared/dynamic-tool-definition.d.ts +18 -8
- package/dist/src/shared/dynamic-tool-definition.js +1 -1
- package/dist/src/shared/hook-definition.d.ts +36 -0
- package/dist/src/shared/hook-definition.js +1 -0
- package/dist/src/shared/instructions-definition.d.ts +26 -0
- package/dist/src/shared/instructions-definition.js +1 -0
- package/dist/src/shared/schedule-definition.d.ts +34 -0
- package/dist/src/shared/schedule-definition.js +1 -0
- package/dist/src/shared/vercel-project.d.ts +25 -0
- package/dist/src/shared/vercel-project.js +1 -0
- package/dist/src/source-change/apply-model-name.js +1 -1
- package/docs/agent-config.md +44 -0
- package/docs/channels/slack.mdx +27 -0
- package/docs/connections/overview.mdx +2 -0
- package/docs/guides/dynamic-capabilities.md +18 -2
- package/docs/sandbox.mdx +3 -1
- package/docs/subagents.mdx +1 -1
- package/package.json +1 -1
- package/dist/src/public/definitions/defineChannel.d.ts +0 -157
- package/dist/src/public/definitions/defineChannel.js +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public definition for an instructions prompt authored in markdown or
|
|
3
|
+
* TypeScript.
|
|
4
|
+
*
|
|
5
|
+
* Authored at the agent root as either `instructions.md` or
|
|
6
|
+
* `instructions.{ts,cts,mts,js,cjs,mjs}`, or inside the
|
|
7
|
+
* `agent/instructions/` directory for multi-file setups. Module-backed
|
|
8
|
+
* static instructions execute once at build time. The compiler captures
|
|
9
|
+
* the resulting markdown into the compiled manifest.
|
|
10
|
+
*
|
|
11
|
+
* When used inside a `defineDynamic` handler, the runtime lowers the
|
|
12
|
+
* returned markdown to `{ role: "system", content: markdown }`.
|
|
13
|
+
* Instructions produce system messages only. Use channel `context` for
|
|
14
|
+
* user-role messages.
|
|
15
|
+
*/
|
|
16
|
+
export interface PublicInstructionsDefinition {
|
|
17
|
+
markdown: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Internal definition for an instructions prompt authored in markdown or
|
|
21
|
+
* TypeScript.
|
|
22
|
+
*/
|
|
23
|
+
export interface InternalInstructionsDefinition {
|
|
24
|
+
name: string;
|
|
25
|
+
markdown: string;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `run` form of {@link ScheduleDefinition} invokes this handler when a
|
|
3
|
+
* schedule's cron fires. It receives {@link ScheduleHandlerArgs} (`receive`,
|
|
4
|
+
* `waitUntil`, `appAuth`) and may return synchronously or as a promise.
|
|
5
|
+
*/
|
|
6
|
+
export type GenericScheduleRunHandler<TArgs> = (args: TArgs) => Promise<void> | void;
|
|
7
|
+
/** Constraint shape that bounds the authored keys accepted by {@link defineSchedule}. */
|
|
8
|
+
export interface GenericScheduleDefinitionFields<TArgs> {
|
|
9
|
+
readonly cron: string;
|
|
10
|
+
readonly markdown?: string;
|
|
11
|
+
readonly run?: GenericScheduleRunHandler<TArgs>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Public definition for a schedule authored in TypeScript. Provide a required
|
|
15
|
+
* `cron` expression plus exactly one of `markdown` or `run`:
|
|
16
|
+
*
|
|
17
|
+
* - `markdown`: fire-and-forget agent invocation. The framework runs the agent
|
|
18
|
+
* on the prompt and discards the output (equivalent to the `<name>.md`
|
|
19
|
+
* markdown form).
|
|
20
|
+
* - `run`: full handler ({@link GenericScheduleRunHandler}). Receives
|
|
21
|
+
* `{ receive, waitUntil, appAuth }` and decides what to do.
|
|
22
|
+
*
|
|
23
|
+
* Identity is derived from the file path under `agent/schedules/`; authored
|
|
24
|
+
* definitions do not carry a `name` field.
|
|
25
|
+
*/
|
|
26
|
+
export type GenericScheduleDefinition<TArgs> = {
|
|
27
|
+
readonly cron: string;
|
|
28
|
+
readonly markdown: string;
|
|
29
|
+
readonly run?: never;
|
|
30
|
+
} | {
|
|
31
|
+
readonly cron: string;
|
|
32
|
+
readonly markdown?: never;
|
|
33
|
+
readonly run: GenericScheduleRunHandler<TArgs>;
|
|
34
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claims eve reads from a Vercel OIDC token payload.
|
|
3
|
+
*
|
|
4
|
+
* Decoded locally without signature verification: callers use the values
|
|
5
|
+
* as stable identifiers (sandbox key derivation, credential routing),
|
|
6
|
+
* never to make authentication decisions.
|
|
7
|
+
*/
|
|
8
|
+
export interface VercelOidcTokenClaims {
|
|
9
|
+
readonly ownerId: string | undefined;
|
|
10
|
+
readonly projectId: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Decodes the payload claims of a Vercel OIDC token. Values that are not
|
|
14
|
+
* decodable JWTs, or that carry no recognized claims, decode to empty
|
|
15
|
+
* claims — callers only ever check individual fields.
|
|
16
|
+
*/
|
|
17
|
+
export declare function decodeVercelOidcTokenClaims(token: string): VercelOidcTokenClaims;
|
|
18
|
+
/**
|
|
19
|
+
* Resolves the Vercel project id visible to this process: the
|
|
20
|
+
* `VERCEL_PROJECT_ID` env var when exposed, otherwise the `project_id`
|
|
21
|
+
* claim of `VERCEL_OIDC_TOKEN`. Both sources exist at build time and at
|
|
22
|
+
* deployed runtime and name the same project, so identifiers derived
|
|
23
|
+
* from this value agree across the two phases.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveVercelProjectIdFromEnvironment(): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const EMPTY_CLAIMS={ownerId:void 0,projectId:void 0};function decodeVercelOidcTokenClaims(t){let n=t.split(`.`)[1];if(n===void 0||n.length===0)return EMPTY_CLAIMS;let r;try{r=JSON.parse(Buffer.from(n,`base64url`).toString(`utf8`))}catch{return EMPTY_CLAIMS}if(typeof r!=`object`||!r)return EMPTY_CLAIMS;let i=r;return{ownerId:typeof i.owner_id==`string`?i.owner_id:void 0,projectId:typeof i.project_id==`string`?i.project_id:void 0}}function resolveVercelProjectIdFromEnvironment(){let e=process.env.VERCEL_PROJECT_ID?.trim();if(e!==void 0&&e.length>0)return e;let t=process.env.VERCEL_OIDC_TOKEN?.trim();if(!(t===void 0||t.length===0))return decodeVercelOidcTokenClaims(t).projectId}export{decodeVercelOidcTokenClaims,resolveVercelProjectIdFromEnvironment};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{parseWithNitroRolldownAst}from"#internal/bundler/nitro-rolldown.js";const AGENT_FACTORY=`defineAgent`;async function applyModelNameToSource(e,n){let r=await parseAgentSource(e);if(`kind`in r)return r;if((r.errors?.length??0)>0){let t=r.errors?.[0];return{kind:`bail`,reason:`agent.ts does not parse: ${t?.message??`unknown parse error`}`,line:parseErrorLine(e,t)}}let i=findDefineAgentObject(r.program??r,AGENT_FACTORY);if(i===void 0)return{kind:`bail`,reason:`no \`export default ${AGENT_FACTORY}({ ... })\` call found`,line:1};let a=findStringLiteralProperty(i,`model`);if(a===void 0)return{kind:`bail`,reason:"`model` is absent or is not a string literal (e.g. an env reference, a template,
|
|
1
|
+
import{parseWithNitroRolldownAst}from"#internal/bundler/nitro-rolldown.js";const AGENT_FACTORY=`defineAgent`;async function applyModelNameToSource(e,n){let r=await parseAgentSource(e);if(`kind`in r)return r;if((r.errors?.length??0)>0){let t=r.errors?.[0];return{kind:`bail`,reason:`agent.ts does not parse: ${t?.message??`unknown parse error`}`,line:parseErrorLine(e,t)}}let i=findDefineAgentObject(r.program??r,AGENT_FACTORY);if(i===void 0)return{kind:`bail`,reason:`no \`export default ${AGENT_FACTORY}({ ... })\` call found`,line:1};let a=findStringLiteralProperty(i,`model`);if(a===void 0)return{kind:`bail`,reason:"`model` is absent or is not a string literal (e.g. an env reference, a template, an inlined SDK model, or a defineDynamic() dynamic model)",line:lineAt(e,i.start??0)};let o=a.value;if(o===n)return{kind:`applied`,from:o,to:n,nextSource:e};let s=a.raw?.[0]===`'`?`'`:`"`,c=`${s}${escapeForQuote(n,s)}${s}`;return{kind:`applied`,from:o,to:n,nextSource:e.slice(0,a.start)+c+e.slice(a.end)}}async function parseAgentSource(t){try{return await parseWithNitroRolldownAst(`agent.ts`,t)}catch(e){let n=e;return{kind:`bail`,reason:`agent.ts does not parse: ${n.message??`unknown parse error`}`,line:parseErrorLine(t,n)}}}function unwrapExpression(e){let t=e;for(;t.type===`ParenthesizedExpression`||t.type===`TSAsExpression`||t.type===`TSSatisfiesExpression`;){if(t.expression===void 0||t.expression===null)return t;t=t.expression}return t}function findDefineAgentObject(e,t){for(let n of e.body??[]){if(n.type!==`ExportDefaultDeclaration`)continue;let e=n.declaration;if(e==null||e.type!==`CallExpression`&&e.type!==`ParenthesizedExpression`&&e.type!==`TSAsExpression`&&e.type!==`TSSatisfiesExpression`)continue;let r=unwrapExpression(e);if(r.type!==`CallExpression`||!isFactoryCallee(r.callee,t))continue;let i=r.arguments?.[0];if(i===void 0||i.type===`SpreadElement`)continue;let a=unwrapExpression(i);if(a.type===`ObjectExpression`)return a}}function isFactoryCallee(e,t){return e?.type===`Identifier`&&e.name===t}function findStringLiteralProperty(e,t){for(let n of e.properties){if(n.type!==`Property`||n.computed||!keyMatches(n.key,t))continue;let e=n.value;if(!isAstNode(e))continue;let r=unwrapExpression(e);return r.type===`Literal`&&typeof r.value==`string`&&r.start!==void 0&&r.end!==void 0?r:void 0}}function keyMatches(e,t){return e===void 0?!1:e.type===`Identifier`?e.name===t:e.type===`Literal`?typeof e.value==`string`&&e.value===t:!1}function isAstNode(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function parseErrorLine(e,t){return typeof t?.loc?.line==`number`?t.loc.line:lineAt(e,t?.labels?.[0]?.start??t?.start??0)}function escapeForQuote(e,t){return e.replaceAll(`\\`,`\\\\`).replaceAll(t,`\\${t}`)}function lineAt(e,t){let n=1;for(let r=0;r<t&&r<e.length;r+=1)e[r]===`
|
|
2
2
|
`&&(n+=1);return n}export{applyModelNameToSource};
|
package/docs/agent-config.md
CHANGED
|
@@ -43,6 +43,50 @@ version uses hyphens (`claude-opus-4-8`), while the Gateway id above uses a dot
|
|
|
43
43
|
|
|
44
44
|
Model use is subject to the terms, data-processing commitments, retention behavior, and available controls of the selected provider and routing path. Review the [AI Gateway model catalog](https://vercel.com/ai-gateway/models) for gateway-routed models, and review the provider's terms when you configure a direct `LanguageModel`.
|
|
45
45
|
|
|
46
|
+
### Choose the model dynamically
|
|
47
|
+
|
|
48
|
+
`model` also accepts `defineDynamic({ fallback, events })`. `fallback` is the
|
|
49
|
+
compiled static model: it anchors build-time metadata (routing, credentials,
|
|
50
|
+
context window) and serves whenever no dynamic selection is set.
|
|
51
|
+
|
|
52
|
+
```ts title="agent/agent.ts"
|
|
53
|
+
import { defineAgent, defineDynamic } from "eve";
|
|
54
|
+
|
|
55
|
+
export default defineAgent({
|
|
56
|
+
model: defineDynamic({
|
|
57
|
+
fallback: "anthropic/claude-sonnet-5",
|
|
58
|
+
events: {
|
|
59
|
+
"session.started": (_event, ctx) =>
|
|
60
|
+
ctx.session.auth.initiator?.attributes.plan === "enterprise"
|
|
61
|
+
? "anthropic/claude-opus-4.8"
|
|
62
|
+
: null,
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Handlers receive the shared [dynamic resolver
|
|
69
|
+
context](./guides/dynamic-capabilities) (`ctx.session`, `ctx.channel`,
|
|
70
|
+
`ctx.messages`) and return a gateway model id, an AI SDK `LanguageModel`, a
|
|
71
|
+
selection object, or `null` to leave the scope unset.
|
|
72
|
+
|
|
73
|
+
- **Scopes.** `session.started` (once per session), `turn.started` (once per
|
|
74
|
+
turn), `step.started` (every model step). Precedence: step > turn >
|
|
75
|
+
session > `fallback`. Prefer `session.started`: prompt caches are per
|
|
76
|
+
model, so every switch re-ingests the conversation at uncached prices.
|
|
77
|
+
- **Failures degrade, never fail the turn.** A resolver that throws or
|
|
78
|
+
returns an invalid selection logs an error and leaves its scope unset.
|
|
79
|
+
Build-time validation covers only `fallback`; a selected model without
|
|
80
|
+
credentials fails at request time.
|
|
81
|
+
- **Serialization.** Session/turn selections must be model id strings; return
|
|
82
|
+
live `LanguageModel` objects only from `step.started`.
|
|
83
|
+
- **Selection object.** `{ model, modelContextWindowTokens?, modelOptions? }`.
|
|
84
|
+
Set `modelContextWindowTokens` when the selected model's window differs
|
|
85
|
+
from the fallback's — it is never inherited. Omitted `modelOptions` reuses
|
|
86
|
+
the agent-level `modelOptions`.
|
|
87
|
+
|
|
88
|
+
Runtime identity reports a dynamic agent's model as `dynamic:<fallback id>`.
|
|
89
|
+
|
|
46
90
|
## Reasoning effort
|
|
47
91
|
|
|
48
92
|
Set `reasoning` to control the model's reasoning effort through AI SDK's
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -70,6 +70,33 @@ export default slackChannel({
|
|
|
70
70
|
|
|
71
71
|
`threadContext` performs one `conversations.replies` request for each triggering thread reply and requires the matching Slack history scope. Omit it when the agent should see only direct mentions. `loadThreadContextMessages` remains available when you need custom filtering or non-model processing of the raw thread messages.
|
|
72
72
|
|
|
73
|
+
### Slack API calls outside a handler
|
|
74
|
+
|
|
75
|
+
Inside webhook-side handlers (`onAppMention`, `onInteraction`, `events`),
|
|
76
|
+
`ctx.slack.request(operation, body)` is the raw-API escape hatch. Outside
|
|
77
|
+
those contexts there is no handle — a schedule resolving reactions on old
|
|
78
|
+
messages, for example, has no inbound Slack request. For that, call the
|
|
79
|
+
same primitive the handle uses directly:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { callSlackApi, resolveSlackBotToken } from "eve/channels/slack";
|
|
83
|
+
import { connectSlackCredentials } from "@vercel/connect/eve";
|
|
84
|
+
|
|
85
|
+
const { botToken } = connectSlackCredentials("slack/my-agent");
|
|
86
|
+
const response = await callSlackApi({
|
|
87
|
+
botToken,
|
|
88
|
+
operation: "reactions.get",
|
|
89
|
+
body: { channel: "C0123456789", timestamp: "1712345678.000100", full: true },
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) throw new Error(String(response.error));
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`callSlackApi` resolves function-form tokens (secret managers, Connect
|
|
95
|
+
rotation) at call time and form-encodes the body — the only safe default,
|
|
96
|
+
since Slack's JSON support is partial (`conversations.replies` rejects
|
|
97
|
+
JSON). `resolveSlackBotToken` materializes a `SlackBotToken` to a string
|
|
98
|
+
when you need the bearer token itself.
|
|
99
|
+
|
|
73
100
|
### Delivery
|
|
74
101
|
|
|
75
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 tool status on `actions.requested`. 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.
|
|
@@ -138,6 +138,8 @@ export default defineMcpClientConnection({
|
|
|
138
138
|
|
|
139
139
|
`"linear/myagent"` is the UID you chose when registering the Connect client. `connect("linear/myagent")` is shorthand for a user-scoped interactive OAuth connection: eve resolves a token for the active user before each tool call, emits `authorization.required` when that user has not authorized yet, and resumes the parked turn after the callback completes.
|
|
140
140
|
|
|
141
|
+
When a local subagent needs interactive authorization, eve surfaces the authorization lifecycle on the root session's channel, including through nested subagent chains. The challenge still points to the child session's callback, so completing it resumes the child directly while the parent continues waiting for its result.
|
|
142
|
+
|
|
141
143
|
That means the channel that creates or continues the session must authenticate a real user. For a web app, configure `agent/channels/eve.ts` so your app session maps to `principalType: "user"`; for platform channels, use the built-in channel auth that maps the sender to a user principal. If no authenticated user is attached to the session, the first user-scoped connection call fails with `reason: "principal_required"`.
|
|
142
144
|
|
|
143
145
|
If the remote service should act as the agent itself instead of the end-user, make the Connect connection app-scoped:
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Dynamic Capabilities"
|
|
3
|
-
description: "Resolve tools, skills, and instructions at runtime
|
|
3
|
+
description: "Resolve models, tools, skills, and instructions at runtime: dynamic model selection, defineDynamic resolver events, execution order, and durable dynamic tools."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
`defineDynamic` resolves tools, skills, and instructions at runtime from a session event instead of declaring them up front. Reach for it when the right
|
|
6
|
+
`defineDynamic` resolves the model, 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 [tools](../tools), [skills](../skills), and [instructions](../instructions) guides each point here for their dynamic form.
|
|
7
|
+
|
|
8
|
+
## Dynamic models
|
|
9
|
+
|
|
10
|
+
The `model` field in `agent.ts` accepts `defineDynamic({ fallback, events })`.
|
|
11
|
+
Resolvers run at `session.started`, `turn.started`, or `step.started`
|
|
12
|
+
(precedence: step > turn > session > `fallback`); `null` leaves a scope unset
|
|
13
|
+
and failures degrade to the next scope. Prefer `session.started` — prompt
|
|
14
|
+
caches are per model, so switching mid-session re-ingests the conversation at
|
|
15
|
+
uncached prices. See
|
|
16
|
+
[agent configuration](../agent-config#choose-the-model-dynamically) for the
|
|
17
|
+
full contract.
|
|
18
|
+
|
|
19
|
+
`fallback` is model-only: the agent always needs exactly one model, and the
|
|
20
|
+
compiled fallback anchors build-time metadata. Tools, skills, and instructions
|
|
21
|
+
default by authoring a static entry (or returning `null`), so `fallback` on
|
|
22
|
+
their `defineDynamic` export is a build error.
|
|
7
23
|
|
|
8
24
|
## Dynamic tools
|
|
9
25
|
|
package/docs/sandbox.mdx
CHANGED
|
@@ -164,7 +164,7 @@ You can also write your own backend. A `SandboxBackend` is an adapter object wit
|
|
|
164
164
|
There are two hooks, scoped differently:
|
|
165
165
|
|
|
166
166
|
- **`bootstrap({ use })`** is template-scoped and runs once when the template is built. Put reusable setup here that every later session inherits, such as cloning a baseline repo, installing dependencies, or seeding files. Call `use()` to get a `SandboxSession`. Only template filesystem state and supported backend metadata carry into later sessions; config like network policy does not. If external inputs affect what bootstrap produces, set `revalidationKey: () => string` so eve knows when to rebuild the template (authored sandbox source and seed contents are already tracked for you).
|
|
167
|
-
- **`onSession({ use, ctx })`** is durable-session-scoped and runs once per session. Put per-session setup here, including network policy, resources, timeout, per-user credentials, and one-time markers. Because it runs inside the active runtime context, it can read `ctx.session` and derive the current principal without baking credentials into the template. Call `use(opts?)` to get a `SandboxSession`; `opts` flow to the backend's update path after create.
|
|
167
|
+
- **`onSession({ use, ctx })`** is durable-session-scoped and runs once per session (and again if a sandbox definition change replaces the session's sandbox). Put per-session setup here, including network policy, resources, timeout, per-user credentials, and one-time markers. Because it runs inside the active runtime context, it can read `ctx.session` and derive the current principal without baking credentials into the template. Call `use(opts?)` to get a `SandboxSession`; `opts` flow to the backend's update path after create.
|
|
168
168
|
|
|
169
169
|
If you require a network policy or other configuration for every session, configure it on the backend factory or in `onSession`; do not rely on bootstrap-only configuration.
|
|
170
170
|
|
|
@@ -185,6 +185,8 @@ export default defineSandbox({
|
|
|
185
185
|
|
|
186
186
|
Sessions are persistent, and how the underlying runtime idles out depends on the backend. On the Vercel backend, the VM times out after a period of inactivity (default 30 minutes); eve preserves the filesystem and resumes the sandbox on the next message as if nothing happened, even days later. The Docker backend keeps a long-lived container per durable session and persists `/workspace` across turns without that timeout, and the just-bash backend stores its virtual filesystem under `.eve/sandbox-cache/`. In every case, `/workspace` survives between turns for the same session.
|
|
187
187
|
|
|
188
|
+
Session sandboxes are keyed per durable session, not per deployment, so redeploying your app does not discard them. A session gets a replacement sandbox only when the sandbox definition itself changes — the authored sandbox source, workspace seed content, or `revalidationKey` — in which case the next turn starts from the rebuilt template and `onSession` runs again.
|
|
189
|
+
|
|
188
190
|
When the eve server stops, no sandbox compute outlives it. `eve dev` stops the sandboxes it started when the dev server closes, and a self-hosted production server stops every open sandbox on shutdown (`SIGTERM`/`SIGINT`). Session state persists across the stop — the next server start reattaches each durable session from its stopped container, VM, or snapshot. Custom `SandboxBackend` adapters participate through the handle's `shutdown()` method: stop the underlying compute, keeping the session reattachable from persisted state where the backend supports it.
|
|
189
191
|
|
|
190
192
|
## Network policy
|
package/docs/subagents.mdx
CHANGED
|
@@ -109,7 +109,7 @@ Because the name lives in the same runtime tool namespace as authored tools, a s
|
|
|
109
109
|
|
|
110
110
|
Do not rely on subagent delegation by itself as an approval boundary. Put sensitive tools behind `approval`, connection approval, route/session authorization, or other controls wherever those tools can be called.
|
|
111
111
|
|
|
112
|
-
Each delegated subagent spins up its own child session and stream. The parent stream carries
|
|
112
|
+
Each delegated subagent spins up its own child session and stream. The parent stream carries the control-plane events `subagent.called` and `subagent.completed`, plus interactive `input.requested`, `authorization.required`, and `authorization.completed` events proxied from descendants so the root channel can prompt the user. To follow the child's other progress, read `subagent.called.data.childSessionId` and subscribe at `GET /eve/v1/session/:childSessionId/stream`.
|
|
113
113
|
|
|
114
114
|
## When to split
|
|
115
115
|
|
package/package.json
CHANGED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import type { FetchFileResult } from "#channel/adapter.js";
|
|
2
|
-
import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js";
|
|
3
|
-
import { type ChannelCors, type ChannelCorsOptions } from "#channel/cors.js";
|
|
4
|
-
import type { TypedReceiveTarget } from "#channel/receive-target.js";
|
|
5
|
-
import type { SessionAuthContext } from "#channel/types.js";
|
|
6
|
-
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
7
|
-
import type { SessionContext } from "#public/definitions/callback-context.js";
|
|
8
|
-
import type { RouteDefinition, SendFn } from "#channel/routes.js";
|
|
9
|
-
import type { Session, SessionHandle } from "#channel/session.js";
|
|
10
|
-
declare const CHANNEL_METADATA_TYPE: unique symbol;
|
|
11
|
-
export type { Session, SessionHandle } from "#channel/session.js";
|
|
12
|
-
export type { ChannelCors, ChannelCorsOptions } from "#channel/cors.js";
|
|
13
|
-
export { GET, POST, PUT, PATCH, DELETE, WS } from "#channel/routes.js";
|
|
14
|
-
export type { HttpRouteDefinition, RouteDefinition, RouteHandlerArgs, SendFn, SendOptions, SendPayload, GetSessionFn, WebSocketMessage, WebSocketPeer, WebSocketRouteDefinition, WebSocketRouteHandler, WebSocketRouteHooks, WebSocketUpgradeRequest, WebSocketUpgradeResult, } from "#channel/routes.js";
|
|
15
|
-
type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, {
|
|
16
|
-
type: T;
|
|
17
|
-
}> extends {
|
|
18
|
-
data: infer D;
|
|
19
|
-
} ? D : undefined;
|
|
20
|
-
/**
|
|
21
|
-
* Session operations on the `channel` argument of every channel event handler.
|
|
22
|
-
*/
|
|
23
|
-
export interface ChannelSessionOps {
|
|
24
|
-
readonly continuationToken: string;
|
|
25
|
-
setContinuationToken(token: string): void;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Channel context passed to event handlers: `TCtx` intersected with
|
|
29
|
-
* {@link ChannelSessionOps}.
|
|
30
|
-
*/
|
|
31
|
-
export type ChannelContext<TCtx> = TCtx & ChannelSessionOps;
|
|
32
|
-
type ChannelEventHandler<T extends HandleMessageStreamEvent["type"], TCtx> = (data: EventData<T>, channel: ChannelContext<TCtx>, ctx: SessionContext) => void | Promise<void>;
|
|
33
|
-
type ChannelSessionFailedHandler<TCtx> = (data: EventData<"session.failed">, channel: ChannelContext<TCtx>) => void | Promise<void>;
|
|
34
|
-
/**
|
|
35
|
-
* Optional handlers keyed by session lifecycle event name. Each handler receives
|
|
36
|
-
* the event `data`, the {@link ChannelContext}, and a {@link SessionContext}
|
|
37
|
-
* `ctx`. The `session.failed` handler is the exception: it receives only `data`
|
|
38
|
-
* and the channel context, with no `ctx`.
|
|
39
|
-
*/
|
|
40
|
-
export interface ChannelEvents<TCtx = void> {
|
|
41
|
-
readonly "turn.started"?: ChannelEventHandler<"turn.started", TCtx>;
|
|
42
|
-
readonly "actions.requested"?: ChannelEventHandler<"actions.requested", TCtx>;
|
|
43
|
-
readonly "action.result"?: ChannelEventHandler<"action.result", TCtx>;
|
|
44
|
-
readonly "message.completed"?: ChannelEventHandler<"message.completed", TCtx>;
|
|
45
|
-
readonly "message.appended"?: ChannelEventHandler<"message.appended", TCtx>;
|
|
46
|
-
readonly "reasoning.appended"?: ChannelEventHandler<"reasoning.appended", TCtx>;
|
|
47
|
-
readonly "reasoning.completed"?: ChannelEventHandler<"reasoning.completed", TCtx>;
|
|
48
|
-
readonly "input.requested"?: ChannelEventHandler<"input.requested", TCtx>;
|
|
49
|
-
readonly "turn.failed"?: ChannelEventHandler<"turn.failed", TCtx>;
|
|
50
|
-
readonly "turn.completed"?: ChannelEventHandler<"turn.completed", TCtx>;
|
|
51
|
-
readonly "session.failed"?: ChannelSessionFailedHandler<TCtx>;
|
|
52
|
-
readonly "session.completed"?: ChannelEventHandler<"session.completed", TCtx>;
|
|
53
|
-
readonly "session.waiting"?: ChannelEventHandler<"session.waiting", TCtx>;
|
|
54
|
-
readonly "authorization.required"?: ChannelEventHandler<"authorization.required", TCtx>;
|
|
55
|
-
readonly "authorization.completed"?: ChannelEventHandler<"authorization.completed", TCtx>;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Input passed to a channel's `receive` callback when another channel or
|
|
59
|
-
* schedule proactively routes a message to it.
|
|
60
|
-
*/
|
|
61
|
-
export interface ReceiveInput<TReceiveTarget = Record<string, unknown>> {
|
|
62
|
-
readonly message: string;
|
|
63
|
-
readonly target: Readonly<TReceiveTarget>;
|
|
64
|
-
readonly auth: SessionAuthContext | null;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* The object passed to {@link defineChannel}. `routes` is required; `state`
|
|
68
|
-
* seeds durable adapter state, `context` builds the per-step `channel` argument
|
|
69
|
-
* for `events` and `deliver`, `events` handle session lifecycle, `receive`
|
|
70
|
-
* accepts cross-channel handoffs, `fetchFile` stages remote file URLs, and
|
|
71
|
-
* `metadata` projects observability data.
|
|
72
|
-
*
|
|
73
|
-
* Generics: `TState` (adapter state), `TCtx` (context factory return type),
|
|
74
|
-
* `TReceiveTarget` (cross-channel target shape), `TMetadata` (instrumentation
|
|
75
|
-
* projection).
|
|
76
|
-
*/
|
|
77
|
-
export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
|
|
78
|
-
readonly state?: TState;
|
|
79
|
-
/**
|
|
80
|
-
* CORS policy for this channel's HTTP routes. `true` enables H3/Nitro's
|
|
81
|
-
* permissive defaults (`origin`, methods, request headers, and exposed
|
|
82
|
-
* headers all `"*"`); `false` or omission leaves CORS untouched. Pass an
|
|
83
|
-
* object for a serializable subset of H3/Nitro CORS options.
|
|
84
|
-
*/
|
|
85
|
-
readonly cors?: ChannelCors;
|
|
86
|
-
/**
|
|
87
|
-
* Builds the per-step channel context handed to `events` and `deliver`.
|
|
88
|
-
* Receives the live {@link SessionHandle}, so a factory can close over it to
|
|
89
|
-
* register late-bound callbacks. eve writes state mutations made inside the
|
|
90
|
-
* returned context back through `adapter.state`.
|
|
91
|
-
*
|
|
92
|
-
* Return the channel-owned context (thread handles, API clients, etc.). The
|
|
93
|
-
* framework passes it as the `channel` argument to event handlers (with
|
|
94
|
-
* {@link ChannelSessionOps} injected) and passes {@link SessionContext} as a
|
|
95
|
-
* separate `ctx` argument.
|
|
96
|
-
*/
|
|
97
|
-
context?(state: NonNullable<TState>, session: SessionHandle): TCtx;
|
|
98
|
-
readonly routes: readonly RouteDefinition<TState>[];
|
|
99
|
-
receive?(input: ReceiveInput<TReceiveTarget>, args: {
|
|
100
|
-
send: SendFn<TState>;
|
|
101
|
-
}): Promise<Session>;
|
|
102
|
-
readonly events?: ChannelEvents<TCtx>;
|
|
103
|
-
/**
|
|
104
|
-
* Fetches bytes for a `URL` object encountered on a `FilePart.data` by the
|
|
105
|
-
* staging pipeline. Return `null` to pass the URL through to the model
|
|
106
|
-
* provider unchanged, or bytes / {@link FetchFileResult} to stage the file to
|
|
107
|
-
* the sandbox.
|
|
108
|
-
*/
|
|
109
|
-
readonly fetchFile?: (url: string) => Promise<Buffer | FetchFileResult | null>;
|
|
110
|
-
/**
|
|
111
|
-
* Channel-owned metadata exposed to instrumentation callbacks. This is the
|
|
112
|
-
* channel's public observability surface, not a dump of durable adapter state,
|
|
113
|
-
* so keep it small. Return an object of JSON primitives, arrays, and plain
|
|
114
|
-
* objects: eve omits `undefined` properties and drops projections containing
|
|
115
|
-
* values such as `Date` or `Map`.
|
|
116
|
-
*/
|
|
117
|
-
readonly metadata?: (state: NonNullable<TState>) => TMetadata;
|
|
118
|
-
/**
|
|
119
|
-
* Identifier of the adapter family this channel belongs to. Set by
|
|
120
|
-
* higher-level wrappers (e.g. `slackChannel` passes `"slack"`) so downstream
|
|
121
|
-
* consumers can render typed channel chips instead of bucketing everything
|
|
122
|
-
* under "unknown".
|
|
123
|
-
*
|
|
124
|
-
* Authors calling `defineChannel` directly do not need to set this; the
|
|
125
|
-
* framework defaults to `"http"` for stateless channels and `"defineChannel"`
|
|
126
|
-
* for stateful ones.
|
|
127
|
-
*/
|
|
128
|
-
readonly kindHint?: string;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Opaque channel value produced by {@link defineChannel} and exported from
|
|
132
|
-
* `agent/channels/<name>.ts`. Exposes the channel's routes, an optional
|
|
133
|
-
* `receive` hook, and (via a phantom property) its metadata shape. Unlike
|
|
134
|
-
* {@link ChannelDefinition} it has no `TCtx` parameter: the context type is
|
|
135
|
-
* internal to the definition.
|
|
136
|
-
*/
|
|
137
|
-
export interface Channel<TState = undefined, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> extends TypedReceiveTarget<TReceiveTarget> {
|
|
138
|
-
readonly __kind: typeof CHANNEL_SENTINEL;
|
|
139
|
-
readonly [CHANNEL_METADATA_TYPE]?: TMetadata;
|
|
140
|
-
readonly routes: readonly RouteDefinition<TState>[];
|
|
141
|
-
readonly cors?: ChannelCorsOptions;
|
|
142
|
-
readonly receive?: (input: ReceiveInput<TReceiveTarget>, args: {
|
|
143
|
-
send: SendFn<TState>;
|
|
144
|
-
}) => Promise<Session>;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Extracts the metadata projection type (`TMetadata`) from a {@link Channel}.
|
|
148
|
-
* Resolves to `Record<string, unknown>` when the value is not a Channel.
|
|
149
|
-
*/
|
|
150
|
-
export type InferChannelMetadata<TChannel> = TChannel extends Channel<any, any, infer TMetadata> ? TMetadata : Record<string, unknown>;
|
|
151
|
-
/**
|
|
152
|
-
* Builds a {@link Channel} from a {@link ChannelDefinition}. Returns a value
|
|
153
|
-
* placed at `agent/channels/<name>.ts`; the file path supplies the channel name
|
|
154
|
-
* (do not add a `name` field). `TCtx` (the context factory's return type) is
|
|
155
|
-
* internal to the definition and is not part of the returned Channel signature.
|
|
156
|
-
*/
|
|
157
|
-
export declare function defineChannel<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>>(definition: ChannelDefinition<TState, TCtx, TReceiveTarget, TMetadata>): Channel<TState, TReceiveTarget, TMetadata>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{CHANNEL_SENTINEL}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{normalizeChannelCors}from"#channel/cors.js";import{HTTP_ADAPTER_KIND}from"#channel/http.js";import{DELETE,GET,PATCH,POST,PUT,WS}from"#channel/routes.js";function defineChannel(t){let n=buildAdapter(t),i=normalizeChannelCors(t.cors);return{__kind:CHANNEL_SENTINEL,routes:t.routes,adapter:n,cors:i,receive:t.receive}}function buildAdapter(e){let r=e.state!=null,a=e.context!=null,o=e.fetchFile!==void 0,s=e.metadata,c=r||a||s!==void 0,l={},u=!1,d=[`turn.started`,`actions.requested`,`action.result`,`message.completed`,`message.appended`,`reasoning.appended`,`reasoning.completed`,`input.requested`,`turn.failed`,`turn.completed`,`session.failed`,`session.completed`,`session.waiting`,`authorization.required`,`authorization.completed`],f=e.events;for(let e of d){let t=f?.[e];t&&(u=!0,l[e]=(r,i)=>{let a={...i,continuationToken:i.session?.continuationToken??``,setContinuationToken:e=>i.session?.setContinuationToken(e)};return e===`session.failed`?t(r,a):t(r,a,buildCallbackContext())})}return!c&&!u&&!o?{kind:e.kindHint??HTTP_ADAPTER_KIND}:{kind:e.kindHint??`defineChannel`,state:r?{...e.state}:{},fetchFile:e.fetchFile,instrumentation:s===void 0?void 0:{metadata(e){return s(e)}},createAdapterContext(t){let n=t.state,r=t.session;return{...a?e.context(n,r):{},state:n,ctx:t.ctx,session:r}},deliver(e){return defaultDeliverResult(e)},...l}}export{DELETE,GET,PATCH,POST,PUT,WS,defineChannel};
|