eve 0.15.3 → 0.15.5
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 +15 -0
- package/dist/src/chunks/{use-eve-agent-8X2UMr8q.js → use-eve-agent-BEOUv37s.js} +70 -0
- package/dist/src/chunks/{use-eve-agent-9ZNiSFMb.js → use-eve-agent-C25KOe9i.js} +70 -0
- package/dist/src/client/authorization-message-parts.d.ts +4 -0
- package/dist/src/client/authorization-message-parts.js +1 -0
- package/dist/src/client/index.d.ts +2 -2
- package/dist/src/client/message-reducer-types.d.ts +40 -1
- package/dist/src/client/message-reducer.d.ts +3 -5
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/evals/index.d.ts +2 -0
- package/dist/src/evals/index.js +1 -1
- package/dist/src/evals/mock-model.d.ts +93 -0
- package/dist/src/evals/mock-model.js +1 -0
- package/dist/src/execution/sandbox/prewarm.js +2 -2
- package/dist/src/internal/application/compiled-artifacts.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/build-application.js +1 -1
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +2 -2
- package/dist/src/internal/workflow/queue-namespace.d.ts +8 -3
- package/dist/src/internal/workflow/queue-namespace.js +1 -1
- package/dist/src/internal/workflow/runtime.d.ts +0 -1
- package/dist/src/internal/workflow/runtime.js +1 -1
- package/dist/src/internal/workflow-bundle/builder-support.d.ts +11 -0
- package/dist/src/internal/workflow-bundle/builder-support.js +2 -2
- package/dist/src/internal/workflow-bundle/builder.d.ts +1 -11
- package/dist/src/internal/workflow-bundle/builder.js +3 -3
- package/dist/src/internal/workflow-bundle/workflow-builders.d.ts +6 -6
- package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
- package/dist/src/protocol/message.d.ts +14 -10
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +3 -3
- package/dist/src/public/channels/slack/limits.d.ts +5 -3
- package/dist/src/public/channels/slack/limits.js +1 -1
- package/dist/src/react/index.d.ts +1 -1
- package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
- 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 +105 -1
- package/dist/src/svelte/index.d.ts +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.d.ts +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/evals/overview.mdx +38 -0
- package/docs/guides/frontend/overview.mdx +34 -4
- package/docs/reference/typescript-api.md +2 -1
- package/package.json +1 -1
|
@@ -142,7 +142,13 @@ function StatusDot({ status }: { readonly status: AgentStatus }) {
|
|
|
142
142
|
}
|
|
143
143
|
`,"app/_components/agent-message.tsx":`"use client";
|
|
144
144
|
|
|
145
|
-
import type {
|
|
145
|
+
import type {
|
|
146
|
+
EveAuthorizationPart,
|
|
147
|
+
EveDynamicToolPart,
|
|
148
|
+
EveMessage,
|
|
149
|
+
EveMessagePart,
|
|
150
|
+
} from "eve/react";
|
|
151
|
+
import { CheckCircleIcon, ExternalLinkIcon, KeyRoundIcon, XCircleIcon } from "lucide-react";
|
|
146
152
|
import { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";
|
|
147
153
|
import { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";
|
|
148
154
|
import {
|
|
@@ -153,6 +159,7 @@ import {
|
|
|
153
159
|
ToolOutput,
|
|
154
160
|
} from "@/components/ai-elements/tool";
|
|
155
161
|
import { Button } from "@/components/ui/button";
|
|
162
|
+
import { cn } from "@/lib/utils";
|
|
156
163
|
|
|
157
164
|
export type AgentInputResponse = {
|
|
158
165
|
readonly optionId?: string;
|
|
@@ -223,6 +230,8 @@ function AgentMessagePart({
|
|
|
223
230
|
<ReasoningContent>{part.text}</ReasoningContent>
|
|
224
231
|
</Reasoning>
|
|
225
232
|
);
|
|
233
|
+
case "authorization":
|
|
234
|
+
return <AuthorizationPrompt part={part} />;
|
|
226
235
|
case "dynamic-tool":
|
|
227
236
|
return (
|
|
228
237
|
<Tool
|
|
@@ -248,6 +257,99 @@ function AgentMessagePart({
|
|
|
248
257
|
}
|
|
249
258
|
}
|
|
250
259
|
|
|
260
|
+
function AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {
|
|
261
|
+
const isAuthorized = part.state === "completed" && part.outcome === "authorized";
|
|
262
|
+
const isCompleted = part.state === "completed";
|
|
263
|
+
const Icon = isAuthorized ? CheckCircleIcon : isCompleted ? XCircleIcon : KeyRoundIcon;
|
|
264
|
+
const instructions = part.authorization?.instructions;
|
|
265
|
+
const shouldShowInstructions = instructions !== undefined && instructions !== part.description;
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<div
|
|
269
|
+
className={cn(
|
|
270
|
+
"space-y-3 rounded-md border p-3",
|
|
271
|
+
isAuthorized
|
|
272
|
+
? "border-emerald-500/30 bg-emerald-500/5"
|
|
273
|
+
: isCompleted
|
|
274
|
+
? "border-destructive/30 bg-destructive/5"
|
|
275
|
+
: "border-blue-500/30 bg-blue-500/5",
|
|
276
|
+
)}
|
|
277
|
+
>
|
|
278
|
+
<div className="flex items-start gap-3">
|
|
279
|
+
<span
|
|
280
|
+
className={cn(
|
|
281
|
+
"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full",
|
|
282
|
+
isAuthorized
|
|
283
|
+
? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"
|
|
284
|
+
: isCompleted
|
|
285
|
+
? "bg-destructive/10 text-destructive"
|
|
286
|
+
: "bg-blue-500/10 text-blue-700 dark:text-blue-300",
|
|
287
|
+
)}
|
|
288
|
+
>
|
|
289
|
+
<Icon className="size-4" />
|
|
290
|
+
</span>
|
|
291
|
+
<div className="min-w-0 flex-1 space-y-2">
|
|
292
|
+
<p className="font-medium text-sm">{authorizationTitle(part)}</p>
|
|
293
|
+
<p className="text-muted-foreground text-sm">{authorizationDescription(part)}</p>
|
|
294
|
+
{shouldShowInstructions ? (
|
|
295
|
+
<p className="text-muted-foreground text-sm">{instructions}</p>
|
|
296
|
+
) : null}
|
|
297
|
+
{part.state === "required" && part.authorization?.userCode ? (
|
|
298
|
+
<div className="flex flex-wrap items-center gap-2 text-sm">
|
|
299
|
+
<span className="text-muted-foreground">Code</span>
|
|
300
|
+
<code className="rounded-md bg-background px-2 py-1 font-mono">
|
|
301
|
+
{part.authorization.userCode}
|
|
302
|
+
</code>
|
|
303
|
+
</div>
|
|
304
|
+
) : null}
|
|
305
|
+
{part.state === "required" && part.authorization?.url ? (
|
|
306
|
+
<Button asChild size="sm">
|
|
307
|
+
<a href={part.authorization.url} rel="noreferrer" target="_blank">
|
|
308
|
+
<ExternalLinkIcon className="size-4" />
|
|
309
|
+
Sign in with {part.displayName}
|
|
310
|
+
</a>
|
|
311
|
+
</Button>
|
|
312
|
+
) : null}
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function authorizationTitle(part: EveAuthorizationPart): string {
|
|
320
|
+
if (part.state === "required") {
|
|
321
|
+
return \`Connect \${part.displayName}\`;
|
|
322
|
+
}
|
|
323
|
+
if (part.outcome === "authorized") {
|
|
324
|
+
return \`\${part.displayName} connected\`;
|
|
325
|
+
}
|
|
326
|
+
return \`\${part.displayName} authorization \${formatAuthorizationOutcome(part.outcome)}\`;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function authorizationDescription(part: EveAuthorizationPart): string {
|
|
330
|
+
if (part.state === "required") {
|
|
331
|
+
return part.description;
|
|
332
|
+
}
|
|
333
|
+
if (part.outcome === "authorized") {
|
|
334
|
+
return \`\${part.displayName} connected.\`;
|
|
335
|
+
}
|
|
336
|
+
const tail = part.reason !== undefined ? \` (\${part.reason})\` : "";
|
|
337
|
+
return \`\${part.displayName} authorization \${formatAuthorizationOutcome(part.outcome)}\${tail}.\`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["outcome"]>): string {
|
|
341
|
+
switch (outcome) {
|
|
342
|
+
case "authorized":
|
|
343
|
+
return "authorized";
|
|
344
|
+
case "declined":
|
|
345
|
+
return "declined";
|
|
346
|
+
case "failed":
|
|
347
|
+
return "failed";
|
|
348
|
+
case "timed-out":
|
|
349
|
+
return "timed out";
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
251
353
|
function InputRequestActions({
|
|
252
354
|
canRespond,
|
|
253
355
|
onInputResponses,
|
|
@@ -303,6 +405,8 @@ function InputRequestActions({
|
|
|
303
405
|
|
|
304
406
|
function partKey(part: EveMessagePart, index: number): string {
|
|
305
407
|
switch (part.type) {
|
|
408
|
+
case "authorization":
|
|
409
|
+
return \`authorization:\${part.turnId}:\${part.stepIndex}:\${part.name}\`;
|
|
306
410
|
case "dynamic-tool":
|
|
307
411
|
return part.toolCallId;
|
|
308
412
|
default:
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { useEveAgent, type PrepareSend, type UseEveAgentOptions, type UseEveAgentReturn, type UseEveAgentSnapshot, type UseEveAgentStatus, } from "#svelte/use-eve-agent.js";
|
|
2
2
|
export { type EveAgentReducer, type EveAgentReducerEvent, type ClientInputRespondedEvent, type ClientMessageFailedEvent, type ClientMessageSubmittedEvent, } from "#client/reducer.js";
|
|
3
|
-
export { defaultMessageReducer, type EveMessageData, type EveDynamicToolPart, type EveMessageInputRequest, type EveMessage, type EveMessageMetadata, type EveMessagePart, type EveMessageToolMetadata, } from "#client/message-reducer.js";
|
|
3
|
+
export { defaultMessageReducer, type EveAuthorizationChallenge, type EveAuthorizationOutcome, type EveAuthorizationPart, type EveMessageData, type EveDynamicToolPart, type EveMessageInputRequest, type EveMessage, type EveMessageMetadata, type EveMessagePart, type EveMessageToolMetadata, } from "#client/message-reducer.js";
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { useEveAgent, type PrepareSend, type UseEveAgentOptions, type UseEveAgentReturn, type UseEveAgentSnapshot, type UseEveAgentStatus, } from "#vue/use-eve-agent.js";
|
|
2
2
|
export { type EveAgentReducer, type EveAgentReducerEvent, type ClientInputRespondedEvent, type ClientMessageFailedEvent, type ClientMessageSubmittedEvent, } from "#client/reducer.js";
|
|
3
|
-
export { defaultMessageReducer, type EveMessageData, type EveDynamicToolPart, type EveMessageInputRequest, type EveMessage, type EveMessageMetadata, type EveMessagePart, type EveMessageToolMetadata, } from "#client/message-reducer.js";
|
|
3
|
+
export { defaultMessageReducer, type EveAuthorizationChallenge, type EveAuthorizationOutcome, type EveAuthorizationPart, type EveMessageData, type EveDynamicToolPart, type EveMessageInputRequest, type EveMessage, type EveMessageMetadata, type EveMessagePart, type EveMessageToolMetadata, } from "#client/message-reducer.js";
|
package/dist/src/vue/index.js
CHANGED
package/docs/evals/overview.mdx
CHANGED
|
@@ -58,6 +58,44 @@ export default defineEvalConfig({
|
|
|
58
58
|
|
|
59
59
|
Everything is optional. `judge` sets the default model for [LLM-as-judge](./judge) assertions (`t.judge.*`); a tree of fully deterministic evals can omit it. `reporters`, `maxConcurrency`, and `timeoutMs` round out the defaults. Config `reporters` observe every eval in the run, so set one `Braintrust()` here instead of adding it to each eval. CLI flags (`--max-concurrency`, `--timeout`) and per-eval values take precedence over the config defaults.
|
|
60
60
|
|
|
61
|
+
## Deterministic fixture models
|
|
62
|
+
|
|
63
|
+
Use `mockModel` when an eval fixture needs to exercise eve's runtime without calling a model provider. A static fixture can be one line:
|
|
64
|
+
|
|
65
|
+
```ts title="agent/agent.ts"
|
|
66
|
+
import { defineAgent } from "eve";
|
|
67
|
+
import { mockModel } from "eve/evals";
|
|
68
|
+
|
|
69
|
+
export default defineAgent({
|
|
70
|
+
model: mockModel("A deterministic reply"),
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Pass a callback when the reply depends on the conversation. The callback receives an eve-owned view of the prompt, including `lastUserMessage`, `userMessages`, `userMessageCount`, available `tools`, and prior `toolResults`:
|
|
75
|
+
|
|
76
|
+
```ts title="agent/agent.ts"
|
|
77
|
+
export default defineAgent({
|
|
78
|
+
model: mockModel(
|
|
79
|
+
({ lastUserMessage, userMessageCount }) => `Turn ${userMessageCount}: ${lastUserMessage}`,
|
|
80
|
+
),
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The callback may return `{ text, toolCalls, usage }` for deterministic tool loops or explicit token counts. Use the options form only when a fixture also needs a custom model identity:
|
|
85
|
+
|
|
86
|
+
```ts title="agent/agent.ts"
|
|
87
|
+
model: mockModel({
|
|
88
|
+
modelId: "weather-script",
|
|
89
|
+
provider: "my-fixtures",
|
|
90
|
+
respond: ({ toolResults }) =>
|
|
91
|
+
toolResults.length === 0
|
|
92
|
+
? { toolCalls: [{ name: "get_weather", input: { city: "Brooklyn" } }] }
|
|
93
|
+
: `Weather: ${JSON.stringify(toolResults[0]?.output)}`,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`mockModel()` uses `"Mock response"` when no response is supplied. It handles both generated and streamed responses, derives deterministic response metadata, and estimates token usage. Because the model is part of the agent definition, use it for a dedicated fixture agent; it remains mocked whether that fixture runs locally or as a deployed eval target.
|
|
98
|
+
|
|
61
99
|
## The `t` context
|
|
62
100
|
|
|
63
101
|
`t` is both the driver and the assertion surface. There are no separate `input`, `run`, `checks`, or `scores` fields. You write ordinary control flow, sending turns and asserting inline.
|
|
@@ -72,9 +72,9 @@ export function Chat() {
|
|
|
72
72
|
| `stop` | Abort the active request. |
|
|
73
73
|
| `reset` | Clear local events, data, errors, and the local session cursor. |
|
|
74
74
|
|
|
75
|
-
Most chat UIs only need `data.messages` and `status`. Drop down to `events`
|
|
75
|
+
Most chat UIs only need `data.messages` and `status`. Drop down to `events` when you need the authoritative wire events directly, for example to persist an audit log or build a custom projection.
|
|
76
76
|
|
|
77
|
-
`data.messages` are `EveMessage[]` following the AI SDK `UIMessage` convention, so they drop straight into any AI SDK UI primitive that accepts a `UIMessage[]`. Parts include user text, assistant text, reasoning, tool calls, tool results, and
|
|
77
|
+
`data.messages` are `EveMessage[]` following the AI SDK `UIMessage` convention, so they drop straight into any AI SDK UI primitive that accepts a `UIMessage[]`. Parts include user text, assistant text, reasoning, tool calls, tool results, input requests, and connection authorization prompts.
|
|
78
78
|
|
|
79
79
|
## Sending and streaming
|
|
80
80
|
|
|
@@ -117,6 +117,38 @@ if (request) {
|
|
|
117
117
|
|
|
118
118
|
`request.prompt` and `request.options` give you what you need to render the approve and deny UI. The default reducer marks the part as responded immediately, then updates it again once eve streams the resumed result.
|
|
119
119
|
|
|
120
|
+
## Authorization prompts
|
|
121
|
+
|
|
122
|
+
Connections and tools that need OAuth or another grant emit `authorization.required`. The default reducer projects that into an `authorization` message part with the display name, instructions, device code, and user-facing sign-in URL. Render that part as a normal chat message, then keep the session cursor; eve resumes the parked turn when the callback completes and updates the part after `authorization.completed`:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import type { EveMessagePart } from "eve/react";
|
|
126
|
+
|
|
127
|
+
function AuthorizationPrompt({ part }: { part: EveMessagePart }) {
|
|
128
|
+
if (part.type !== "authorization") return null;
|
|
129
|
+
|
|
130
|
+
if (part.state === "completed") {
|
|
131
|
+
return (
|
|
132
|
+
<p>
|
|
133
|
+
{part.outcome === "authorized"
|
|
134
|
+
? `${part.displayName} connected.`
|
|
135
|
+
: `${part.displayName} authorization ${part.outcome}.`}
|
|
136
|
+
</p>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<section>
|
|
142
|
+
<p>{part.description}</p>
|
|
143
|
+
{part.authorization?.userCode ? <code>{part.authorization.userCode}</code> : null}
|
|
144
|
+
{part.authorization?.url ? <a href={part.authorization.url}>Sign in</a> : null}
|
|
145
|
+
</section>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
For fully custom state machines, `authorization.required` and `authorization.completed` are still available on `events` and `onEvent`.
|
|
151
|
+
|
|
120
152
|
## Attach page context per turn
|
|
121
153
|
|
|
122
154
|
`clientContext` adds ephemeral context for the next model call only. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, so it never dispatches a turn on its own and never lands in durable session history. Pass it directly to `send()`:
|
|
@@ -222,8 +254,6 @@ For multiple chat threads, keep one saved event log and session cursor per threa
|
|
|
222
254
|
|
|
223
255
|
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.
|
|
224
256
|
|
|
225
|
-
Connection authorization prompts need one extra bit of UI state. eve emits `authorization.required` when a tool needs OAuth or another connection grant. Treat that as a parked chat turn for rendering and persistence: show the authorization prompt, disable ordinary text input for that thread, and keep the session cursor so the callback or a structured decline can continue the same session.
|
|
226
|
-
|
|
227
257
|
## Custom hosts and headers
|
|
228
258
|
|
|
229
259
|
Pass `host` when the eve server isn't same-origin, and pass `auth` or `headers` when the channel needs credentials. Function values are re-resolved before every HTTP request, reconnects included:
|
|
@@ -49,6 +49,7 @@ export default defineTool({
|
|
|
49
49
|
| `defineRemoteAgent` | `eve` | `agent/subagents/<id>/agent.ts` | [Remote agents](../guides/remote-agents) |
|
|
50
50
|
| `defineEval` | `eve/evals` | `evals/*.eval.ts` | [Evals](../evals/overview) |
|
|
51
51
|
| `defineEvalConfig` | `eve/evals` | `evals/evals.config.ts` | [Evals](../evals/overview) |
|
|
52
|
+
| `mockModel` | `eve/evals` | Deterministic fixture agent models | [Evals](../evals/overview) |
|
|
52
53
|
| `useEveAgent` | `eve/react`, `eve/vue`, `eve/svelte` | frontend | [Frontend](../guides/frontend/overview) |
|
|
53
54
|
|
|
54
55
|
A few non-`define*` helpers round out the set: `disableTool` and `ExperimentalWorkflow` from `eve/tools` (see [Default harness](../concepts/default-harness)), the route verbs `GET`/`POST`/`PUT`/`PATCH`/`DELETE`/`WS` from `eve/channels`, the approval policies `always`/`once`/`never` from `eve/tools/approval`, and the channel auth helpers `localDev`/`vercelOidc`/`placeholderAuth` from `eve/channels/auth`. To wrap a built-in tool, import its default value from `eve/tools/defaults` (`bash`, `readFile`, `writeFile`, `glob`, `grep`, `webFetch`, `webSearch`, `todo`, `loadSkill`). `AgentReasoningDefinition` is exported from `eve` for the top-level `defineAgent({ reasoning })` setting. `AgentWorkflowDefinition` and `AgentWorkflowWorldDefinition` are exported from `eve` for the `defineAgent({ experimental: { workflow } })` config shape.
|
|
@@ -85,7 +86,7 @@ A few non-`define*` helpers round out the set: `disableTool` and `ExperimentalWo
|
|
|
85
86
|
| `eve/context` | `defineState`, session and state types |
|
|
86
87
|
| `eve/sandbox` | `defineSandbox`, backends |
|
|
87
88
|
| `eve/instrumentation` | `defineInstrumentation`, `isChannel` |
|
|
88
|
-
| `eve/evals` | `defineEval`, `defineEvalConfig`, eval types
|
|
89
|
+
| `eve/evals` | `defineEval`, `defineEvalConfig`, `mockModel`, eval types |
|
|
89
90
|
| `eve/evals/expect` | `includes`, `equals`, `matches`, `similarity` |
|
|
90
91
|
| `eve/evals/reporters` | `Braintrust`, `JUnit`, `EvalReporter` |
|
|
91
92
|
| `eve/evals/loaders` | `loadJson`, `loadYaml` |
|