eve 0.27.12 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/src/channel/adapter.d.ts +5 -5
- package/dist/src/channel/session.d.ts +2 -2
- package/dist/src/channel/types.d.ts +10 -6
- package/dist/src/chunks/{use-eve-agent-CsSQOKnp.js → use-eve-agent-CZkX_ZTT.js} +90 -1
- package/dist/src/chunks/{use-eve-agent-CWYe-vqE.js → use-eve-agent-hdPX68_i.js} +90 -1
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/integration-setup.js +1 -1
- package/dist/src/cli/commands/register-registry-commands.js +1 -1
- package/dist/src/cli/commands/registry-setup-command.d.ts +5 -3
- package/dist/src/cli/commands/registry-setup-command.js +1 -1
- package/dist/src/cli/commands/registry.d.ts +9 -3
- package/dist/src/cli/commands/registry.js +1 -1
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/subagent-pump.d.ts +8 -2
- package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
- package/dist/src/cli/invoke/result.d.ts +15 -0
- package/dist/src/cli/invoke/result.js +1 -1
- package/dist/src/client/eve-agent-store.d.ts +7 -4
- package/dist/src/client/eve-agent-store.js +1 -1
- package/dist/src/client/index.d.ts +3 -3
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/message-action-parts.js +1 -1
- package/dist/src/client/message-reducer-types.d.ts +5 -3
- package/dist/src/client/message-response.d.ts +4 -4
- package/dist/src/client/ndjson.d.ts +3 -3
- package/dist/src/client/open-stream.d.ts +2 -2
- package/dist/src/client/output-schema.d.ts +2 -2
- package/dist/src/client/reducer.d.ts +2 -2
- package/dist/src/client/session-utils.d.ts +5 -5
- package/dist/src/client/session.d.ts +2 -2
- package/dist/src/client/types.d.ts +2 -2
- package/dist/src/compiler/compile-from-memory.d.ts +1 -0
- package/dist/src/compiler/extension-compatibility.d.ts +8 -8
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.d.ts +2 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/context/dynamic-instruction-lifecycle.d.ts +2 -2
- package/dist/src/context/dynamic-model-lifecycle.d.ts +2 -2
- package/dist/src/context/dynamic-skill-lifecycle.d.ts +2 -2
- package/dist/src/context/dynamic-tool-lifecycle.d.ts +2 -2
- package/dist/src/context/hook-lifecycle.d.ts +2 -2
- package/dist/src/evals/assertions/run.d.ts +3 -3
- package/dist/src/evals/match.d.ts +4 -4
- package/dist/src/evals/runner/derive-run-facts.d.ts +2 -2
- package/dist/src/evals/session.d.ts +3 -3
- package/dist/src/evals/types.d.ts +12 -12
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/route-child-delivery.d.ts +4 -3
- package/dist/src/execution/route-child-delivery.js +1 -1
- package/dist/src/execution/session-delivery-hook.d.ts +1 -0
- package/dist/src/execution/session-delivery-hook.js +1 -1
- package/dist/src/execution/session-timeout-control.d.ts +9 -0
- package/dist/src/execution/session-timeout-control.js +1 -0
- package/dist/src/execution/session-timeout-steps.d.ts +13 -0
- package/dist/src/execution/session-timeout-steps.js +1 -0
- package/dist/src/execution/session-timeout-workflow.d.ts +6 -0
- package/dist/src/execution/session-timeout-workflow.js +1 -0
- package/dist/src/execution/session-timeout.d.ts +2 -0
- package/dist/src/execution/session-timeout.js +1 -0
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/subagent-event-proxy-step.js +1 -1
- package/dist/src/execution/subagent-hitl-proxy.d.ts +5 -1
- package/dist/src/execution/subagent-hitl-proxy.js +1 -1
- package/dist/src/execution/terminal-session-completion-step.d.ts +5 -0
- package/dist/src/execution/terminal-session-completion-step.js +1 -0
- package/dist/src/execution/terminal-session-failure-step.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.d.ts +1 -0
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +4 -0
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +5 -2
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/agent-otel-provider.js +1 -1
- package/dist/src/harness/ai-sdk-hook-bridge.js +1 -1
- package/dist/src/harness/input-extraction.js +1 -1
- package/dist/src/harness/input-request-class.d.ts +23 -0
- package/dist/src/harness/input-request-class.js +1 -0
- package/dist/src/harness/input-requests.d.ts +20 -9
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/instrumentation-lifecycle.d.ts +12 -1
- package/dist/src/harness/proxy-input-requests.d.ts +10 -4
- package/dist/src/harness/proxy-input-requests.js +1 -1
- package/dist/src/harness/session-limit-continuation.d.ts +0 -11
- package/dist/src/harness/session-limit-continuation.js +1 -1
- package/dist/src/harness/session-limit-enforcement.d.ts +3 -2
- package/dist/src/harness/session-limit-enforcement.js +1 -1
- package/dist/src/harness/session-token-limits.d.ts +41 -0
- package/dist/src/harness/session-token-limits.js +1 -0
- package/dist/src/harness/stale-input-responses.js +1 -1
- package/dist/src/harness/subagent-token-budget.d.ts +6 -4
- package/dist/src/harness/subagent-token-budget.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/turn-tag-state.d.ts +26 -17
- package/dist/src/harness/turn-tag-state.js +1 -1
- package/dist/src/harness/types.d.ts +4 -4
- package/dist/src/harness/workflow-lifecycle.d.ts +2 -2
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/core.js +1 -1
- package/dist/src/internal/node-esm-compat-banner.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-core-shim.d.ts +1 -1
- package/dist/src/internal/workflow-bundle/workflow-core-shim.js +1 -1
- package/dist/src/protocol/event-dedupe.d.ts +25 -0
- package/dist/src/protocol/event-dedupe.js +1 -0
- package/dist/src/protocol/event-id.d.ts +16 -0
- package/dist/src/protocol/event-id.js +1 -0
- package/dist/src/protocol/message.d.ts +39 -23
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/public/channels/discord/discordChannel.d.ts +3 -3
- package/dist/src/public/channels/github/githubChannel.d.ts +3 -3
- package/dist/src/public/channels/linear/defaults.js +4 -2
- package/dist/src/public/channels/linear/linearChannel.d.ts +3 -3
- package/dist/src/public/channels/slack/hitl.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +3 -3
- package/dist/src/public/channels/teams/hitl.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -3
- package/dist/src/public/channels/telegram/telegramChannel.d.ts +3 -3
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +3 -3
- package/dist/src/public/definitions/channel.d.ts +4 -4
- package/dist/src/public/definitions/hook.d.ts +2 -2
- package/dist/src/react/use-eve-agent.d.ts +3 -2
- package/dist/src/runtime/framework-tools/ask-question.js +1 -1
- package/dist/src/runtime/hooks/registry.d.ts +2 -2
- package/dist/src/runtime/input/types.d.ts +19 -4
- package/dist/src/runtime/input/types.js +1 -1
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/types.d.ts +2 -2
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
- package/dist/src/setup/scaffold/create/web-template.js +2 -2
- package/dist/src/shared/agent-definition.d.ts +12 -0
- package/dist/src/shared/dynamic-tool-definition.d.ts +2 -2
- package/dist/src/shared/ulid.d.ts +39 -0
- package/dist/src/shared/ulid.js +1 -0
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.d.ts +4 -4
- 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.d.ts +4 -4
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/agent-config.md +28 -16
- package/docs/channels/linear.mdx +4 -0
- package/docs/concepts/execution-model-and-durability.mdx +1 -1
- package/docs/concepts/sessions-runs-and-streaming.md +61 -0
- package/docs/extensions.md +3 -1
- package/docs/guides/client/streaming.mdx +9 -3
- package/docs/guides/frontend/overview.mdx +4 -2
- package/docs/guides/frontend/use-eve-agent-svelte.mdx +1 -1
- package/docs/guides/frontend/use-eve-agent-vue.mdx +10 -10
- package/docs/guides/hooks.md +40 -2
- package/docs/guides/instrumentation.md +4 -0
- package/docs/install-integrations.mdx +76 -1
- package/docs/reference/cli.md +3 -0
- package/docs/tools/human-in-the-loop.md +5 -0
- package/package.json +1 -1
|
@@ -3,13 +3,13 @@ import type { PublicToolInputSchema, PublicToolOutputSchema, ToolModelOutput } f
|
|
|
3
3
|
import type { Approval } from "#public/definitions/approval.js";
|
|
4
4
|
import type { ToolContext } from "#public/definitions/tool.js";
|
|
5
5
|
import type { SessionAuth } from "#context/keys.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { UnstampedMessageStreamEvent } from "#protocol/message.js";
|
|
7
7
|
/**
|
|
8
8
|
* Stream event types allowed for dynamic tool resolvers. Dispatch
|
|
9
9
|
* supports any event; this extract restricts the public surface until
|
|
10
10
|
* more events are validated.
|
|
11
11
|
*/
|
|
12
|
-
export type DynamicToolEventName = Extract<
|
|
12
|
+
export type DynamicToolEventName = Extract<UnstampedMessageStreamEvent["type"], "session.started" | "turn.started" | "step.started">;
|
|
13
13
|
export declare const ALLOWED_DYNAMIC_TOOL_EVENTS: ReadonlySet<string>;
|
|
14
14
|
/**
|
|
15
15
|
* Instructions and skills are restricted to session/turn boundaries.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ULID-compatible generation, vendored rather than taken from npm: the
|
|
3
|
+
* `ulid` package's Node build hard-imports `node:crypto`, and this module is
|
|
4
|
+
* bundled into browser clients, the Nitro server, and the workflow step
|
|
5
|
+
* sandbox. `ulid.test.ts` pins the encoding against the reference
|
|
6
|
+
* implementation's golden vectors.
|
|
7
|
+
*/
|
|
8
|
+
/** Character count of a ULID: a 10-char timestamp then a 16-char random tail. */
|
|
9
|
+
export declare const ULID_LENGTH: number;
|
|
10
|
+
/** Mints one ULID. See {@link createUlidFactory}. */
|
|
11
|
+
export type UlidFactory = () => string;
|
|
12
|
+
/**
|
|
13
|
+
* Creates an independent ULID generator with its own monotonic state.
|
|
14
|
+
*
|
|
15
|
+
* Prefer {@link createUlid} unless a caller needs a sequence that unrelated
|
|
16
|
+
* code cannot perturb. Ids sort in the order one generator produced them:
|
|
17
|
+
* those minted within a millisecond increment the random tail, and a
|
|
18
|
+
* backwards clock pins to the last millisecond observed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createUlidFactory(): UlidFactory;
|
|
21
|
+
/**
|
|
22
|
+
* Mints a ULID from the process-wide generator: a 48-bit millisecond
|
|
23
|
+
* timestamp then 80 bits of randomness, in Crockford base32.
|
|
24
|
+
*
|
|
25
|
+
* Ids lead with their timestamp, so they are broadly time-ordered. Ordering
|
|
26
|
+
* holds within one process only — separate processes have independent clocks
|
|
27
|
+
* and random tails — so a ULID is not a lossless pagination cursor.
|
|
28
|
+
*
|
|
29
|
+
* Throws when the clock is outside the 48-bit timestamp range or Web Crypto
|
|
30
|
+
* is unavailable rather than weakening the randomness.
|
|
31
|
+
*/
|
|
32
|
+
export declare const createUlid: UlidFactory;
|
|
33
|
+
/**
|
|
34
|
+
* Returns true when `value` is shaped like a ULID: {@link ULID_LENGTH}
|
|
35
|
+
* characters drawn from the Crockford base32 alphabet.
|
|
36
|
+
*
|
|
37
|
+
* Shape-only — this does not prove the value was minted here.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isUlid(value: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const ENCODING=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`,TIME_MAX=2**48-1,ULID_LENGTH=26;function createUlidFactory(){let e=-1,n=new Uint8Array(10);return function(){let r=Date.now();if(!Number.isInteger(r)||r<0||r>TIME_MAX)throw Error(`Cannot mint a ULID: timestamp must be an integer from 0 to ${TIME_MAX}.`);if(r>e)e=r,randomFill(n);else if(!incrementRandom(n)){if(e===TIME_MAX)throw Error(`Cannot mint a ULID: random component overflowed at the maximum timestamp.`);e+=1,randomFill(n)}return`${encodeTime(e)}${encodeRandom(n)}`}}const createUlid=createUlidFactory();function isUlid(t){if(t.length!==26||ENCODING.indexOf(t[0]??``)>7)return!1;for(let n of t)if(!ENCODING.includes(n))return!1;return!0}function randomFill(e){let t=globalThis.crypto;if(typeof t?.getRandomValues!=`function`)throw Error(`Cannot mint a ULID: globalThis.crypto.getRandomValues is unavailable.`);t.getRandomValues(e)}function encodeTime(t){let n=t,r=``;for(let t=0;t<10;t+=1)r=ENCODING[n%32]+r,n=Math.floor(n/32);return r}function encodeRandom(t){let n=0,r=0,i=``;for(let a of t){for(n=n<<8|a,r+=8;r>=5;)r-=5,i+=ENCODING[n>>>r&31];n&=(1<<r)-1}return i}function incrementRandom(e){for(let t=e.length-1;t>=0;--t){let n=e[t]??0;if(n<255)return e[t]=n+1,e.fill(0,t+1),!0}return!1}export{ULID_LENGTH,createUlid,createUlidFactory,isUlid};
|
package/dist/src/svelte/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { type EveMessageData } from "#client/message-reducer.js";
|
|
|
3
3
|
import type { EveAgentReducer } from "#client/reducer.js";
|
|
4
4
|
import type { ClientSession } from "#client/session.js";
|
|
5
5
|
import type { ClientAuth, HeadersValue, SendTurnPayload, SessionState } from "#client/types.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { MessageStreamEvent } from "#protocol/message.js";
|
|
7
7
|
export type { PrepareSend };
|
|
8
8
|
/**
|
|
9
9
|
* Session lifecycle phase: `"ready"` (idle), `"submitted"` (request sent,
|
|
@@ -30,7 +30,7 @@ export interface UseEveAgentReturn<TData> {
|
|
|
30
30
|
/** Last transport-level error, or `undefined` when healthy. */
|
|
31
31
|
readonly error: Error | undefined;
|
|
32
32
|
/** Raw server events received during this session (authoritative stream). */
|
|
33
|
-
readonly events: readonly
|
|
33
|
+
readonly events: readonly MessageStreamEvent[];
|
|
34
34
|
/** Clear all state and start a new session. */
|
|
35
35
|
readonly reset: () => void;
|
|
36
36
|
/** Send a turn with full structured input (message, attachments, input responses). */
|
|
@@ -76,8 +76,8 @@ export interface UseEveAgentOptions<TData> extends EveAgentStoreCallbacks<TData>
|
|
|
76
76
|
* @default ""
|
|
77
77
|
*/
|
|
78
78
|
readonly host?: string;
|
|
79
|
-
/**
|
|
80
|
-
readonly initialEvents?: readonly
|
|
79
|
+
/** Ordered prefix of the session stream used to rehydrate projected state. */
|
|
80
|
+
readonly initialEvents?: readonly MessageStreamEvent[];
|
|
81
81
|
/** Seed session identity and stream cursor for resuming a prior conversation. */
|
|
82
82
|
readonly initialSession?: SessionState;
|
|
83
83
|
/**
|
package/dist/src/vue/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { type EveAgentStoreCallbacks, type EveAgentStoreSnapshot, type EveAgentS
|
|
|
3
3
|
import type { EveAgentReducer } from "#client/reducer.js";
|
|
4
4
|
import type { ClientSession } from "#client/session.js";
|
|
5
5
|
import { type EveMessageData } from "#client/message-reducer.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { MessageStreamEvent } from "#protocol/message.js";
|
|
7
7
|
import type { ClientAuth, HeadersValue, SendTurnPayload, SessionState } from "#client/types.js";
|
|
8
8
|
export type { PrepareSend };
|
|
9
9
|
/**
|
|
@@ -29,7 +29,7 @@ export interface UseEveAgentReturn<TData> {
|
|
|
29
29
|
/** Last transport-level error, or `undefined` when healthy. */
|
|
30
30
|
readonly error: ComputedRef<Error | undefined>;
|
|
31
31
|
/** Raw server events from this session (authoritative stream). */
|
|
32
|
-
readonly events: ComputedRef<readonly
|
|
32
|
+
readonly events: ComputedRef<readonly MessageStreamEvent[]>;
|
|
33
33
|
/** Clear all state and start a new session. */
|
|
34
34
|
readonly reset: () => void;
|
|
35
35
|
/** Send a turn with full structured input (message, attachments, input responses). */
|
|
@@ -75,8 +75,8 @@ export interface UseEveAgentOptions<TData> extends EveAgentStoreCallbacks<TData>
|
|
|
75
75
|
* @default ""
|
|
76
76
|
*/
|
|
77
77
|
readonly host?: string;
|
|
78
|
-
/**
|
|
79
|
-
readonly initialEvents?: readonly
|
|
78
|
+
/** Ordered prefix of the session stream used to rehydrate projected state. */
|
|
79
|
+
readonly initialEvents?: readonly MessageStreamEvent[];
|
|
80
80
|
/** Prior session cursor to resume from on mount. */
|
|
81
81
|
readonly initialSession?: SessionState;
|
|
82
82
|
/**
|
package/docs/agent-config.md
CHANGED
|
@@ -131,10 +131,18 @@ export default defineAgent({
|
|
|
131
131
|
limits: {
|
|
132
132
|
maxInputTokensPerSession: 200_000,
|
|
133
133
|
maxOutputTokensPerSession: 20_000,
|
|
134
|
+
sessionTimeoutMs: 7 * 24 * 60 * 60 * 1_000,
|
|
134
135
|
},
|
|
135
136
|
});
|
|
136
137
|
```
|
|
137
138
|
|
|
139
|
+
`sessionTimeoutMs` sets an absolute lifetime for every session, including
|
|
140
|
+
delegated sessions. It defaults to 30 days, starts at creation, and survives
|
|
141
|
+
restarts and redeployments. At the deadline, eve lets an active turn settle,
|
|
142
|
+
then emits `session.completed` and releases the continuation; the next
|
|
143
|
+
qualifying channel message starts fresh. Set it to `false` to disable the
|
|
144
|
+
timeout. Expiration does not delete stored session data.
|
|
145
|
+
|
|
138
146
|
Input and output budgets are checked independently. The model call that crosses
|
|
139
147
|
either limit is allowed to finish because providers only report exact token
|
|
140
148
|
usage after a call completes. Before the next model call, eve pauses the
|
|
@@ -147,12 +155,14 @@ still over budget, the next message re-raises the prompt. Declining a
|
|
|
147
155
|
delegated child's prompt cancels the root turn, which cascades to the whole
|
|
148
156
|
delegation tree — the delegating parent never receives an error result it
|
|
149
157
|
could retry against a fresh quota share. A reply that answers neither option
|
|
150
|
-
|
|
151
|
-
budget is granted.
|
|
158
|
+
is queued while the existing prompt stays pending; eve does not raise another
|
|
159
|
+
copy. The reply is processed once the budget is granted.
|
|
152
160
|
|
|
153
161
|
Sessions that cannot reach a human — task-mode runs such as schedules and
|
|
154
162
|
subagents without input proxying — skip the prompt and fail the next model
|
|
155
|
-
call with `SESSION_TOKEN_LIMIT_REACHED`.
|
|
163
|
+
call with `SESSION_TOKEN_LIMIT_REACHED`. A delegated task with no inherited
|
|
164
|
+
quota also fails instead of raising a continuation prompt that could only
|
|
165
|
+
grant another zero-token window.
|
|
156
166
|
|
|
157
167
|
When `maxInputTokensPerSession` is omitted, root sessions apply a default
|
|
158
168
|
input budget of `40_000_000` provider-reported input tokens.
|
|
@@ -161,11 +171,13 @@ to `false` uncaps that axis — the session never stops on it.
|
|
|
161
171
|
|
|
162
172
|
Delegated subagent sessions have no fixed default. Each child receives a
|
|
163
173
|
share of the delegating parent's remaining quota at dispatch time — the
|
|
164
|
-
remainder
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
remainder in the current budget window split evenly across the batch's local
|
|
175
|
+
subagent calls — and a completed child's usage counts against the parent's
|
|
176
|
+
quota, so a delegation tree can never outspend the budget configured at its
|
|
177
|
+
root. Approving a continuation opens a fresh parent window for later child
|
|
178
|
+
grants without erasing lifetime usage. An authored child limit applies only
|
|
179
|
+
when it is tighter than the parent's grant; an uncapped parent delegates
|
|
180
|
+
uncapped children.
|
|
169
181
|
|
|
170
182
|
## Workflow world
|
|
171
183
|
|
|
@@ -208,14 +220,14 @@ installed package must stay external in hosted output, list it in
|
|
|
208
220
|
|
|
209
221
|
`defineAgent` takes a few more fields, all optional. For the exported types, see the [TypeScript API](./reference/typescript-api).
|
|
210
222
|
|
|
211
|
-
| Field | Type | Default | Description
|
|
212
|
-
| -------------- | --------------------------------------- | ---------------- |
|
|
213
|
-
| `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls.
|
|
214
|
-
| `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call.
|
|
215
|
-
| `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits.
|
|
216
|
-
| `experimental` | `{ workflow?: { world?: string } }` | unset | Opt-in settings that can change or disappear in any release. Treat them as unstable. `workflow.world` selects the Workflow world package backing session state, queues, hooks, and streams on the root agent.
|
|
217
|
-
| `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for task-mode runs (a subagent, schedule, or remote job). Interactive conversation turns ignore it unless the client supplies a per-message schema.
|
|
218
|
-
| `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output.
|
|
223
|
+
| Field | Type | Default | Description |
|
|
224
|
+
| -------------- | --------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
225
|
+
| `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls. |
|
|
226
|
+
| `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
|
|
227
|
+
| `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. Sessions complete after 30 days by default; token-limit defaults and inheritance are described above. Set a limit to `false` to disable it. |
|
|
228
|
+
| `experimental` | `{ workflow?: { world?: string } }` | unset | Opt-in settings that can change or disappear in any release. Treat them as unstable. `workflow.world` selects the Workflow world package backing session state, queues, hooks, and streams on the root agent. |
|
|
229
|
+
| `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for task-mode runs (a subagent, schedule, or remote job). Interactive conversation turns ignore it unless the client supplies a per-message schema. |
|
|
230
|
+
| `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output. |
|
|
219
231
|
|
|
220
232
|
`externalDependencies` is a packaging control only. It keeps selected packages as runtime dependencies in the hosted output; it does not authorize, configure, or review any third-party service those packages may call.
|
|
221
233
|
|
package/docs/channels/linear.mdx
CHANGED
|
@@ -82,6 +82,10 @@ Turn start posts an ephemeral `thought`, tool calls post ephemeral `action` acti
|
|
|
82
82
|
|
|
83
83
|
Human-in-the-loop (HITL) input requests render as Linear `elicitation` activities. When the user replies to the Agent Session, the channel resolves that prompt back to the pending eve input request and resumes with `inputResponses`.
|
|
84
84
|
|
|
85
|
+
### Connection authorization
|
|
86
|
+
|
|
87
|
+
When a user-scoped connection needs authorization, the default channel posts Linear's native `auth` elicitation with the provider's sign-in URL, targeted to the Linear user who started the session. URL-less device flows render their instructions and user code as a plain elicitation. After authorization finishes, the channel posts a thought with the outcome; successful authorization indicates that the parked turn is resuming.
|
|
88
|
+
|
|
85
89
|
### Proactive sessions
|
|
86
90
|
|
|
87
91
|
Start a session without an inbound webhook with `receive(linear, { target })`. See [Proactive sessions](#proactive-sessions) below for the target shape and examples.
|
|
@@ -56,7 +56,7 @@ Provider keys, tool secrets, and MCP, OpenAPI, and connection credentials stay i
|
|
|
56
56
|
|
|
57
57
|
## Resuming after a crash
|
|
58
58
|
|
|
59
|
-
Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn. Completed steps never re-run; eve replays the recorded result. A step interrupted mid-execution re-runs, so make non-idempotent side effects like charges or emails idempotent, or gate them with approval.
|
|
59
|
+
Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn. Completed steps never re-run; eve replays the recorded result. A step interrupted mid-execution re-runs, so make non-idempotent side effects like charges or emails idempotent, or gate them with approval. Whatever that step already wrote to the session stream stays there, and the re-run emits its events again under new ids, so a stream consumer sees both attempts — see [the event envelope](./sessions-runs-and-streaming#the-event-envelope).
|
|
60
60
|
|
|
61
61
|
There's nothing to configure. eve owns the workflow lifecycle, and sessions are durable by default.
|
|
62
62
|
|
|
@@ -14,6 +14,12 @@ Two handles do two jobs, and mixing them up is the most common mistake. One hand
|
|
|
14
14
|
|
|
15
15
|
A session has one active continuation at a time: each follow-up uses the current `continuationToken`, and a stale one is rejected.
|
|
16
16
|
|
|
17
|
+
Sessions last 30 days by default; configure `limits.sessionTimeoutMs` in
|
|
18
|
+
`agent.ts`, or set it to `false` to disable the deadline. At expiration, eve
|
|
19
|
+
lets an active turn settle, emits `session.completed`, and releases the
|
|
20
|
+
continuation so the next qualifying channel message starts fresh. Stored
|
|
21
|
+
session data is not deleted. See [Agent config](../agent-config#runtime-limits).
|
|
22
|
+
|
|
17
23
|
React, Vue, and Svelte apps reach for [`useEveAgent()`](../guides/frontend/overview) instead of calling these routes by hand. Next.js and Nuxt apps can proxy them to the eve runtime from the same origin.
|
|
18
24
|
|
|
19
25
|
## Start a session
|
|
@@ -73,6 +79,59 @@ A delegated subagent publishes progress on its own child-session stream. The par
|
|
|
73
79
|
|
|
74
80
|
`step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally — whatever the turn streamed before cancellation stays on the stream, while durable history keeps only what had already settled. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`).
|
|
75
81
|
|
|
82
|
+
## The event envelope
|
|
83
|
+
|
|
84
|
+
Alongside `type` and `data`, every event carries a `meta` envelope:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"type": "message.completed",
|
|
89
|
+
"data": {
|
|
90
|
+
"message": "Sunny and 72°F.",
|
|
91
|
+
"finishReason": "stop",
|
|
92
|
+
"sequence": 0,
|
|
93
|
+
"stepIndex": 0,
|
|
94
|
+
"turnId": "turn_0"
|
|
95
|
+
},
|
|
96
|
+
"meta": { "id": "evt_01KYJBZA88B4M9XN3RTC5FDGHJ", "at": "2026-07-27T18:04:11.912Z" }
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- **`meta.id`** uniquely identifies the event. It is an `evt_`-prefixed [ULID](https://github.com/ulid/spec): a millisecond timestamp followed by random bits, so ids are broadly time-ordered.
|
|
101
|
+
- **`meta.at`** is the ISO-8601 time the event was emitted.
|
|
102
|
+
|
|
103
|
+
`meta.id` is stable. eve mints it once, when the event is written to the durable stream, and stores it with the event. Reconnecting from a cursor, rewinding to `startIndex=0`, or replaying a finished session all return the same id for the same event.
|
|
104
|
+
|
|
105
|
+
`meta.at` has always been there; `meta.id` arrived in stream version 20. Events written by an earlier version are stored with the envelope but no id inside it, so rewinding into the part of a session that ran before you upgraded yields events whose `meta.id` is absent, even though the type says it is always a string. eve passes those events through rather than dropping them, and they cannot be deduplicated. The exposure ends when the sessions that predate your upgrade do.
|
|
106
|
+
|
|
107
|
+
That makes it the key for ingesting a stream into a database without duplicating rows when you re-read it:
|
|
108
|
+
|
|
109
|
+
```sql
|
|
110
|
+
insert into agent_events (id, session_id, type, data, emitted_at)
|
|
111
|
+
values ($1, $2, $3, $4, $5)
|
|
112
|
+
on conflict (id) do nothing;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Because ids lead with a timestamp, a `primary key (id)` stays roughly append-ordered and keeps inserts clustered.
|
|
116
|
+
|
|
117
|
+
**What the id covers.** Reconnecting is not the only way the same event reaches you twice. Keying on `meta.id` is what makes ingestion correct in all of these:
|
|
118
|
+
|
|
119
|
+
- Reconnecting mid-turn and overlapping events you already handled.
|
|
120
|
+
- Rewinding with `startIndex=0`, or reading back from the tail with a negative `startIndex`.
|
|
121
|
+
- Restoring a saved event log that overlaps the prefix the live stream replays.
|
|
122
|
+
|
|
123
|
+
**What it does not cover: a retried step re-emits under new ids.** eve runs each durable step up to four times. If a step is interrupted partway — a crash, a timeout, a model error it retries through — whatever it already wrote stays on the stream, and the new attempt emits its own events with their own ids. Both attempts carry the same `turnId`, `stepIndex`, and `sequence`, because the retry restores that state from the step's input, but they are distinct events and no field records which attempt finished.
|
|
124
|
+
|
|
125
|
+
Replaying a _completed_ step is a different thing and emits nothing at all: eve serves the recorded result from its journal without re-running the body. Crash recovery, redeploys, and resuming a parked turn therefore add nothing to the stream. Only an interrupted step re-runs.
|
|
126
|
+
|
|
127
|
+
Three more things to know:
|
|
128
|
+
|
|
129
|
+
- **Ids are time-ordered, not a total order.** The turn steps of one session can run in different processes, each generating ids from its own clock and its own random bits. Two events emitted in the same millisecond by different steps may sort either way, and clock skew between machines can invert neighbours. Record your own ingestion sequence, or read the stream in order and store the index, when you need an exact ordering to page against — do not use `where id > $cursor` as a lossless cursor. The stream itself is authoritative: `startIndex` is an absolute event count.
|
|
130
|
+
- **Ids identify events, not intent.** Two events with identical payloads — the `step.failed` → `turn.failed` → `session.failed` cascade, or two identical text deltas in one step — are distinct events with distinct ids. Deduplicate on `meta.id` only; matching on content would drop real data.
|
|
131
|
+
- **A subagent's event is re-emitted, not shared.** When a parent forwards a child's event onto its own stream, the parent's copy is a separate event with its own id. Correlate the two streams through `subagent.called.data.childSessionId`.
|
|
132
|
+
|
|
133
|
+
Authored [hooks](../guides/hooks) receive the same envelope, but observe each event as it is emitted rather than as it is read — so a hook sees a retry as new events, and `meta.id` is a key for a stored row rather than a retry guard. Two things a hook does not have to defend against: a turn that parks for human input resumes without re-emitting anything it already sent, and a retried turn dispatch cannot double-stream a turn, because only one turn run can claim a session's turn inbox.
|
|
134
|
+
|
|
76
135
|
## Send a follow-up message
|
|
77
136
|
|
|
78
137
|
Once the session is waiting (you'll see `session.waiting`), POST your follow-up to the session endpoint with `event.data.continuationToken`:
|
|
@@ -112,6 +171,8 @@ Custom channel routes request the same cancellation without knowing the session
|
|
|
112
171
|
|
|
113
172
|
The stream is durable. Every event is recorded before a step completes, so consumers can reconnect from their cursor when an HTTP connection ends. A nonnegative `startIndex` is an absolute event count: use it to pick up where you dropped off or pass `0` to rewind to the start.
|
|
114
173
|
|
|
174
|
+
If a reconnect overlaps events you already handled, [`meta.id`](#the-event-envelope) identifies the duplicates: it is unchanged across reconnects and rewinds, so a consumer keyed on it can replay safely.
|
|
175
|
+
|
|
115
176
|
```bash
|
|
116
177
|
curl "http://127.0.0.1:2000/eve/v1/session/<sessionId>/stream?startIndex=<count>"
|
|
117
178
|
```
|
package/docs/extensions.md
CHANGED
|
@@ -3,7 +3,9 @@ title: "Extensions"
|
|
|
3
3
|
description: "Package reusable eve capabilities and mount them from npm or a monorepo workspace."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Extensions package eve tools, connections, skills, instruction fragments, and hooks. An author builds an extension package; each agent that uses it declares the package as a dependency and mounts it. The package can be published to a registry or kept private inside a monorepo workspace.
|
|
6
|
+
Extensions package eve tools, connections, skills, instruction fragments, and hooks. An author builds an extension package; each agent that uses it declares the package as a dependency and mounts it. The package can be published to a package registry or kept private inside a monorepo workspace.
|
|
7
|
+
|
|
8
|
+
Ready-made extensions can also be distributed through an eve integration registry. See [Install Integrations](./install-integrations) to discover and add one with `eve add`; this page explains how extension packages are authored, mounted, configured, and overridden.
|
|
7
9
|
|
|
8
10
|
This enables sharing many different capability sets. A browser extension might include several tools for navigating a site. A memory extension could use hooks to capture context and tools to recall it. A self-improving extension could pair hooks with dynamic instructions.
|
|
9
11
|
|
|
@@ -60,13 +60,17 @@ for await (const event of response) {
|
|
|
60
60
|
|
|
61
61
|
## Handle event types
|
|
62
62
|
|
|
63
|
-
Import event types from `eve/client` when you want exhaustiveness or helpers
|
|
63
|
+
Import event types from `eve/client` when you want exhaustiveness or helpers. Events read from a stream are `MessageStreamEvent`: the same union, with the `meta` envelope guaranteed present.
|
|
64
|
+
|
|
65
|
+
`HandleMessageStreamEvent` remains available as a deprecated alias, so existing type imports continue to compile.
|
|
64
66
|
|
|
65
67
|
```ts
|
|
66
|
-
import type {
|
|
68
|
+
import type { MessageStreamEvent } from "eve/client";
|
|
67
69
|
import { isCurrentTurnBoundaryEvent } from "eve/client";
|
|
68
70
|
|
|
69
|
-
function handleEvent(event:
|
|
71
|
+
function handleEvent(event: MessageStreamEvent) {
|
|
72
|
+
console.log(event.meta.id, event.meta.at);
|
|
73
|
+
|
|
70
74
|
if (isCurrentTurnBoundaryEvent(event)) {
|
|
71
75
|
console.log("turn settled:", event.type);
|
|
72
76
|
}
|
|
@@ -105,6 +109,8 @@ If you support refresh while an authorization prompt is pending, keep the sessio
|
|
|
105
109
|
|
|
106
110
|
HTTP connections can end before a run does. The client reconnects from the number of events already consumed, so long turns continue without replaying events. It stops at a turn boundary, when aborted, or when the stream can no longer make progress.
|
|
107
111
|
|
|
112
|
+
If your consumer persists events, key on `event.meta.id`. It is stable across reconnects and rewinds, so an overlapping replay is safe to ingest twice. See [the event envelope](../../concepts/sessions-runs-and-streaming#the-event-envelope).
|
|
113
|
+
|
|
108
114
|
Set `streamReconnectPolicy: { reconnect: false }` when a relay or proxy owns the cursor and reconnection policy. This makes a single stream GET attempt and returns when that connection ends; it does not stop the server-side turn:
|
|
109
115
|
|
|
110
116
|
```ts
|
|
@@ -226,10 +226,10 @@ const agent = useEveAgent({ reducer: toolCounter });
|
|
|
226
226
|
The browser conversation lives durably on the server. Persist both the rendered event log and the `session` cursor to pick it back up after a reload:
|
|
227
227
|
|
|
228
228
|
```tsx
|
|
229
|
-
import type {
|
|
229
|
+
import type { SessionState, MessageStreamEvent } from "eve/client";
|
|
230
230
|
|
|
231
231
|
type SavedEveChat = {
|
|
232
|
-
events?: readonly
|
|
232
|
+
events?: readonly MessageStreamEvent[];
|
|
233
233
|
session?: SessionState;
|
|
234
234
|
};
|
|
235
235
|
|
|
@@ -255,6 +255,8 @@ const agent = useEveAgent({
|
|
|
255
255
|
|
|
256
256
|
Store the full `session` object (`sessionId`, `continuationToken`, `streamIndex`), not a single field. The session cursor lets eve continue the durable conversation; the event log lets your UI render historical messages without replaying the whole stream. A database-backed chat app should usually persist stream events as they arrive with `onEvent` and then save a final snapshot in `onFinish`.
|
|
257
257
|
|
|
258
|
+
`initialEvents` must be an ordered prefix of the same session's stream, but its endpoint does not have to line up exactly with where the stream resumes. Every event carries a stable [`meta.id`](/docs/concepts/sessions-runs-and-streaming#the-event-envelope), and the store drops any event whose id it has already applied — so a saved log that overlaps the replayed prefix renders once, and `onEvent` only fires for events your UI has not seen.
|
|
259
|
+
|
|
258
260
|
For multiple chat threads, keep one saved event log and session cursor per thread. `agent`, `host`, `reducer`, `session`, `initialEvents`, `initialSession`, `auth`, `headers`, and `optimistic` are read when the hook creates its store, so remount the chat component when switching threads, for example with `key={chat.id}`.
|
|
259
261
|
|
|
260
262
|
If the user can refresh or navigate immediately after pressing send, create your app-level chat row and store the pending user message before calling `send()`. After the request starts, persist the session state as soon as it contains a `sessionId`, then reconnect an interrupted in-flight turn with `session.stream({ startIndex: savedEvents.length })` from the lower-level client.
|
|
@@ -28,7 +28,7 @@ Import from `eve/svelte` and read the reactive getters directly. No `$` prefix:
|
|
|
28
28
|
| `data` | `TData` | Projected state. With the default reducer, `EveMessageData` (`messages`). |
|
|
29
29
|
| `status` | `UseEveAgentStatus` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. |
|
|
30
30
|
| `error` | `Error \| undefined` | Last transport-level error. |
|
|
31
|
-
| `events` | `readonly
|
|
31
|
+
| `events` | `readonly MessageStreamEvent[]` | Raw server events for this session. |
|
|
32
32
|
| `session` | `SessionState` | Snapshot of session state. |
|
|
33
33
|
| `send` | `(input: SendTurnPayload) => Promise<void>` | Send text or a full turn (multi-part, attachments, HITL responses). |
|
|
34
34
|
| `stop` | `() => void` | Abort the client's in-flight stream. |
|
|
@@ -25,16 +25,16 @@ const { data } = useEveAgent();
|
|
|
25
25
|
|
|
26
26
|
## What it returns
|
|
27
27
|
|
|
28
|
-
| Property | Type
|
|
29
|
-
| --------- |
|
|
30
|
-
| `data` | `ComputedRef<TData>`
|
|
31
|
-
| `status` | `ComputedRef<UseEveAgentStatus>`
|
|
32
|
-
| `error` | `ComputedRef<Error \| undefined>`
|
|
33
|
-
| `events` | `ComputedRef<readonly
|
|
34
|
-
| `session` | `ComputedRef<SessionState>`
|
|
35
|
-
| `send` | `(input: SendTurnPayload) => Promise<void>`
|
|
36
|
-
| `stop` | `() => void`
|
|
37
|
-
| `reset` | `() => void`
|
|
28
|
+
| Property | Type | Description |
|
|
29
|
+
| --------- | -------------------------------------------- | ------------------------------------------------------------------------- |
|
|
30
|
+
| `data` | `ComputedRef<TData>` | Projected state. With the default reducer, `EveMessageData` (`messages`). |
|
|
31
|
+
| `status` | `ComputedRef<UseEveAgentStatus>` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. |
|
|
32
|
+
| `error` | `ComputedRef<Error \| undefined>` | Last transport-level error. |
|
|
33
|
+
| `events` | `ComputedRef<readonly MessageStreamEvent[]>` | Raw server events for this session. |
|
|
34
|
+
| `session` | `ComputedRef<SessionState>` | Snapshot of session state. |
|
|
35
|
+
| `send` | `(input: SendTurnPayload) => Promise<void>` | Send text or a full turn (multi-part, attachments, HITL responses). |
|
|
36
|
+
| `stop` | `() => void` | Abort the client's in-flight stream. |
|
|
37
|
+
| `reset` | `() => void` | Clear state and start a new session. |
|
|
38
38
|
|
|
39
39
|
The first five are `ComputedRef`s; the rest are methods. Destructure whatever you need, since refs keep their reactivity through destructuring. Read them with `.value` in `<script>`, and unwrapped in `<template>`.
|
|
40
40
|
|
package/docs/guides/hooks.md
CHANGED
|
@@ -80,15 +80,53 @@ import { search } from "@acme/crm/tools";
|
|
|
80
80
|
const crmSearch = toolResultFrom(event.data.result, search); // typed; matches crm__search
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
### Persist events to your own database
|
|
84
|
+
|
|
85
|
+
Every event carries a `meta` envelope with `meta.id`, a unique, sortable identifier for that event. It makes a natural primary key for an events table:
|
|
86
|
+
|
|
87
|
+
```ts title="agent/hooks/persist.ts"
|
|
88
|
+
import { defineHook } from "eve/hooks";
|
|
89
|
+
|
|
90
|
+
export default defineHook({
|
|
91
|
+
events: {
|
|
92
|
+
async "*"(event, ctx) {
|
|
93
|
+
await db.query(
|
|
94
|
+
`insert into agent_events (id, session_id, type, data, emitted_at)
|
|
95
|
+
values ($1, $2, $3, $4, $5)
|
|
96
|
+
on conflict (id) do nothing`,
|
|
97
|
+
[
|
|
98
|
+
event.meta.id,
|
|
99
|
+
ctx.session.id,
|
|
100
|
+
event.type,
|
|
101
|
+
"data" in event ? event.data : null,
|
|
102
|
+
event.meta.at,
|
|
103
|
+
],
|
|
104
|
+
);
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`meta.id` is stable for the life of the persisted event, so a consumer that re-reads the stream can ingest the same event twice safely. It is not a retry guard for the hook itself: if a step is interrupted and re-runs, the turn re-emits its events as _new_ events with new ids, and your hook runs again for each one.
|
|
111
|
+
|
|
112
|
+
What to key on instead depends on what you are protecting:
|
|
113
|
+
|
|
114
|
+
- **A side effect that must happen once per turn or step** — a charge, an email, a ticket — keys well on the coordinates in `event.data` (`turnId`, `stepIndex`, `sequence`). A retry restores those from the step's input, so the second attempt computes the same key and your gate holds.
|
|
115
|
+
- **Stored content should not key on those coordinates.** The retry re-invokes the model, so one coordinate can carry different text on each attempt. `on conflict (turn_id, step_index, sequence) do nothing` would keep the abandoned attempt and drop the one that finished. Key on `meta.id`, and accept that an interrupted turn leaves both attempts in the table.
|
|
116
|
+
|
|
117
|
+
Behind that split is an asymmetry worth knowing: durable history keeps only the attempt that completed, while the event stream keeps every attempt, and no field marks which is which. Hooks are at-least-once, and no key collapses a retry.
|
|
118
|
+
|
|
119
|
+
See [the event envelope](../concepts/sessions-runs-and-streaming#the-event-envelope) for the full contract.
|
|
120
|
+
|
|
83
121
|
## Execution order
|
|
84
122
|
|
|
85
123
|
When a stream event fires, three things happen in order:
|
|
86
124
|
|
|
87
|
-
1. Emit. The channel adapter handler runs,
|
|
125
|
+
1. Emit. The channel adapter handler runs, the event is stamped with its `meta` envelope, then it is written to the durable stream.
|
|
88
126
|
2. Hooks. Stream-event hooks fire (typed handlers first, then the `*` wildcard). Return values are ignored.
|
|
89
127
|
3. Dynamic tool resolvers. Resolvers subscribed to the event type run and update the tool set.
|
|
90
128
|
|
|
91
|
-
Hooks always run after the event is durably recorded, so if a hook throws, the stream stays consistent.
|
|
129
|
+
Hooks always run after the event is durably recorded, so if a hook throws, the stream stays consistent. The persisted event and every hook observe the same `meta.id`.
|
|
92
130
|
|
|
93
131
|
## What happens when a hook throws
|
|
94
132
|
|
|
@@ -15,6 +15,10 @@ The directory is an immutable OTLP/JSON spool and remains available after `eve d
|
|
|
15
15
|
|
|
16
16
|
Use `eve trace ls` to list captured traces and `eve trace <trace>` to inspect a session's span tree.
|
|
17
17
|
|
|
18
|
+
When a model call is served by Vercel AI Gateway, its `agent.step` span also carries the cost the gateway reported: `gen_ai.usage.cost` (raw inference, USD), `gen_ai.usage.gateway_cost` (with the gateway surcharge), `gen_ai.usage.input_cost` / `gen_ai.usage.output_cost` (the split), and `gen_ai.generation.id` for reconciliation with the gateway dashboard. These attributes only exist for gateway-served calls — other providers emit nothing. Cost per turn is the sum across the turn's step spans.
|
|
19
|
+
|
|
20
|
+
Model and step spans also split token usage when the provider reports details: `gen_ai.usage.cache_read.input_tokens` and `gen_ai.usage.cache_creation.input_tokens` (named for the [OTel GenAI semantic conventions](https://github.com/open-telemetry/semantic-conventions-genai)) alongside the `agent.usage.input_tokens` / `agent.usage.output_tokens` totals — cached tokens price differently, so the split makes cost attribution exact. Providers without detailed usage emit only the totals.
|
|
21
|
+
|
|
18
22
|
The local writer is an internal development default, not a second provider layered over authored instrumentation. When `instrumentation.ts` exists, its setup retains control and the zero-config writer is not installed.
|
|
19
23
|
|
|
20
24
|
### Local trace retention
|
|
@@ -18,6 +18,8 @@ eve add instrumentation/braintrust
|
|
|
18
18
|
|
|
19
19
|
Extensions may create a mount under `agent/extensions/`. Connections write their initial definition under `agent/connections/` and install `@vercel/connect` when required. Instrumentation providers write `agent/instrumentation.ts`; because an agent has one instrumentation file, compose multiple exporters there by hand. Configure generated files and required environment variables before running your agent.
|
|
20
20
|
|
|
21
|
+
When an official item has an interactive setup flow, eve asks whether to run it after installation. Run the printed `eve add <item> --skip-install` command to resume a skipped or cancelled setup later.
|
|
22
|
+
|
|
21
23
|
## Find an integration
|
|
22
24
|
|
|
23
25
|
Browse the [Integrations directory](/integrations) to see the official integrations available from the eve registry.
|
|
@@ -44,7 +46,7 @@ eve registry view extension/agent-browser
|
|
|
44
46
|
|
|
45
47
|
## Add a third-party source
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
Use the integration URL template provided by the registry publisher and give the source a namespace:
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
52
|
eve registry add @acme=https://registry.acme.com/r/{name}.json
|
|
@@ -71,6 +73,79 @@ Install a known integration URL directly when you do not need a namespace:
|
|
|
71
73
|
eve add https://registry.acme.com/r/analytics.json
|
|
72
74
|
```
|
|
73
75
|
|
|
76
|
+
## Contribute an official integration
|
|
77
|
+
|
|
78
|
+
Community contributions to the official registry are welcome. Open an issue and get maintainer agreement before submitting a pull request, then follow the [registry contribution guide](https://github.com/vercel/eve/blob/main/CONTRIBUTING.md#adding-an-integration-to-the-registry) for the required source files, metadata, validation, and extension requirements.
|
|
79
|
+
|
|
80
|
+
## Host your own registry
|
|
81
|
+
|
|
82
|
+
Hosting your own registry is the publishing side of the [third-party source workflow](#add-a-third-party-source). Once it is deployed, other eve projects can give it a namespace and pull integrations from it.
|
|
83
|
+
|
|
84
|
+
An eve registry is a standard [shadcn registry](https://ui.shadcn.com/docs/registry), so it can be hosted by any service that serves JSON over HTTP. It needs two kinds of endpoint:
|
|
85
|
+
|
|
86
|
+
- A catalog such as `https://registry.acme.com/r/registry.json` for `eve registry list` and `eve registry search`
|
|
87
|
+
- One JSON document per integration, such as `https://registry.acme.com/r/analytics.json`, for `eve registry view` and `eve add`
|
|
88
|
+
|
|
89
|
+
Start with a source file for the integration and a `registry.json` that describes where to install it:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
registry.json
|
|
93
|
+
registry/
|
|
94
|
+
└── analytics.ts
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```json title="registry.json"
|
|
98
|
+
{
|
|
99
|
+
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
|
100
|
+
"name": "acme",
|
|
101
|
+
"homepage": "https://registry.acme.com",
|
|
102
|
+
"items": [
|
|
103
|
+
{
|
|
104
|
+
"name": "analytics",
|
|
105
|
+
"type": "registry:item",
|
|
106
|
+
"title": "Acme Analytics",
|
|
107
|
+
"description": "Add Acme analytics tools to an eve agent.",
|
|
108
|
+
"dependencies": ["@acme/eve-analytics"],
|
|
109
|
+
"envVars": {
|
|
110
|
+
"ACME_API_KEY": ""
|
|
111
|
+
},
|
|
112
|
+
"files": [
|
|
113
|
+
{
|
|
114
|
+
"path": "registry/analytics.ts",
|
|
115
|
+
"type": "registry:file",
|
|
116
|
+
"target": "agent/extensions/analytics.ts"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`files[].path` is relative to `registry.json`. `files[].target` is relative to the root of the eve project that installs the item. Use `registry:item` with explicit `registry:file` targets for eve integrations so installation does not depend on a UI framework or shadcn project aliases.
|
|
125
|
+
|
|
126
|
+
Validate the source registry, then build its static JSON:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm dlx shadcn@latest registry validate
|
|
130
|
+
pnpm dlx shadcn@latest build
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
By default, the build writes the catalog to `public/r/registry.json` and each item to `public/r/<name>.json`. Deploy the `public` directory to a static host, or use the shadcn registry APIs to serve the same payloads from dynamic routes.
|
|
134
|
+
|
|
135
|
+
Before sharing the registry, test its deployed catalog and item endpoints from an eve project:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
eve registry list --registry https://registry.acme.com/r/registry.json
|
|
139
|
+
eve registry view https://registry.acme.com/r/analytics.json
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Share the item URL template with consumers. From another eve project, they can add the hosted registry as a third-party source and pull the integration through its namespace:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
eve registry add @acme=https://registry.acme.com/r/{name}.json
|
|
146
|
+
eve add @acme/analytics
|
|
147
|
+
```
|
|
148
|
+
|
|
74
149
|
## Configure generated files
|
|
75
150
|
|
|
76
151
|
Integrations add project files. Read the generated mount before you run the agent, then add the configuration the extension requires.
|