eve 0.19.0 → 0.21.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 +29 -0
- package/dist/src/channel/types.d.ts +9 -5
- package/dist/src/chunks/{use-eve-agent-Dvy_Wjvq.js → use-eve-agent-CM24ZUEI.js} +48 -34
- package/dist/src/chunks/{use-eve-agent-Bh1NmXO9.js → use-eve-agent-CxcKypLZ.js} +48 -34
- package/dist/src/cli/dev/tui/setup-selection-input.js +1 -1
- package/dist/src/cli/dev/tui/stream-format.d.ts +4 -0
- package/dist/src/cli/dev/tui/stream-format.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +1 -1
- package/dist/src/cli/dev/tui/test/mock-terminal.d.ts +2 -0
- package/dist/src/cli/dev/tui/test/mock-terminal.js +1 -1
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/message-reducer-types.d.ts +11 -3
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/compiler/workspace-resources.js +1 -1
- package/dist/src/context/build-base-tool-context.d.ts +9 -0
- package/dist/src/context/build-base-tool-context.js +1 -0
- package/dist/src/context/build-dynamic-tools.js +1 -1
- package/dist/src/context/dynamic-skill-lifecycle.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/keys.d.ts +0 -1
- package/dist/src/context/keys.js +1 -1
- package/dist/src/discover/sandbox.d.ts +0 -6
- package/dist/src/discover/sandbox.js +1 -1
- package/dist/src/evals/cli/eval.js +4 -1
- package/dist/src/evals/runner/discover.d.ts +10 -0
- package/dist/src/evals/runner/discover.js +1 -1
- package/dist/src/execution/create-session-step.d.ts +2 -1
- package/dist/src/execution/create-session-step.js +1 -1
- package/dist/src/execution/delegated-parent-notification.d.ts +6 -0
- package/dist/src/execution/delegated-parent-notification.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/dispatch-workflow-runtime-actions-step.js +1 -1
- package/dist/src/execution/durable-session-migrations/turn-workflow.d.ts +2 -0
- package/dist/src/execution/durable-session-store.d.ts +1 -0
- package/dist/src/execution/next-driver-action.d.ts +3 -0
- package/dist/src/execution/node-step.d.ts +8 -0
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/run-session-limits.d.ts +21 -0
- package/dist/src/execution/run-session-limits.js +1 -0
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/sandbox/abort-bound-session.d.ts +6 -0
- package/dist/src/execution/sandbox/abort-bound-session.js +1 -0
- package/dist/src/execution/sandbox/active-handles.d.ts +29 -0
- package/dist/src/execution/sandbox/active-handles.js +1 -0
- package/dist/src/execution/sandbox/bindings/docker.d.ts +2 -2
- package/dist/src/execution/sandbox/bindings/docker.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/local-backend-utils.d.ts +1 -1
- package/dist/src/execution/sandbox/bindings/local-backend-utils.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-provider-state.d.ts +11 -0
- package/dist/src/execution/sandbox/bindings/microsandbox-provider-state.js +1 -0
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.d.ts +7 -4
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/ensure.js +1 -1
- package/dist/src/execution/sandbox/prewarm.js +1 -1
- package/dist/src/execution/sandbox/require-sandbox.d.ts +3 -1
- package/dist/src/execution/sandbox/require-sandbox.js +1 -1
- package/dist/src/execution/session-callback-step.d.ts +6 -0
- package/dist/src/execution/session-callback-step.js +1 -1
- package/dist/src/execution/session.d.ts +14 -3
- package/dist/src/execution/session.js +2 -4
- package/dist/src/execution/skills/instructions.d.ts +8 -4
- package/dist/src/execution/skills/instructions.js +2 -2
- package/dist/src/execution/subagent-tool.d.ts +7 -0
- package/dist/src/execution/subagent-tool.js +1 -1
- package/dist/src/execution/subagent-usage-span.d.ts +9 -0
- package/dist/src/execution/subagent-usage-span.js +1 -0
- package/dist/src/execution/tool-auth.d.ts +2 -1
- package/dist/src/execution/tool-auth.js +1 -1
- package/dist/src/execution/turn-execution-cursor.d.ts +2 -0
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/web-fetch/tool.d.ts +6 -1
- package/dist/src/execution/web-fetch/tool.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.js +1 -1
- package/dist/src/execution/workflow-skill-root.d.ts +6 -0
- package/dist/src/execution/workflow-skill-root.js +1 -0
- package/dist/src/execution/workflow-steps.d.ts +3 -0
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/advertised-tools.d.ts +1 -0
- package/dist/src/harness/advertised-tools.js +1 -1
- package/dist/src/harness/attachment-staging.js +1 -1
- package/dist/src/harness/compaction.d.ts +1 -1
- package/dist/src/harness/compaction.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/execute-tool.d.ts +2 -1
- package/dist/src/harness/input-requests.d.ts +8 -0
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/model-call-error.js +1 -1
- package/dist/src/harness/runtime-actions.js +1 -1
- package/dist/src/harness/session-limit-continuation.d.ts +55 -0
- package/dist/src/harness/session-limit-continuation.js +1 -0
- package/dist/src/harness/session-limit-enforcement.d.ts +55 -0
- package/dist/src/harness/session-limit-enforcement.js +1 -0
- package/dist/src/harness/step-hooks.d.ts +1 -1
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/subagent-depth.d.ts +1 -4
- package/dist/src/harness/subagent-depth.js +1 -1
- package/dist/src/harness/subagent-token-budget.d.ts +14 -0
- package/dist/src/harness/subagent-token-budget.js +1 -0
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tools.d.ts +2 -3
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/harness/turn-cancellation.d.ts +8 -0
- package/dist/src/harness/turn-cancellation.js +1 -0
- package/dist/src/harness/turn-tag-state.d.ts +33 -0
- package/dist/src/harness/turn-tag-state.js +1 -1
- package/dist/src/harness/types.d.ts +23 -4
- package/dist/src/harness/workflow-sandbox.d.ts +1 -0
- package/dist/src/harness/workflow-sandbox.js +1 -1
- package/dist/src/harness/workflow-subagent-limit.d.ts +38 -0
- package/dist/src/harness/workflow-subagent-limit.js +1 -0
- package/dist/src/harness/workflow-tool-description.d.ts +6 -1
- package/dist/src/harness/workflow-tool-description.js +5 -3
- 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/create-application-nitro.js +1 -1
- package/dist/src/internal/nitro/host/sandbox-shutdown-plugin.d.ts +40 -0
- package/dist/src/internal/nitro/host/sandbox-shutdown-plugin.js +1 -0
- package/dist/src/internal/nitro/host/start-production-server.js +1 -1
- package/dist/src/protocol/message.d.ts +31 -2
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +34 -3
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
- package/dist/src/public/channels/chat-sdk/index.d.ts +2 -0
- package/dist/src/public/channels/chat-sdk/index.js +1 -1
- package/dist/src/public/channels/chat-sdk/messageToUserContent.d.ts +13 -0
- package/dist/src/public/channels/chat-sdk/messageToUserContent.js +1 -0
- package/dist/src/public/channels/chat-sdk/notImplemented.d.ts +7 -0
- package/dist/src/public/channels/chat-sdk/notImplemented.js +1 -0
- package/dist/src/public/channels/slack/api.d.ts +14 -12
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/definitions/approval.d.ts +4 -1
- package/dist/src/public/definitions/tool.d.ts +44 -0
- package/dist/src/public/definitions/tool.js +1 -1
- package/dist/src/public/tools/index.d.ts +1 -1
- package/dist/src/public/tools/index.js +1 -1
- package/dist/src/public/tools/internal.d.ts +3 -2
- package/dist/src/public/tools/internal.js +1 -1
- package/dist/src/runtime/actions/types.d.ts +9 -0
- package/dist/src/runtime/actions/types.js +1 -1
- package/dist/src/runtime/agent/bootstrap.d.ts +2 -0
- package/dist/src/runtime/agent/bootstrap.js +1 -1
- package/dist/src/runtime/connections/mcp-client.d.ts +2 -2
- package/dist/src/runtime/connections/mcp-client.js +1 -1
- package/dist/src/runtime/connections/openapi-client.d.ts +2 -2
- package/dist/src/runtime/connections/openapi-client.js +1 -1
- package/dist/src/runtime/connections/types.d.ts +6 -1
- package/dist/src/runtime/framework-tools/bash.js +1 -1
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +1 -1
- package/dist/src/runtime/framework-tools/glob.js +1 -1
- package/dist/src/runtime/framework-tools/grep.js +1 -1
- package/dist/src/runtime/framework-tools/read-file.js +1 -1
- package/dist/src/runtime/framework-tools/web-fetch.js +1 -1
- package/dist/src/runtime/framework-tools/write-file.js +1 -1
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/sandbox/keys.js +1 -1
- package/dist/src/runtime/sandbox/template-plan.js +1 -1
- package/dist/src/runtime/session-callback-route.js +1 -1
- package/dist/src/runtime/skills/sandbox-access.d.ts +1 -1
- package/dist/src/runtime/skills/sandbox-access.js +1 -1
- package/dist/src/runtime/workspace/seed-files.js +1 -1
- package/dist/src/sandbox/state.d.ts +0 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +2 -2
- package/dist/src/setup/scaffold/create/web-template.js +77 -3
- package/dist/src/shared/agent-definition.d.ts +31 -3
- package/dist/src/shared/dynamic-tool-definition.d.ts +4 -1
- package/dist/src/shared/sandbox-backend.d.ts +7 -1
- package/dist/src/shared/skill-package.d.ts +2 -2
- package/dist/src/shared/skill-package.js +1 -1
- package/dist/src/shared/skill-paths.d.ts +28 -0
- package/dist/src/shared/skill-paths.js +2 -0
- package/dist/src/shared/token-usage.d.ts +22 -0
- package/dist/src/shared/token-usage.js +1 -0
- package/dist/src/shared/tool-definition.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.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/agent-config.md +32 -15
- package/docs/channels/chat-sdk.mdx +209 -0
- package/docs/channels/meta.json +1 -0
- package/docs/concepts/context-control.md +2 -2
- package/docs/concepts/default-harness.md +10 -0
- package/docs/concepts/sessions-runs-and-streaming.md +1 -1
- package/docs/guides/client/messages.mdx +4 -0
- package/docs/guides/client/streaming.mdx +17 -12
- package/docs/guides/dynamic-workflows.md +87 -0
- package/docs/guides/frontend/overview.mdx +5 -1
- package/docs/guides/meta.json +1 -0
- package/docs/guides/remote-agents.md +1 -0
- package/docs/reference/project-layout.md +5 -4
- package/docs/reference/typescript-api.md +26 -26
- package/docs/sandbox.mdx +4 -2
- package/docs/skills.mdx +3 -1
- package/docs/subagents.mdx +2 -1
- package/docs/tools/human-in-the-loop.md +1 -1
- package/docs/tools/overview.mdx +2 -0
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ export default eveChannel({
|
|
|
15
15
|
});
|
|
16
16
|
`,"app/_components/agent-chat.tsx":`"use client";
|
|
17
17
|
|
|
18
|
+
import type { UserContent } from "ai";
|
|
18
19
|
import { useEveAgent } from "eve/react";
|
|
19
20
|
import { AlertCircleIcon } from "lucide-react";
|
|
20
21
|
import {
|
|
@@ -42,9 +43,27 @@ export function AgentChat() {
|
|
|
42
43
|
|
|
43
44
|
const handleSubmit = async (message: PromptInputMessage) => {
|
|
44
45
|
const text = message.text.trim();
|
|
45
|
-
if (
|
|
46
|
+
if ((text.length === 0 && message.files.length === 0) || isBusy) return;
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
if (message.files.length === 0) {
|
|
49
|
+
await agent.send({ message: text });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const parts: UserContent = [];
|
|
54
|
+
if (text.length > 0) {
|
|
55
|
+
parts.push({ text, type: "text" });
|
|
56
|
+
}
|
|
57
|
+
for (const file of message.files) {
|
|
58
|
+
parts.push({
|
|
59
|
+
data: file.url,
|
|
60
|
+
filename: file.filename,
|
|
61
|
+
mediaType: file.mediaType,
|
|
62
|
+
type: "file",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
await agent.send({ message: parts });
|
|
48
67
|
};
|
|
49
68
|
|
|
50
69
|
const composer = (
|
|
@@ -148,7 +167,14 @@ import type {
|
|
|
148
167
|
EveMessage,
|
|
149
168
|
EveMessagePart,
|
|
150
169
|
} from "eve/react";
|
|
151
|
-
import {
|
|
170
|
+
import {
|
|
171
|
+
CheckCircleIcon,
|
|
172
|
+
ExternalLinkIcon,
|
|
173
|
+
FileIcon,
|
|
174
|
+
ImageIcon,
|
|
175
|
+
KeyRoundIcon,
|
|
176
|
+
XCircleIcon,
|
|
177
|
+
} from "lucide-react";
|
|
152
178
|
import { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";
|
|
153
179
|
import { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";
|
|
154
180
|
import {
|
|
@@ -167,6 +193,8 @@ export type AgentInputResponse = {
|
|
|
167
193
|
readonly text?: string;
|
|
168
194
|
};
|
|
169
195
|
|
|
196
|
+
type EveFilePart = Extract<EveMessagePart, { type: "file" }>;
|
|
197
|
+
|
|
170
198
|
export function AgentMessage({
|
|
171
199
|
canRespond,
|
|
172
200
|
isStreaming,
|
|
@@ -230,6 +258,8 @@ function AgentMessagePart({
|
|
|
230
258
|
<ReasoningContent>{part.text}</ReasoningContent>
|
|
231
259
|
</Reasoning>
|
|
232
260
|
);
|
|
261
|
+
case "file":
|
|
262
|
+
return <AttachmentPart part={part} />;
|
|
233
263
|
case "authorization":
|
|
234
264
|
return <AuthorizationPrompt part={part} />;
|
|
235
265
|
case "dynamic-tool":
|
|
@@ -257,6 +287,37 @@ function AgentMessagePart({
|
|
|
257
287
|
}
|
|
258
288
|
}
|
|
259
289
|
|
|
290
|
+
function AttachmentPart({ part }: { readonly part: EveFilePart }) {
|
|
291
|
+
const label = part.filename ?? "Attachment";
|
|
292
|
+
const detail = [part.mediaType, formatBytes(part.size)].filter(Boolean).join(" - ");
|
|
293
|
+
const isImage = part.mediaType.startsWith("image/") && part.url !== undefined;
|
|
294
|
+
const Icon = isImage ? ImageIcon : FileIcon;
|
|
295
|
+
const body = (
|
|
296
|
+
<span className="flex max-w-sm items-center gap-3 rounded-md border bg-background/60 p-2 text-sm">
|
|
297
|
+
{isImage ? (
|
|
298
|
+
<img alt={label} className="size-12 shrink-0 rounded-sm object-cover" src={part.url} />
|
|
299
|
+
) : (
|
|
300
|
+
<span className="flex size-10 shrink-0 items-center justify-center rounded-sm bg-muted text-muted-foreground">
|
|
301
|
+
<Icon className="size-4" />
|
|
302
|
+
</span>
|
|
303
|
+
)}
|
|
304
|
+
<span className="min-w-0 flex-1">
|
|
305
|
+
<span className="block truncate font-medium">{label}</span>
|
|
306
|
+
{detail ? <span className="block truncate text-muted-foreground">{detail}</span> : null}
|
|
307
|
+
</span>
|
|
308
|
+
{part.url ? <ExternalLinkIcon className="size-4 shrink-0 text-muted-foreground" /> : null}
|
|
309
|
+
</span>
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
return part.url ? (
|
|
313
|
+
<a href={part.url} rel="noreferrer" target="_blank">
|
|
314
|
+
{body}
|
|
315
|
+
</a>
|
|
316
|
+
) : (
|
|
317
|
+
body
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
260
321
|
function AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {
|
|
261
322
|
const isAuthorized = part.state === "completed" && part.outcome === "authorized";
|
|
262
323
|
const isCompleted = part.state === "completed";
|
|
@@ -350,6 +411,19 @@ function formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["o
|
|
|
350
411
|
}
|
|
351
412
|
}
|
|
352
413
|
|
|
414
|
+
function formatBytes(size: number | undefined): string | undefined {
|
|
415
|
+
if (size === undefined) {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
if (size < 1024) {
|
|
419
|
+
return \`\${size} B\`;
|
|
420
|
+
}
|
|
421
|
+
if (size < 1024 * 1024) {
|
|
422
|
+
return \`\${(size / 1024).toFixed(1)} KB\`;
|
|
423
|
+
}
|
|
424
|
+
return \`\${(size / (1024 * 1024)).toFixed(1)} MB\`;
|
|
425
|
+
}
|
|
426
|
+
|
|
353
427
|
function InputRequestActions({
|
|
354
428
|
canRespond,
|
|
355
429
|
onInputResponses,
|
|
@@ -103,9 +103,28 @@ export interface AgentLimitsDefinition {
|
|
|
103
103
|
* Root sessions are depth 0. A `maxSubagentDepth` of 3 allows child sessions at
|
|
104
104
|
* depths 1, 2, and 3; sessions already at depth 3 cannot delegate again.
|
|
105
105
|
*
|
|
106
|
+
* Delegated subagent sessions resolve this against the cap inherited from
|
|
107
|
+
* the delegating parent; the tighter value wins.
|
|
108
|
+
*
|
|
106
109
|
* @default 3
|
|
107
110
|
*/
|
|
108
111
|
readonly maxSubagentDepth?: number;
|
|
112
|
+
/**
|
|
113
|
+
* Maximum number of subagent calls one `Workflow` tool invocation may
|
|
114
|
+
* dispatch.
|
|
115
|
+
*
|
|
116
|
+
* Applies to the opt-in `Workflow` orchestration tool: a single
|
|
117
|
+
* model-authored workflow program may spawn at most this many subagent or
|
|
118
|
+
* remote-agent calls, counted across the whole program (sequential and
|
|
119
|
+
* parallel calls alike). Calls beyond the limit fail with an error result
|
|
120
|
+
* instead of starting a child session.
|
|
121
|
+
*
|
|
122
|
+
* Delegated subagent sessions resolve this against the cap inherited from
|
|
123
|
+
* the delegating parent; the tighter value wins.
|
|
124
|
+
*
|
|
125
|
+
* @default 100
|
|
126
|
+
*/
|
|
127
|
+
readonly maxSubagents?: number;
|
|
109
128
|
/**
|
|
110
129
|
* Maximum provider-reported input tokens accumulated by one durable session.
|
|
111
130
|
*
|
|
@@ -113,17 +132,26 @@ export interface AgentLimitsDefinition {
|
|
|
113
132
|
* the limit is allowed to finish because providers only report exact usage
|
|
114
133
|
* after the call completes; later model calls in the same session are blocked.
|
|
115
134
|
*
|
|
116
|
-
*
|
|
135
|
+
* `false` disables the limit: the session is uncapped.
|
|
136
|
+
*
|
|
137
|
+
* Delegated subagent sessions default to the delegating parent's remaining
|
|
138
|
+
* quota at dispatch time, and the parent's remaining quota always caps an
|
|
139
|
+
* authored child limit — a child can never outspend its parent's budget.
|
|
140
|
+
*
|
|
141
|
+
* @default 40_000_000 for root sessions; the parent's remaining quota for delegated subagent sessions
|
|
117
142
|
*/
|
|
118
|
-
readonly maxInputTokensPerSession?: number;
|
|
143
|
+
readonly maxInputTokensPerSession?: number | false;
|
|
119
144
|
/**
|
|
120
145
|
* Maximum provider-reported output tokens accumulated by one durable session.
|
|
121
146
|
*
|
|
122
147
|
* eve checks this before starting each model call. The model call that crosses
|
|
123
148
|
* the limit is allowed to finish because providers only report exact usage
|
|
124
149
|
* after the call completes; later model calls in the same session are blocked.
|
|
150
|
+
*
|
|
151
|
+
* `false` disables the limit. Unset by default; delegated subagent sessions
|
|
152
|
+
* inherit the parent's remaining output quota when the parent has one.
|
|
125
153
|
*/
|
|
126
|
-
readonly maxOutputTokensPerSession?: number;
|
|
154
|
+
readonly maxOutputTokensPerSession?: number | false;
|
|
127
155
|
}
|
|
128
156
|
/**
|
|
129
157
|
* Experimental, opt-in agent capabilities authored in `agent.ts`.
|
|
@@ -4,7 +4,10 @@ import type { SessionContext } from "#public/definitions/callback-context.js";
|
|
|
4
4
|
import type { Approval } from "#public/definitions/approval.js";
|
|
5
5
|
import type { SessionAuth } from "#context/keys.js";
|
|
6
6
|
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
7
|
-
type ToolContext = SessionContext
|
|
7
|
+
type ToolContext = SessionContext & {
|
|
8
|
+
/** Aborts when the active turn is cancelled. */
|
|
9
|
+
readonly abortSignal: AbortSignal;
|
|
10
|
+
};
|
|
8
11
|
/**
|
|
9
12
|
* Stream event types allowed for dynamic tool resolvers. Dispatch
|
|
10
13
|
* supports any event; this extract restricts the public surface until
|
|
@@ -11,7 +11,13 @@ export interface SandboxBackendHandle<SO = Record<string, never>> {
|
|
|
11
11
|
readonly session: SandboxSession;
|
|
12
12
|
readonly useSessionFn: SandboxSessionUseFn<SO>;
|
|
13
13
|
captureState(): Promise<SandboxBackendSessionState>;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Stops the underlying compute because the eve server is shutting
|
|
16
|
+
* down; nothing may be left running afterwards. The session must
|
|
17
|
+
* remain reattachable from persisted state on the next server start
|
|
18
|
+
* when the backend supports durable sessions.
|
|
19
|
+
*/
|
|
20
|
+
shutdown(): Promise<void>;
|
|
15
21
|
}
|
|
16
22
|
/**
|
|
17
23
|
* Serializable per-sandbox reconnect record stored on the harness session.
|
|
@@ -30,7 +30,7 @@ export declare function writeSkillPackageDirectory(input: {
|
|
|
30
30
|
}): Promise<void>;
|
|
31
31
|
/**
|
|
32
32
|
* Writes a normalized package into the live sandbox under
|
|
33
|
-
*
|
|
33
|
+
* the sandbox skill root.
|
|
34
34
|
*/
|
|
35
35
|
export declare function writeSkillPackageToSandbox(input: {
|
|
36
36
|
readonly sandbox: SandboxSession;
|
|
@@ -45,6 +45,6 @@ export declare function removeSkillPackageFromSandbox(input: {
|
|
|
45
45
|
}): Promise<void>;
|
|
46
46
|
/**
|
|
47
47
|
* Validates a runtime-contributed skill name before it becomes one path
|
|
48
|
-
* segment under
|
|
48
|
+
* segment under the sandbox skill root.
|
|
49
49
|
*/
|
|
50
50
|
export declare function assertSafeSkillPackageName(name: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname,join}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{Buffer}from"node:buffer";
|
|
1
|
+
import{dirname,join}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{resolveSandboxSkillRoot,resolveSandboxSkillWritePath}from"#shared/skill-paths.js";import{Buffer}from"node:buffer";function normalizeSkillPackage(e){assertSafeSkillPackageName(e.name);let t=[{content:Buffer.from(e.markdown,`utf8`),relativePath:`SKILL.md`}];for(let[n,r]of Object.entries(e.files??{}))assertSafeSkillPackageFilePath(n),t.push({content:contentToBuffer(r),relativePath:n});return t.sort((e,t)=>comparePaths(e.relativePath,t.relativePath)),{description:e.description,files:t,license:e.license,markdown:e.markdown,metadata:e.metadata===void 0?void 0:{...e.metadata},name:e.name}}async function writeSkillPackageDirectory(i){for(let a of i.skill.files){let o=join(i.rootPath,`skills`,i.skill.name,a.relativePath);await mkdir(dirname(o),{recursive:!0}),await writeFile(o,a.content)}}async function writeSkillPackageToSandbox(e){for(let t of e.skill.files)await e.sandbox.writeBinaryFile({content:t.content,path:await resolveSandboxSkillWritePath({name:e.skill.name,relativePath:t.relativePath,sandbox:e.sandbox})})}async function removeSkillPackageFromSandbox(e){assertSafeSkillPackageName(e.name);let t=await resolveSandboxSkillRoot({sandbox:e.sandbox});await e.sandbox.removePath({force:!0,path:`${t}/${e.name}`,recursive:!0})}function assertSafeSkillPackageName(e){if(e.length===0||e.startsWith(`.`)||e.includes(`/`)||e.includes(`\\`)||e.includes(`..`)||!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(e)||/^[A-Za-z]:/.test(e))throw Error(`Expected skill name to be a non-empty shell-safe path segment starting with an alphanumeric character and containing only alphanumerics, ".", "_", or "-".`)}function assertSafeSkillPackageFilePath(e){if(e===`SKILL.md`)throw Error(`Skill package files must not include "SKILL.md"; eve generates it.`);if(e.length===0||e.startsWith(`/`)||e.includes(`\\`)||/^[A-Za-z]:/.test(e)||e.split(`/`).some(e=>e.length===0||e===`.`||e===`..`))throw Error(`Expected skill package file paths to be relative POSIX paths.`)}function contentToBuffer(e){return typeof e==`string`?Buffer.from(e,`utf8`):Buffer.from(e)}function comparePaths(e,t){return e<t?-1:+(e>t)}export{assertSafeSkillPackageName,normalizeSkillPackage,removeSkillPackageFromSandbox,writeSkillPackageDirectory,writeSkillPackageToSandbox};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SandboxSession } from "#shared/sandbox-session.js";
|
|
2
|
+
export declare const MODEL_SKILL_ROOT = "$HOME/.agents/skills";
|
|
3
|
+
export declare const FALLBACK_SKILL_ROOT = "/workspace/skills";
|
|
4
|
+
export declare function formatSkillModelPath(input: {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly relativePath: string;
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function formatFallbackSkillPath(input: {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly relativePath: string;
|
|
11
|
+
}): string;
|
|
12
|
+
export declare function resolveSandboxSkillRoot(input: {
|
|
13
|
+
readonly sandbox: SandboxSession;
|
|
14
|
+
}): Promise<string>;
|
|
15
|
+
export declare function resolveSandboxSkillReadPaths(input: {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly relativePath: string;
|
|
18
|
+
readonly sandbox: SandboxSession;
|
|
19
|
+
}): Promise<readonly string[]>;
|
|
20
|
+
export declare function resolveSandboxSkillWritePath(input: {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly relativePath: string;
|
|
23
|
+
readonly sandbox: SandboxSession;
|
|
24
|
+
}): Promise<string>;
|
|
25
|
+
export declare function resolveSandboxSeedFilePath(input: {
|
|
26
|
+
readonly path: string;
|
|
27
|
+
readonly sandbox: SandboxSession;
|
|
28
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const MODEL_SKILL_ROOT=`$HOME/.agents/skills`,FALLBACK_SKILL_ROOT=`/workspace/skills`,skillRootCache=new WeakMap;function formatSkillModelPath(t){return formatSkillPath({name:t.name,relativePath:t.relativePath,root:MODEL_SKILL_ROOT})}function formatFallbackSkillPath(e){return formatSkillPath({name:e.name,relativePath:e.relativePath,root:FALLBACK_SKILL_ROOT})}async function resolveSandboxSkillRoot(e){let t=skillRootCache.get(e.sandbox);if(t!==void 0)return await t;let r=probeSandboxSkillRoot(e.sandbox);return skillRootCache.set(e.sandbox,r),await r}async function resolveSandboxSkillReadPaths(e){return[formatSkillPath({name:e.name,relativePath:e.relativePath,root:await resolveSandboxSkillRoot({sandbox:e.sandbox})})]}async function resolveSandboxSkillWritePath(e){return formatSkillPath({name:e.name,relativePath:e.relativePath,root:await resolveSandboxSkillRoot({sandbox:e.sandbox})})}async function resolveSandboxSeedFilePath(e){return e.path.startsWith(`$HOME/.agents/skills/`)?`${await resolveSandboxSkillRoot({sandbox:e.sandbox})}${e.path.slice(20)}`:e.path}function formatSkillPath(e){return`${e.root}/${e.name}/${e.relativePath}`}async function probeSandboxSkillRoot(e){try{let n=await e.run({command:`printf '%s\\n' "$HOME"`});if(n.exitCode!==0)return FALLBACK_SKILL_ROOT;let r=n.stdout.trim();return isUsableSandboxHome(r)?joinHomeSkillRoot(r):FALLBACK_SKILL_ROOT}catch{return FALLBACK_SKILL_ROOT}}function isUsableSandboxHome(e){return e.length>0&&e.startsWith(`/`)&&!e.includes(`\0`)&&!e.includes(`
|
|
2
|
+
`)&&!e.includes(`\r`)}function joinHomeSkillRoot(e){return`${e===`/`?``:e.replace(/\/+$/,``)}/.agents/skills`}export{FALLBACK_SKILL_ROOT,MODEL_SKILL_ROOT,formatFallbackSkillPath,formatSkillModelPath,resolveSandboxSeedFilePath,resolveSandboxSkillReadPaths,resolveSandboxSkillRoot,resolveSandboxSkillWritePath};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from "#compiled/zod/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Provider-reported token usage totals.
|
|
4
|
+
*
|
|
5
|
+
* The single usage shape across eve: harness accumulation
|
|
6
|
+
* (`turn-tag-state`), delegated subagent results, remote session
|
|
7
|
+
* callbacks, and usage spans all carry this type.
|
|
8
|
+
*/
|
|
9
|
+
export type TokenUsage = z.infer<typeof tokenUsageSchema>;
|
|
10
|
+
/**
|
|
11
|
+
* Zod schema for {@link TokenUsage}.
|
|
12
|
+
*
|
|
13
|
+
* Validates the `usage` field of remote session callbacks, which may come
|
|
14
|
+
* from a callee on a different eve version — unknown keys are stripped
|
|
15
|
+
* rather than rejected so a newer sender never voids the whole payload.
|
|
16
|
+
*/
|
|
17
|
+
export declare const tokenUsageSchema: z.ZodObject<{
|
|
18
|
+
cacheReadTokens: z.ZodNumber;
|
|
19
|
+
cacheWriteTokens: z.ZodNumber;
|
|
20
|
+
inputTokens: z.ZodNumber;
|
|
21
|
+
outputTokens: z.ZodNumber;
|
|
22
|
+
}, z.core.$strip>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z}from"#compiled/zod/index.js";const tokenUsageSchema=z.object({cacheReadTokens:z.number().int().nonnegative(),cacheWriteTokens:z.number().int().nonnegative(),inputTokens:z.number().int().nonnegative(),outputTokens:z.number().int().nonnegative()});export{tokenUsageSchema};
|
|
@@ -6,7 +6,7 @@ import type { JsonObject } from "#shared/json.js";
|
|
|
6
6
|
* function. These are the same options the SDK passes to every tool call.
|
|
7
7
|
*/
|
|
8
8
|
export type ToolExecuteOptions = Omit<ToolExecutionOptions<unknown>, "context">;
|
|
9
|
-
export type ToolExecuteFn<TInput = unknown, TOutput = unknown> = (input: TInput, options
|
|
9
|
+
export type ToolExecuteFn<TInput = unknown, TOutput = unknown> = (input: TInput, options: ToolExecuteOptions) => Promise<TOutput> | TOutput;
|
|
10
10
|
interface ToolDefinitionBase {
|
|
11
11
|
readonly description: string;
|
|
12
12
|
}
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.js
CHANGED
package/docs/agent-config.md
CHANGED
|
@@ -93,13 +93,30 @@ export default defineAgent({
|
|
|
93
93
|
|
|
94
94
|
Input and output budgets are checked independently. The model call that crosses
|
|
95
95
|
either limit is allowed to finish because providers only report exact token
|
|
96
|
-
usage after a call completes.
|
|
97
|
-
with
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
`
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
usage after a call completes. Before the next model call, eve pauses the
|
|
97
|
+
session and sends a deterministic continuation prompt with two options:
|
|
98
|
+
**Continue** grants a fresh budget window of the configured size (both input
|
|
99
|
+
and output windows reset together), and **Stop** ends the session gracefully
|
|
100
|
+
(`session.completed`) — declining is a user decision, not an error. A reply
|
|
101
|
+
that answers neither option re-raises the prompt; the reply stays in history
|
|
102
|
+
and is processed once the budget is granted.
|
|
103
|
+
|
|
104
|
+
Sessions that cannot reach a human — task-mode runs such as schedules and
|
|
105
|
+
subagents without input proxying — skip the prompt and fail the next model
|
|
106
|
+
call with `SESSION_TOKEN_LIMIT_REACHED`.
|
|
107
|
+
|
|
108
|
+
When `maxInputTokensPerSession` is omitted, root sessions apply a default
|
|
109
|
+
input budget of `40_000_000` provider-reported input tokens.
|
|
110
|
+
`maxOutputTokensPerSession` is unset unless configured. Setting either limit
|
|
111
|
+
to `false` uncaps that axis — the session never stops on it.
|
|
112
|
+
|
|
113
|
+
Delegated subagent sessions have no fixed default. Each child receives a
|
|
114
|
+
share of the delegating parent's remaining quota at dispatch time — the
|
|
115
|
+
remainder (limit minus accumulated usage) split evenly across the batch's
|
|
116
|
+
local subagent calls — and a completed child's usage counts against the
|
|
117
|
+
parent's quota, so a delegation tree can never outspend the budget configured
|
|
118
|
+
at its root. An authored child limit applies only when it is tighter than the
|
|
119
|
+
parent's grant; an uncapped parent delegates uncapped children.
|
|
103
120
|
|
|
104
121
|
## Workflow world
|
|
105
122
|
|
|
@@ -142,14 +159,14 @@ installed package must stay external in hosted output, list it in
|
|
|
142
159
|
|
|
143
160
|
`defineAgent` takes a few more fields, all optional. For the exported types, see the [TypeScript API](./reference/typescript-api).
|
|
144
161
|
|
|
145
|
-
| Field | Type | Default | Description
|
|
146
|
-
| -------------- | --------------------------------------- | ---------------- |
|
|
147
|
-
| `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls.
|
|
148
|
-
| `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call.
|
|
149
|
-
| `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. `maxSubagentDepth` defaults to `3`; `maxInputTokensPerSession` defaults to `40_000_000` for root sessions and
|
|
150
|
-
| `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.
|
|
151
|
-
| `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.
|
|
152
|
-
| `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.
|
|
162
|
+
| Field | Type | Default | Description |
|
|
163
|
+
| -------------- | --------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
164
|
+
| `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls. |
|
|
165
|
+
| `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
|
|
166
|
+
| `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. `maxSubagentDepth` defaults to `3`; `maxInputTokensPerSession` defaults to `40_000_000` for root sessions, and delegated subagent sessions inherit the parent's remaining quota; `maxOutputTokensPerSession` is unset unless configured; `false` uncaps a session token limit. |
|
|
167
|
+
| `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. |
|
|
168
|
+
| `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. |
|
|
169
|
+
| `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. |
|
|
153
170
|
|
|
154
171
|
`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.
|
|
155
172
|
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Chat SDK"
|
|
3
|
+
description: "Bridge any Vercel Chat SDK adapter — Slack, Discord, Telegram, WhatsApp, email, and more — to your agent through one channel, using your own credentials and state store."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The Chat SDK channel connects your agent to any [Vercel Chat SDK](https://chat-sdk.dev) adapter. You pick an adapter (`@chat-adapter/slack`, `@resend/chat-sdk-adapter`, and so on), register handlers for the messages you care about, and call `send` to hand each turn to eve. Use it to reach a surface eve does not ship a first-class channel for, or when you want to manage credentials and state with the Chat SDK's own primitives rather than [Vercel Connect](../guides/auth-and-route-protection). See [Channels](./overview) for the contract this builds on.
|
|
7
|
+
|
|
8
|
+
You supply an adapter and a state store: the adapter owns provider auth, webhook verification, and delivery, while eve owns session dispatch, streaming, typing, and human-in-the-loop. First-class channels such as [Slack](./slack) manage credentials through Vercel Connect instead — reach for whichever fits the surface you are targeting.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
Add eve, the Chat SDK core (`chat`), an adapter, and a state adapter. The example below uses the Resend email adapter with the in-memory state store:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install eve@latest chat @resend/chat-sdk-adapter @chat-adapter/state-memory
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Swap in whichever adapter matches your surface — `@chat-adapter/slack`, `@chat-adapter/discord`, `@chat-adapter/telegram`, and so on. Any Chat SDK adapter works.
|
|
19
|
+
|
|
20
|
+
## Add the channel
|
|
21
|
+
|
|
22
|
+
`chatSdkChannel` returns `{ bot, channel, send }`. Register Chat SDK handlers on `bot`, call `send` from those handlers to start or resume an eve session, and export `channel` as the module default:
|
|
23
|
+
|
|
24
|
+
```ts title="agent/channels/resend.ts"
|
|
25
|
+
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
26
|
+
import { createResendAdapter } from "@resend/chat-sdk-adapter";
|
|
27
|
+
import type { Message, Thread } from "chat";
|
|
28
|
+
import { chatSdkChannel } from "eve/channels/chat-sdk";
|
|
29
|
+
|
|
30
|
+
export const { bot, channel, send } = chatSdkChannel({
|
|
31
|
+
userName: "Resend Bot",
|
|
32
|
+
adapters: {
|
|
33
|
+
resend: createResendAdapter({
|
|
34
|
+
fromAddress: "hello@example.com",
|
|
35
|
+
fromName: "Resend Bot",
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
state: createMemoryState(),
|
|
39
|
+
streaming: false,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
bot.onNewMention(async (thread: Thread, message: Message) => {
|
|
43
|
+
await thread.subscribe();
|
|
44
|
+
await send(message.text, { thread });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
bot.onSubscribedMessage(async (thread: Thread, message: Message) => {
|
|
48
|
+
await send(message.text, { thread });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export default channel;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`adapters` is a map of adapter name to adapter instance; each entry mounts its own webhook (see below). `state` takes any Chat SDK state adapter: `createMemoryState()` is fine for local development, but use a durable adapter (Redis, Upstash, etc.) in production so thread subscriptions and inbound deduplication survive restarts. `send` accepts a plain string, an AI SDK `UserContent` array, or a `SendPayload`, and must be called from inside a Chat SDK handler — it dispatches the turn on the webhook that is currently running.
|
|
55
|
+
|
|
56
|
+
Deploy once the channel file is in place:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
eve deploy
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`eve deploy` links the project if needed and deploys to Vercel production.
|
|
63
|
+
|
|
64
|
+
## Configure the webhook route
|
|
65
|
+
|
|
66
|
+
Each adapter mounts one `POST` route at `/eve/v1/{adapterName}`, so the `resend` adapter above is served at `/eve/v1/resend`. Point your provider's webhook (the Resend inbound address, the Slack Event Subscriptions URL, etc.) at that path.
|
|
67
|
+
|
|
68
|
+
Override the base path for every adapter with `route`, or pin an individual adapter's path with `routes`:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
export const { bot, channel, send } = chatSdkChannel({
|
|
72
|
+
userName: "Resend Bot",
|
|
73
|
+
adapters: { resend: createResendAdapter({ fromAddress: "hello@example.com" }) },
|
|
74
|
+
state: createMemoryState(),
|
|
75
|
+
route: "/webhooks", // resend now mounts at /webhooks/resend
|
|
76
|
+
routes: { resend: "/webhooks/inbound-email" }, // …or pin it exactly
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Use `routes` when a provider requires a fixed URL or when you are migrating an existing endpoint without changing the provider's settings.
|
|
81
|
+
|
|
82
|
+
## How the channel handles messages
|
|
83
|
+
|
|
84
|
+
### Dispatch
|
|
85
|
+
|
|
86
|
+
You choose which Chat SDK events start a turn by registering handlers on `bot` and calling `send`:
|
|
87
|
+
|
|
88
|
+
- `bot.onNewMention(thread, message)` fires on a fresh `@mention` (or, for surfaces like email, a new inbound thread). Call `thread.subscribe()` when you want later replies in the same thread to keep reaching the agent.
|
|
89
|
+
- `bot.onSubscribedMessage(thread, message)` fires on subsequent messages in a subscribed thread.
|
|
90
|
+
- `bot.onAction`, `bot.onReaction`, and `bot.onSlashCommand` are available for adapters that emit them.
|
|
91
|
+
|
|
92
|
+
`send(input, options)` starts or resumes the eve session. The `thread` you pass determines the continuation token and the persisted channel state, so replies land back on the originating thread:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
bot.onNewMention(async (thread, message) => {
|
|
96
|
+
await send(message.text, { thread, title: "Support request" });
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`options` accepts `{ thread, auth?, title?, mode?, callback?, adapterName? }`. `title` sets the eve session's display title without changing the model message; `auth` attaches an authenticated principal to the turn.
|
|
101
|
+
|
|
102
|
+
### Delivery
|
|
103
|
+
|
|
104
|
+
The default handlers post the agent's reply back to the thread — no `events` override required. Completed assistant messages are posted as markdown (`{ markdown: … }`) so adapters render rich text and email HTML rather than a raw string.
|
|
105
|
+
|
|
106
|
+
Streaming is on by default: the channel posts an initial message and edits it as tokens arrive (`message.appended`), throttled by `streamingEditIntervalMs` (default `1000`). Set `streaming: false` for surfaces that deliver one message per turn — email, for example — so the reply posts once on completion instead of editing:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
chatSdkChannel({
|
|
110
|
+
userName: "Resend Bot",
|
|
111
|
+
adapters: { resend: createResendAdapter({ fromAddress: "hello@example.com" }) },
|
|
112
|
+
state: createMemoryState(),
|
|
113
|
+
streaming: false,
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Typing indicators post automatically where the adapter supports them: `Working…` on `turn.started`, and tool status on `actions.requested`.
|
|
118
|
+
|
|
119
|
+
### Optional capabilities degrade gracefully
|
|
120
|
+
|
|
121
|
+
Adapters do not all implement every operation. When an adapter's `startTyping` or `editMessage` throws a `NotImplementedError` (or an error with code `NOT_IMPLEMENTED`), the channel swallows it: typing indicators are skipped, and a streaming edit falls back to a single final post for the rest of the session. You never have to guard optional capabilities in your own handlers. The same predicate is exported as `isNotImplemented` if you want it in custom `events`:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { isNotImplemented } from "eve/channels/chat-sdk";
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Override any default by passing `events`. Handlers receive `(eventData, channel, ctx)`, with the rebuilt Chat SDK thread on `channel.thread`:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
chatSdkChannel({
|
|
131
|
+
userName: "Resend Bot",
|
|
132
|
+
adapters: { resend: createResendAdapter({ fromAddress: "hello@example.com" }) },
|
|
133
|
+
state: createMemoryState(),
|
|
134
|
+
events: {
|
|
135
|
+
"message.completed"(eventData, channel) {
|
|
136
|
+
if (eventData.finishReason === "tool-calls" || !eventData.message || !channel.thread) return;
|
|
137
|
+
return channel.thread.post({ markdown: eventData.message });
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Human-in-the-loop (HITL)
|
|
144
|
+
|
|
145
|
+
HITL prompts render as a Chat SDK `Card` with buttons. Button clicks resume the parked session automatically — the channel wires `bot.onAction` for you. Change the action-id prefix with `inputActionPrefix` (default `eve_input:`) if your app already uses it, and provide `resolveInputAuth` to carry user or tenant auth across the resume:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
chatSdkChannel({
|
|
149
|
+
userName: "Support Bot",
|
|
150
|
+
adapters: { slack: createSlackAdapter() },
|
|
151
|
+
state: createMemoryState(),
|
|
152
|
+
resolveInputAuth: (event) => ({
|
|
153
|
+
authenticator: "slack",
|
|
154
|
+
principalType: "user",
|
|
155
|
+
principalId: event.user?.userId ?? "unknown",
|
|
156
|
+
attributes: {},
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Proactive sessions
|
|
162
|
+
|
|
163
|
+
Start a session without an inbound webhook through `channel.receive({ message, target, auth })` — from a schedule `run` handler, or `args.receive(channel, ...)` from another channel. The target is a serialized Chat SDK thread, or `{ threadId, adapterName }` when you only have a provider-native thread id:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
await channel.receive({
|
|
167
|
+
message: "Your weekly digest is ready.",
|
|
168
|
+
target: { adapterName: "resend", threadId: "resend:user@example.com" },
|
|
169
|
+
auth: null,
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Attachments
|
|
174
|
+
|
|
175
|
+
`send` takes plain text or an AI SDK `UserContent` array. To forward a Chat SDK message's attachments, convert it with `messageToUserContent`, which returns `message.text` when there are no attachments and a `UserContent` array (text plus one file part per attachment URL) when there are:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { messageToUserContent } from "eve/channels/chat-sdk";
|
|
179
|
+
|
|
180
|
+
bot.onNewMention(async (thread, message) => {
|
|
181
|
+
await send(messageToUserContent(message), { thread });
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
See [File uploads](./custom#file-uploads) for how eve stages remote file URLs before the model call.
|
|
186
|
+
|
|
187
|
+
## Configuration reference
|
|
188
|
+
|
|
189
|
+
| Option | Default | Purpose |
|
|
190
|
+
| ------------------------- | ------------ | ------------------------------------------------------------------------ |
|
|
191
|
+
| `adapters` | — | Map of adapter name to Chat SDK adapter instance. One webhook per entry. |
|
|
192
|
+
| `state` | — | Chat SDK state adapter for subscriptions, locks, and dedupe. |
|
|
193
|
+
| `userName` | — | Display name for the bot (a standard Chat SDK `ChatConfig` field). |
|
|
194
|
+
| `route` | `/eve/v1` | Base path for generated adapter webhooks (`{route}/{adapter}`). |
|
|
195
|
+
| `routes` | — | Per-adapter path overrides for fixed or migrated webhook URLs. |
|
|
196
|
+
| `streaming` | `true` | Post-then-edit streaming. Set `false` for one-message-per-turn surfaces. |
|
|
197
|
+
| `streamingEditIntervalMs` | `1000` | Minimum interval between streaming edits. |
|
|
198
|
+
| `events` | built-in | Per-event handlers. A supplied handler replaces that built-in default. |
|
|
199
|
+
| `inputActionPrefix` | `eve_input:` | Prefix for default HITL button action ids. |
|
|
200
|
+
| `resolveInputAuth` | `null` | Auth resolver applied when a HITL button click resumes a session. |
|
|
201
|
+
| `webhook` | — | Extra Chat SDK webhook options (eve owns `waitUntil`). |
|
|
202
|
+
|
|
203
|
+
Any other Chat SDK `ChatConfig` field (for example `concurrency`) is accepted and passed through.
|
|
204
|
+
|
|
205
|
+
## What to read next
|
|
206
|
+
|
|
207
|
+
- [Channels overview](./overview): the channel contract and every built-in channel
|
|
208
|
+
- [Custom channels](./custom): build a channel for any surface with `defineChannel`
|
|
209
|
+
- [Auth & route protection](../guides/auth-and-route-protection): authenticating inbound traffic
|