eve 0.13.4 → 0.13.6
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 +25 -0
- package/dist/src/channel/schedule-auth.d.ts +7 -0
- package/dist/src/channel/schedule-auth.js +1 -0
- package/dist/src/channel/schedule.d.ts +2 -6
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/channel/send.d.ts +3 -1
- package/dist/src/channel/send.js +1 -1
- package/dist/src/channel/types.d.ts +6 -0
- package/dist/src/chunks/{use-eve-agent-C8UVUMA4.js → use-eve-agent-8X2UMr8q.js} +31 -20
- package/dist/src/chunks/{use-eve-agent-BLv-Mj5g.js → use-eve-agent-9ZNiSFMb.js} +31 -20
- package/dist/src/cli/dev/tui/blocks.d.ts +1 -1
- package/dist/src/cli/dev/tui/blocks.js +1 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.d.ts +5 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
- package/dist/src/cli/dev/tui/prompt-commands.d.ts +7 -7
- package/dist/src/cli/dev/tui/prompt-commands.js +2 -2
- package/dist/src/cli/dev/tui/remote-auth-command.d.ts +11 -0
- package/dist/src/cli/dev/tui/remote-auth-command.js +3 -0
- package/dist/src/cli/dev/tui/remote-auth-result.d.ts +5 -0
- package/dist/src/cli/dev/tui/remote-auth-result.js +2 -1
- package/dist/src/cli/dev/tui/remote-auth.d.ts +30 -0
- package/dist/src/cli/dev/tui/remote-auth.js +1 -0
- package/dist/src/cli/dev/tui/remote-connection-probe.d.ts +3 -1
- package/dist/src/cli/dev/tui/remote-connection-probe.js +1 -1
- package/dist/src/cli/dev/tui/remote-connection-types.d.ts +2 -1
- package/dist/src/cli/dev/tui/remote-connection.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +18 -1
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +4 -4
- package/dist/src/cli/dev/tui/setup-commands.js +2 -2
- package/dist/src/cli/dev/tui/setup-issues.d.ts +1 -1
- package/dist/src/cli/dev/tui/setup-issues.js +1 -1
- package/dist/src/cli/dev/tui/status-line.d.ts +6 -14
- package/dist/src/cli/dev/tui/status-line.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +8 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +9 -9
- package/dist/src/cli/dev/tui/test/index.d.ts +1 -0
- package/dist/src/cli/dev/tui/test/index.js +1 -1
- package/dist/src/cli/dev/tui/tui.d.ts +1 -1
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/cli/dev/tui/vercel-trusted-sources.js +1 -1
- package/dist/src/cli/run.js +1 -1
- package/dist/src/client/agent-info-error.d.ts +17 -0
- package/dist/src/client/agent-info-error.js +1 -0
- package/dist/src/client/client.d.ts +4 -0
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/index.d.ts +1 -0
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/client/ndjson.js +3 -3
- package/dist/src/context/keys.d.ts +1 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/evals/cli/eval-client.js +1 -1
- package/dist/src/execution/delegated-parent-notification.js +1 -1
- package/dist/src/execution/durable-session-store.js +1 -1
- package/dist/src/execution/eve-workflow-attributes.d.ts +8 -0
- package/dist/src/execution/eve-workflow-attributes.js +1 -1
- package/dist/src/execution/hook-ownership.d.ts +7 -0
- package/dist/src/execution/hook-ownership.js +1 -0
- package/dist/src/execution/ndjson-stream.d.ts +19 -0
- package/dist/src/execution/ndjson-stream.js +3 -0
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/subagent-adapter.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -3
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/action-result-helpers.d.ts +2 -3
- package/dist/src/harness/action-result-helpers.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/provider-tools.d.ts +4 -27
- package/dist/src/harness/provider-tools.js +1 -1
- package/dist/src/harness/step-hooks.d.ts +0 -13
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tool-output-serialization.d.ts +17 -0
- package/dist/src/harness/tool-output-serialization.js +1 -0
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/workflow/configure-world.js +1 -1
- package/dist/src/internal/workflow/queue-namespace.d.ts +0 -1
- package/dist/src/internal/workflow/queue-namespace.js +1 -1
- package/dist/src/internal/workflow/runtime.d.ts +4 -0
- package/dist/src/internal/workflow/runtime.js +1 -0
- package/dist/src/internal/workflow-bundle/builder-support.js +6 -6
- package/dist/src/internal/workflow-bundle/builder.js +2 -2
- package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-core-shim.d.ts +10 -8
- package/dist/src/public/channels/github/dispatch.d.ts +22 -1
- package/dist/src/public/channels/github/dispatch.js +1 -1
- package/dist/src/public/channels/github/githubChannel.d.ts +21 -3
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/github/inbound.d.ts +46 -1
- package/dist/src/public/channels/github/inbound.js +2 -2
- package/dist/src/public/channels/github/index.d.ts +1 -1
- package/dist/src/public/channels/github/state.d.ts +3 -1
- package/dist/src/public/channels/github/state.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/runtime/connections/callback-route.js +1 -1
- package/dist/src/runtime/framework-tools/web-search.d.ts +2 -2
- package/dist/src/runtime/framework-tools/web-search.js +1 -1
- package/dist/src/runtime/session-callback-route.js +1 -1
- package/dist/src/services/dev-client/request-headers.d.ts +2 -0
- package/dist/src/services/dev-client/request-headers.js +1 -1
- package/dist/src/services/dev-client/vercel-auth-error.d.ts +12 -14
- package/dist/src/services/dev-client/vercel-auth-error.js +9 -2
- package/dist/src/setup/flows/install-vercel-cli.d.ts +1 -1
- package/dist/src/setup/flows/login.d.ts +3 -1
- package/dist/src/setup/flows/login.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/vercel-deployment.d.ts +12 -5
- package/dist/src/setup/vercel-deployment.js +1 -1
- package/dist/src/setup/vercel-project-api.d.ts +13 -2
- package/dist/src/setup/vercel-project-api.js +1 -1
- package/dist/src/setup/vercel-project.d.ts +5 -1
- package/dist/src/setup/vercel-project.js +0 -0
- package/dist/src/setup/verified-remote-client.js +1 -1
- package/dist/src/shared/empty-delivery.d.ts +3 -0
- package/dist/src/shared/empty-delivery.js +1 -0
- 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/channels/custom.mdx +1 -1
- package/docs/channels/eve.mdx +1 -1
- package/docs/channels/github.mdx +13 -1
- package/docs/channels/slack.mdx +1 -1
- package/docs/concepts/execution-model-and-durability.md +2 -0
- package/docs/guides/client/continuations.mdx +4 -0
- package/docs/guides/client/streaming.mdx +6 -0
- package/docs/guides/dev-tui.md +22 -12
- package/docs/guides/frontend/overview.mdx +28 -8
- package/docs/schedules.mdx +5 -3
- package/docs/tools/overview.mdx +2 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isNotFoundApiFailure,normalizeVercelApiResult}from"./vercel-api-failure.js";import{
|
|
1
|
+
import{object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isForbiddenApiFailure,isNotFoundApiFailure,normalizeVercelApiResult}from"./vercel-api-failure.js";import{captureVercel}from"#setup/primitives/index.js";const VercelDeploymentSchema=object({ownerId:string().min(1),projectId:string().min(1),name:string().min(1),target:string().nullable().optional(),customEnvironment:object({slug:string().min(1)}).nullable().optional()}),verifiedVercelTargetBrand=Symbol(`VerifiedVercelTarget`),defaultDeps={captureVercel};function environmentForDeployment(e){return e.customEnvironment!==null&&e.customEnvironment!==void 0?e.customEnvironment.slug:e.target===`production`?`production`:`preview`}async function resolveVercelDeployment(e){let t={...defaultDeps,...e.deps},n=e.source,r=e.scope??n?.orgId,i=normalizeVercelApiResult(await t.captureVercel([`api`,`/v13/deployments/${encodeURIComponent(e.host)}`,...r===void 0?[]:[`--scope`,r],`--raw`],{cwd:e.workspaceRoot,nonInteractive:!0,signal:e.signal,timeoutMs:1e4}));if(!i.ok)return e.signal?.aborted===!0||i.failure.errno===`ABORT_ERR`?{kind:`cancelled`}:isNotFoundApiFailure(i.failure)?{kind:`not-found`}:isForbiddenApiFailure(i.failure)?{kind:`forbidden`}:{kind:`failed`,failure:{cause:`vercel`,failure:i.failure}};let a;try{a=JSON.parse(i.stdout)}catch{return{kind:`failed`,failure:{cause:`invalid-json`,message:`Vercel returned invalid deployment JSON.`}}}let o=VercelDeploymentSchema.safeParse(a);if(!o.success)return{kind:`failed`,failure:{cause:`invalid-shape`,message:`Vercel returned an invalid deployment response.`}};if(n!==void 0&&o.data.projectId!==n.projectId)return{kind:`project-mismatch`,expectedProjectId:n.projectId,actualProjectId:o.data.projectId};let s=`https://${new URL(`https://${e.host}`).host}`;return{kind:`resolved`,target:{[verifiedVercelTargetBrand]:!0,origin:s,deployment:{provider:`vercel`,ownerId:o.data.ownerId,projectId:o.data.projectId,projectName:o.data.name,environment:environmentForDeployment(o.data)}}}}export{resolveVercelDeployment};
|
|
@@ -2,6 +2,8 @@ import { type VercelCaptureFailure } from "#setup/primitives/index.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { VercelProjectOperationOptions } from "./project-resolution.js";
|
|
4
4
|
export type { VercelProjectOperationOptions };
|
|
5
|
+
/** Shared deadline for Vercel project list and exact-lookup requests. */
|
|
6
|
+
export declare const VERCEL_PROJECT_REQUEST_TIMEOUT_MS = 15000;
|
|
5
7
|
declare const VercelTeamListEntrySchema: z.ZodObject<{
|
|
6
8
|
name: z.ZodString;
|
|
7
9
|
slug: z.ZodString;
|
|
@@ -13,6 +15,11 @@ declare const VercelProjectListEntrySchema: z.ZodObject<{
|
|
|
13
15
|
id: z.ZodString;
|
|
14
16
|
}, z.core.$strip>;
|
|
15
17
|
export type VercelProjectListEntry = z.infer<typeof VercelProjectListEntrySchema>;
|
|
18
|
+
/** One ranked Vercel project search page and its optional continuation cursor. */
|
|
19
|
+
export interface VercelProjectSearchPage {
|
|
20
|
+
readonly projects: VercelProjectListEntry[];
|
|
21
|
+
readonly next?: number;
|
|
22
|
+
}
|
|
16
23
|
/** Parses one JSON response captured from the Vercel CLI. */
|
|
17
24
|
export declare function parseVercelJson(stdout: string, description: string): unknown;
|
|
18
25
|
/** Converts a scoped API denial into the Vercel re-authentication action. */
|
|
@@ -21,5 +28,9 @@ export declare function requireVercelTeamAccess(failure: VercelCaptureFailure):
|
|
|
21
28
|
export declare function listTeams(projectRoot: string, options?: VercelProjectOperationOptions): Promise<VercelTeamListEntry[]>;
|
|
22
29
|
/** Lists the 20 most recent Vercel projects in one account scope. */
|
|
23
30
|
export declare function listRecentProjects(projectRoot: string, team: string, options?: VercelProjectOperationOptions): Promise<VercelProjectListEntry[]>;
|
|
24
|
-
/**
|
|
25
|
-
export declare function
|
|
31
|
+
/** Ranks exact and prefix project-name matches ahead of substring matches. */
|
|
32
|
+
export declare function rankProjectSearchResults(projects: readonly VercelProjectListEntry[], query: string): VercelProjectListEntry[];
|
|
33
|
+
/** Searches one ranked Vercel project page and retains its continuation cursor. */
|
|
34
|
+
export declare function searchProjects(projectRoot: string, team: string, query: string, options?: VercelProjectOperationOptions & {
|
|
35
|
+
readonly next?: number;
|
|
36
|
+
}): Promise<VercelProjectSearchPage>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{array,boolean,number,object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isForbiddenApiFailure}from"./vercel-api-failure.js";import{captureVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";const VercelTeamListEntrySchema=object({name:string(),slug:string(),current:boolean()}),VercelProjectListEntrySchema=object({name:string(),id:string()}),VercelPaginationSchema=object({next:number().int().nonnegative().nullable().optional()}),VercelTeamPageSchema=object({teams:array(VercelTeamListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.teams,next:e.pagination?.next??void 0})),VercelProjectPageSchema=object({projects:array(VercelProjectListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.projects,next:e.pagination?.next??void 0}));function parseVercelJson(e,t){try{return JSON.parse(e)}catch{throw Error(`Could not parse ${t} JSON from Vercel CLI output.`)}}async function drainPages(e,t,n){let r=new Map,i=new Set,a;for(;;){let o=await n(a);for(let e of o.items)r.set(t(e),e);if(o.next===void 0)return[...r.values()];if(i.has(o.next))throw Error(`Vercel returned a repeated pagination cursor for ${e}.`);i.add(o.next),a=o.next}}function requireVercelTeamAccess(e){let t=e.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-forbidden`,command:`vercel login`,reason:`Vercel denied access to this scope.${t?` ${t}`:``} Re-authenticate (for example to complete a team's SSO) or switch to a team you can access.`})}async function fetchTeamPage(e,t,n){let r=[`teams`,`ls`,`--format`,`json`];n!==void 0&&r.push(`--next`,String(n));let i=await captureVercel(r,{cwd:e,signal:t.signal});if(t.signal?.throwIfAborted(),!i.ok)throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not list Vercel teams. ${i.failure.message}`);let s=VercelTeamPageSchema.safeParse(parseVercelJson(i.stdout,`teams`));if(!s.success)throw Error(`Could not read teams from Vercel CLI JSON output.`);return s.data}async function listTeams(e,t={}){return drainPages(`Vercel teams`,e=>e.slug,n=>fetchTeamPage(e,t,n))}async function fetchProjectPage(e,t,n){let r=[`project`,`ls`,`--format`,`json`,`--scope`,t];n.search!==void 0&&r.push(`--filter`,n.search),n.next!==void 0&&r.push(`--next`,String(n.next));let i=await captureVercel(r,{cwd:e,signal:n.signal,timeoutMs:
|
|
1
|
+
import{array,boolean,number,object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isForbiddenApiFailure}from"./vercel-api-failure.js";import{captureVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";const VERCEL_PROJECT_REQUEST_TIMEOUT_MS=15e3,VercelTeamListEntrySchema=object({name:string(),slug:string(),current:boolean()}),VercelProjectListEntrySchema=object({name:string(),id:string()}),VercelPaginationSchema=object({next:number().int().nonnegative().nullable().optional()}),VercelTeamPageSchema=object({teams:array(VercelTeamListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.teams,next:e.pagination?.next??void 0})),VercelProjectPageSchema=object({projects:array(VercelProjectListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.projects,next:e.pagination?.next??void 0}));function parseVercelJson(e,t){try{return JSON.parse(e)}catch{throw Error(`Could not parse ${t} JSON from Vercel CLI output.`)}}async function drainPages(e,t,n){let r=new Map,i=new Set,a;for(;;){let o=await n(a);for(let e of o.items)r.set(t(e),e);if(o.next===void 0)return[...r.values()];if(i.has(o.next))throw Error(`Vercel returned a repeated pagination cursor for ${e}.`);i.add(o.next),a=o.next}}function requireVercelTeamAccess(e){let t=e.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-forbidden`,command:`vercel login`,reason:`Vercel denied access to this scope.${t?` ${t}`:``} Re-authenticate (for example to complete a team's SSO) or switch to a team you can access.`})}async function fetchTeamPage(e,t,n){let r=[`teams`,`ls`,`--format`,`json`];n!==void 0&&r.push(`--next`,String(n));let i=await captureVercel(r,{cwd:e,signal:t.signal});if(t.signal?.throwIfAborted(),!i.ok)throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not list Vercel teams. ${i.failure.message}`);let s=VercelTeamPageSchema.safeParse(parseVercelJson(i.stdout,`teams`));if(!s.success)throw Error(`Could not read teams from Vercel CLI JSON output.`);return s.data}async function listTeams(e,t={}){return drainPages(`Vercel teams`,e=>e.slug,n=>fetchTeamPage(e,t,n))}async function fetchProjectPage(e,t,n){let r=[`project`,`ls`,`--format`,`json`,`--scope`,t];n.search!==void 0&&r.push(`--filter`,n.search),n.next!==void 0&&r.push(`--next`,String(n.next));let i=await captureVercel(r,{cwd:e,signal:n.signal,timeoutMs:VERCEL_PROJECT_REQUEST_TIMEOUT_MS});if(n.signal?.throwIfAborted(),!i.ok)throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not list Vercel projects in ${t}. ${i.failure.message}`);let s=VercelProjectPageSchema.safeParse(parseVercelJson(i.stdout,`projects`));if(!s.success)throw Error(`Could not read projects from Vercel CLI JSON output.`);return s.data}async function listRecentProjects(e,t,n={}){return(await fetchProjectPage(e,t,n)).items}function projectSearchRank(e,t){let n=e.name.toLowerCase(),r=t.toLowerCase();return n===r?0:n.startsWith(r)?1:2}function rankProjectSearchResults(e,t){let n=t.trim();return[...e].sort((e,t)=>projectSearchRank(e,n)-projectSearchRank(t,n))}async function searchProjects(e,t,n,r={}){let i=n.trim();if(i.length===0)throw Error(`Project search query cannot be empty.`);let a=await fetchProjectPage(e,t,{...r,search:i}),o=rankProjectSearchResults(a.items,i);return a.next===void 0?{projects:o}:{projects:o,next:a.next}}export{VERCEL_PROJECT_REQUEST_TIMEOUT_MS,listRecentProjects,listTeams,parseVercelJson,rankProjectSearchResults,requireVercelTeamAccess,searchProjects};
|
|
@@ -8,6 +8,10 @@ export interface PickProjectOptions extends VercelProjectOperationOptions {
|
|
|
8
8
|
/** Whether an empty project list may fall back to entering a name to create. */
|
|
9
9
|
allowCreateWhenEmpty?: boolean;
|
|
10
10
|
}
|
|
11
|
+
export interface PickTeamOptions extends VercelProjectOperationOptions {
|
|
12
|
+
/** Builds the team selector heading from the current team's display name. */
|
|
13
|
+
selectMessage?: (currentTeam: string) => string;
|
|
14
|
+
}
|
|
11
15
|
export declare function unresolvedProject(): ProjectResolution;
|
|
12
16
|
/** Resolves the linked project id from a resolution, if any. */
|
|
13
17
|
export declare function projectIdFromResolution(project: ProjectResolution): string | undefined;
|
|
@@ -74,7 +78,7 @@ export declare function validateTeam(prompter: Prompter, projectRoot: string, te
|
|
|
74
78
|
* zero or one team the current scope is used without prompting; otherwise the
|
|
75
79
|
* user filters and chooses from the list with a single-selection picker.
|
|
76
80
|
*/
|
|
77
|
-
export declare function pickTeam(prompter: Prompter, projectRoot: string, presetTeam: string | undefined, options?:
|
|
81
|
+
export declare function pickTeam(prompter: Prompter, projectRoot: string, presetTeam: string | undefined, options?: PickTeamOptions): Promise<string>;
|
|
78
82
|
/** Picks an existing project under a team, or a name to create when none exist. */
|
|
79
83
|
export declare function pickProject(prompter: Prompter, projectRoot: string, team: string, options?: PickProjectOptions): Promise<ResolvedVercelProjectSpec>;
|
|
80
84
|
/** Returns a project name for a new Vercel project, prompting when the default exists. */
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolveVercelDeployment}from"./vercel-deployment.js";import{
|
|
1
|
+
import{resolveVercelDeployment}from"./vercel-deployment.js";import{resolveDevelopmentOidcToken}from"#services/dev-client/request-headers.js";import{resolveRemoteDevelopmentClientOptions}from"#services/dev-client/client-options.js";import{createDevelopmentCredentialGate}from"#services/dev-client/credential-gate.js";const defaultDeps={resolveVercelDeployment,resolveDevelopmentOidcToken};async function resolveVerifiedRemoteDevelopmentClient(e){let t={...defaultDeps,...e.deps},r=createDevelopmentCredentialGate(e.serverUrl),i=await t.resolveVercelDeployment({workspaceRoot:e.workspaceRoot,host:new URL(e.serverUrl).host});if(i.kind===`resolved`){let{ownerId:e,projectId:n}=i.target.deployment;r.authorize({target:i.target,resolveToken:()=>t.resolveDevelopmentOidcToken({ownerId:e,projectId:n})})}return{options:resolveRemoteDevelopmentClientOptions({serverUrl:e.serverUrl,credentials:r}),lastOidcTokenFailure:r.lastTokenFailure}}export{resolveVerifiedRemoteDevelopmentClient};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const EMPTY_DELIVERY_SENTINEL = "<eve-empty-delivery/>";
|
|
2
|
+
export declare const CONDITIONAL_DELIVERY_INSTRUCTION = "Conditional delivery\nOnly when the current task explicitly makes delivery conditional and there is nothing to report, reply with exactly <eve-empty-delivery/> and no other text. Do not use this marker for ordinary conversations, after input or approval responses, or merely because you have no additional commentary. Never return an empty response; use the marker to intentionally deliver nothing.";
|
|
3
|
+
export declare function hasEmptyDeliverySentinel(text: string | null | undefined): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const EMPTY_DELIVERY_SENTINEL=`<eve-empty-delivery/>`,CONDITIONAL_DELIVERY_INSTRUCTION=`Conditional delivery\nOnly when the current task explicitly makes delivery conditional and there is nothing to report, reply with exactly ${EMPTY_DELIVERY_SENTINEL} and no other text. Do not use this marker for ordinary conversations, after input or approval responses, or merely because you have no additional commentary. Never return an empty response; use the marker to intentionally deliver nothing.`;function hasEmptyDeliverySentinel(e){return e?.includes(`<eve-empty-delivery/>`)??!1}export{CONDITIONAL_DELIVERY_INSTRUCTION,EMPTY_DELIVERY_SENTINEL,hasEmptyDeliverySentinel};
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.js
CHANGED
package/docs/channels/custom.mdx
CHANGED
|
@@ -225,7 +225,7 @@ defineChannel<{ ref: string | null }>({
|
|
|
225
225
|
});
|
|
226
226
|
```
|
|
227
227
|
|
|
228
|
-
|
|
228
|
+
At the next workflow boundary, the runtime claims the new park hook before releasing the old token. If another active session already owns the new token, the re-keying session fails instead of taking it over. After a successful re-key, inbound deliveries still addressed to the old token are dropped, so coordinate with your senders to use the new token.
|
|
229
229
|
|
|
230
230
|
## File uploads
|
|
231
231
|
|
package/docs/channels/eve.mdx
CHANGED
|
@@ -39,7 +39,7 @@ Stream that session's events as newline-delimited JSON (`application/x-ndjson; c
|
|
|
39
39
|
```bash
|
|
40
40
|
curl -N https://<deployment>/eve/v1/session/ses_01h.../stream
|
|
41
41
|
# {"type":"turn.started",...}
|
|
42
|
-
# {"type":"
|
|
42
|
+
# {"type":"message.appended","data":{"messageDelta":"It is ",...}}
|
|
43
43
|
# {"type":"message.completed",...}
|
|
44
44
|
```
|
|
45
45
|
|
package/docs/channels/github.mdx
CHANGED
|
@@ -32,7 +32,7 @@ GITHUB_APP_SLUG=... # supplies botName when it is not set in config
|
|
|
32
32
|
|
|
33
33
|
`appId`/`privateKey`/`webhookSecret` also take a lazy resolver function if you'd rather fetch them on demand.
|
|
34
34
|
|
|
35
|
-
Point the GitHub App webhook URL at `https://<deployment>/eve/v1/github`. For mention-driven turns, subscribe to `issue_comment` and `pull_request_review_comment`; add `issues`
|
|
35
|
+
Point the GitHub App webhook URL at `https://<deployment>/eve/v1/github`. For mention-driven turns, subscribe to `issue_comment` and `pull_request_review_comment`; add `issues`, `pull_request`, `check_suite`, `check_run`, or `workflow_run` if you wire up their opt-in hooks. A comment that `@mention`s `botName` starts a turn.
|
|
36
36
|
|
|
37
37
|
## How the channel handles messages
|
|
38
38
|
|
|
@@ -50,9 +50,21 @@ export default githubChannel({
|
|
|
50
50
|
// Opt in; no default dispatch on these events.
|
|
51
51
|
onIssue: (ctx, issue) => (issue.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null),
|
|
52
52
|
onPullRequest: (ctx, pr) => (pr.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null),
|
|
53
|
+
onCheckSuite: (ctx, suite) =>
|
|
54
|
+
suite.action === "completed" &&
|
|
55
|
+
suite.conclusion === "failure" &&
|
|
56
|
+
suite.app.slug === "github-actions" &&
|
|
57
|
+
suite.pullRequests.length > 0
|
|
58
|
+
? {
|
|
59
|
+
auth: defaultGitHubAuth(ctx),
|
|
60
|
+
context: [`Triage failed check suite ${suite.checkSuiteId} at ${suite.headSha}.`],
|
|
61
|
+
}
|
|
62
|
+
: null,
|
|
53
63
|
});
|
|
54
64
|
```
|
|
55
65
|
|
|
66
|
+
The CI hooks expose normalized `action`, `status`, `conclusion`, `app.slug`, `headSha`, and `pullRequests` fields, plus `checkSuiteId`, `checkRunId`, or `workflowRunId`. `workflow_run` is a GitHub Actions-only event, so its normalized `app.slug` is `"github-actions"`. A dispatched CI turn is anchored to the first number in `pullRequests`; the hook still runs when the array is empty, but it must return `null` because there is no issue or PR thread for the session.
|
|
67
|
+
|
|
56
68
|
### Delivery
|
|
57
69
|
|
|
58
70
|
When a turn starts, the channel adds an `eyes` reaction to the triggering comment (turn this off with `progress: { reactions: false }`). The reply comes back as a comment, on the timeline or in the review thread, and splits across multiple comments when it runs long. If the turn fails, you get a short error comment carrying an error id.
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -80,7 +80,7 @@ export default slackChannel({
|
|
|
80
80
|
|
|
81
81
|
The default handlers reply in-thread and show progress. Typing indicators post automatically: `Thinking…` on inbound, `Working…` on `turn.started`, a truncated reasoning snippet on `reasoning.appended`, and tool status on `actions.requested`. Reasoning snippets build progressively: extensions of at least four characters appear immediately, while smaller streamed deltas use the five-second refresh interval to avoid one Slack request per token. Override `events["reasoning.appended"]` if you prefer generic wording. Override `onAppMention` or the `events` handlers to customize.
|
|
82
82
|
|
|
83
|
-
When a session starts without a `threadTs` (say, from a schedule or `receive(slack, ...)`), it
|
|
83
|
+
When a session starts without a `threadTs` (say, from a schedule or `receive(slack, ...)`), eve gives it a unique temporary continuation token. The first agent post anchors the session to the Slack message timestamp, and later posts and mentions resume that same session. Pass `initialMessage` with a `Card` to land a structured anchor first instead. `threadTs` and `initialMessage` are mutually exclusive.
|
|
84
84
|
|
|
85
85
|
The example below overrides `onAppMention` to gate on an authored message and posts the completed reply to the thread. Event handlers receive `(eventData, channel, ctx)`, with Slack platform handles on `channel.thread` and `channel.slack`:
|
|
86
86
|
|
|
@@ -54,6 +54,8 @@ Some work has to wait, including a human approving a [tool](../tools), an intera
|
|
|
54
54
|
|
|
55
55
|
eve does not maintain a durable FIFO queue of user messages for a session. The `continuationToken` is a resume handle for the session's current workflow hook, not a general message-queue address.
|
|
56
56
|
|
|
57
|
+
Only one active session can own a continuation token. When a session starts with a token, eve commits the park hook before processing its first turn and fails a competing session if another run already owns that token. A tokenless session claims its token after the first turn establishes one. Competing input is not forwarded to the owner.
|
|
58
|
+
|
|
57
59
|
When a session is waiting, a delivery to the current continuation token wakes the session and starts the next turn. When a turn is already active, the hook may accept additional deliveries, but the runtime only drains them at specific workflow boundaries. If more than one delivery is ready when the driver checks, eve may fold them into the next turn; that drain is best-effort and depends on workflow and transport timing.
|
|
58
60
|
|
|
59
61
|
So don't rely on concurrent sends to the same session behaving like a typical ordered chat queue. For deterministic behavior, send one user turn at a time and wait for `session.waiting` before sending the next message to the same session. If your channel can receive bursts while the agent is working, keep your own per-session queue in the channel or app layer, then deliver the next message after the session parks again. Separate sessions still run independently.
|
|
@@ -35,6 +35,8 @@ interface SessionState {
|
|
|
35
35
|
|
|
36
36
|
The continuation token resumes the conversation. The session ID and stream index let the client reconnect to the right stream position without replaying events it already consumed.
|
|
37
37
|
|
|
38
|
+
`SessionState` is a cursor, not a chat transcript. If your app shows historical messages, persist the stream events separately and store them under your own chat or thread ID. On reload, pass the saved `SessionState` back to `client.session(savedState)` or `useEveAgent({ initialSession })`, and pass the saved events to your renderer or `useEveAgent({ initialEvents })`.
|
|
39
|
+
|
|
38
40
|
## Resume a saved session
|
|
39
41
|
|
|
40
42
|
Pass the saved state back into `client.session()`:
|
|
@@ -97,6 +99,8 @@ await save("support", support.state);
|
|
|
97
99
|
|
|
98
100
|
The shared `Client` only owns host, auth, headers, and reconnect settings. Conversation state lives on each `ClientSession`.
|
|
99
101
|
|
|
102
|
+
For a multi-chat UI, this usually means one application row per chat with two eve fields: the latest `SessionState` and the ordered event log for rendering. Do not reuse one `ClientSession` across sidebar conversations, and do not treat `streamIndex` as your database row index; it is only the remote stream cursor for that eve session.
|
|
103
|
+
|
|
100
104
|
## Reconnect an existing stream
|
|
101
105
|
|
|
102
106
|
When a session already has a `sessionId`, `session.stream()` reattaches to its stream from the saved cursor. Resuming a saved `SessionState` after a restart is the common reason to do this:
|
|
@@ -76,6 +76,12 @@ The most common UI events are:
|
|
|
76
76
|
|
|
77
77
|
For the complete event table, see [Sessions, runs & streaming](../../concepts/sessions-runs-and-streaming).
|
|
78
78
|
|
|
79
|
+
## Authorization pauses
|
|
80
|
+
|
|
81
|
+
`authorization.required` is different from the normal `session.waiting` boundary. It means a connection needs OAuth or another authorization challenge before the parked turn can continue. Chat UIs should render the authorization prompt, disable ordinary text input for that session, and persist the event with the rest of the chat history.
|
|
82
|
+
|
|
83
|
+
If you support refresh while an authorization prompt is pending, keep the session cursor from the started session and rehydrate the saved events on load. Do not treat a missing `session.waiting` after `authorization.required` as a finished conversation; the callback or a structured decline should resume the same eve session.
|
|
84
|
+
|
|
79
85
|
## Reconnection
|
|
80
86
|
|
|
81
87
|
The client reconnects after transient stream disconnects. It resumes from the number of events already consumed in the current session:
|
package/docs/guides/dev-tui.md
CHANGED
|
@@ -24,23 +24,25 @@ The conversation streams straight into your terminal's normal scrollback, so you
|
|
|
24
24
|
|
|
25
25
|
Each turn renders without boxes. A colored gutter glyph marks who is speaking, tool calls collapse to a one-line summary (`✓ get_weather city="SF" → 73°F`), and a subagent's work is indented beneath its `◆` header. When input is ready, the prompt stays bare until you type. A green circle-dot pulses while the agent is waiting to answer and disappears when reasoning or answer content begins.
|
|
26
26
|
|
|
27
|
-
A persistent line beneath the prompt or status shows the model, the session's token flow (`↑ 394.4K ↓ 4.3K`), the linked Vercel project
|
|
27
|
+
A persistent line beneath the prompt or status shows the model, the session's token flow (`↑ 394.4K ↓ 4.3K`), the linked Vercel project, and a yellow `/deploy pending` marker once a channel added this session still needs `/deploy`. The Vercel segment stays hidden until the directory is linked. Remote sessions lead with a padded `↗ project (environment)` badge, or the host when Vercel cannot resolve the deployment. The badge is gray while checking or unavailable, yellow while authentication is required or failed, and blue when connected. Remote status lines omit AI Gateway endpoint state.
|
|
28
28
|
|
|
29
29
|
Errors render compactly with docs links highlighted. A code bug escaping your agent's own code shows its stack trace dim beneath the error headline. Dev-server rebuilds condense into one status row that updates in place (`tui/setup-panel.ts changed · rebuilding…`, then `· rebuilt`); only the latest rebuild shows, and paths shrink to their last two components.
|
|
30
30
|
|
|
31
31
|
## Slash commands
|
|
32
32
|
|
|
33
|
-
Each command echoes as an invocation line, asks through a bordered panel that takes the input area's place (one question at a time, separate from the chat transcript), and finishes with a one-line `⎿` result. Loading states stay on the ephemeral status line instead of piling into the transcript; model and
|
|
33
|
+
Each command echoes as an invocation line, asks through a bordered panel that takes the input area's place (one question at a time, separate from the chat transcript), and finishes with a one-line `⎿` result. Loading states stay on the ephemeral status line instead of piling into the transcript; model, channel, and the Vercel CLI commands (`/vc:install`, `/vc:login`) use the same green square pulse as the build phase, while `/deploy` keeps a spinner. Setup menus render the selected option with a filled arrow and an inverse label padded by one space on each side. Text prompts use a blinking block cursor over the character at the caret. The selected label is blue normally and yellow for warning rows.
|
|
34
34
|
|
|
35
|
-
| Command
|
|
36
|
-
|
|
|
37
|
-
| `/model`
|
|
38
|
-
| `/channels`
|
|
39
|
-
| `/deploy`
|
|
40
|
-
| `/
|
|
41
|
-
| `/
|
|
42
|
-
| `/
|
|
43
|
-
| `/
|
|
35
|
+
| Command | Does |
|
|
36
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
37
|
+
| `/model` | Opens a configure menu that loops until Done (or Esc). See [Configure the model and provider](#configure-the-model-and-provider). |
|
|
38
|
+
| `/channels` | Shows the agent's channel list and adds the one you pick. See [Add a channel](#add-a-channel). |
|
|
39
|
+
| `/deploy` | Ships the agent to Vercel production, linking the directory first when it is unlinked. |
|
|
40
|
+
| `/vc:install` | Installs the Vercel CLI. Available locally and on a remote session. |
|
|
41
|
+
| `/vc:login` | Logs in to Vercel locally. On a remote session, resolves the deployment's project, refreshes its OIDC token, and confirms any required Trusted Sources rule. |
|
|
42
|
+
| `/loglevel` | Switches which logs the transcript shows. See [Control what logs show](#control-what-logs-show). |
|
|
43
|
+
| `/new` | Starts a fresh session. |
|
|
44
|
+
| `/exit` | Quits the TUI. |
|
|
45
|
+
| `/help` | Lists the commands available for the current local or remote session. |
|
|
44
46
|
|
|
45
47
|
`/model`, `/channels`, and `/deploy` manage the project and are available only when `eve dev` runs the server locally, not when connected to a remote server with `--url`.
|
|
46
48
|
|
|
@@ -119,7 +121,15 @@ Pass a URL and the TUI talks to a running deployment instead of starting a local
|
|
|
119
121
|
eve dev https://<your-app>
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
The bare URL is shorthand for `--url`;
|
|
124
|
+
The bare URL is shorthand for `--url`; it cannot be combined with `--host`, `--port`, or `--no-ui`.
|
|
125
|
+
|
|
126
|
+
At startup the TUI asks Vercel to resolve the remote origin under the active scope. A resolved response is the authority for a project-scoped OIDC token—refreshing an expired development token when refresh credentials exist—or an automation-bypass secret. An unresolved host is probed anonymously. The TUI then requests `/eve/v1/info`, with a ten-second timeout. A successful response marks the remote ready. An eve OIDC challenge, Vercel Deployment Protection challenge, or `TRUSTED_SOURCES_ENVIRONMENT_MISMATCH` opens `/vc:login` automatically; ordinary network failures and server errors remain remote-availability errors and do not start an authentication flow. Esc or Ctrl-C cancels the authentication flow.
|
|
127
|
+
|
|
128
|
+
In a remote session, `/vc:login` first resolves the deployment's Vercel project from its URL. If the active Vercel scope cannot resolve it, the flow asks for another team and reruns the lookup in that team's scope. If the CLI is logged out, the same panel runs the browser login first. The flow asks before adding any required Trusted Sources rule and requests a project-scoped token through `@vercel/oidc`. It does not relink the directory or modify `.env.local`. Finally, it retries `/eve/v1/info` to prove the credential works. A failure reports any login or Trusted Sources update that completed before it stopped.
|
|
129
|
+
|
|
130
|
+
The project-scoped token represents the resolved project's Development environment. Vercel already allows a project's Development environment to call its own Preview deployments by default. For a Production or custom-environment target, `/vc:login` shows the exact Development-to-target rule before changing that project's Trusted Sources. Eve preserves existing entries. When it creates an explicit rule, it also carries Vercel's default self-access rows forward because saved rules replace those defaults. See Vercel's [Trusted Sources guide](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources), [error reference](https://vercel.com/docs/errors/trusted_sources_environment_mismatch), and [OIDC token anatomy](https://vercel.com/docs/oidc/reference#oidc-token-anatomy).
|
|
131
|
+
|
|
132
|
+
`VERCEL_AUTOMATION_BYPASS_SECRET` remains available for a Protection Bypass for Automation token. See [Deployment](./deployment) for the smoke-test flow.
|
|
123
133
|
|
|
124
134
|
## What to read next
|
|
125
135
|
|
|
@@ -186,23 +186,43 @@ const agent = useEveAgent({ reducer: toolCounter });
|
|
|
186
186
|
|
|
187
187
|
## Resumable sessions
|
|
188
188
|
|
|
189
|
-
The browser conversation lives durably on the server. Persist the `session` cursor to pick it back up after a reload:
|
|
189
|
+
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:
|
|
190
190
|
|
|
191
191
|
```tsx
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
import type { HandleMessageStreamEvent, SessionState } from "eve/client";
|
|
193
|
+
|
|
194
|
+
type SavedEveChat = {
|
|
195
|
+
events?: readonly HandleMessageStreamEvent[];
|
|
196
|
+
session?: SessionState;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const [saved] = useState<SavedEveChat>(() => {
|
|
200
|
+
const raw = localStorage.getItem("eve-chat");
|
|
201
|
+
return raw ? JSON.parse(raw) : {};
|
|
195
202
|
});
|
|
196
203
|
|
|
197
204
|
const agent = useEveAgent({
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
205
|
+
initialEvents: saved.events ?? [],
|
|
206
|
+
initialSession: saved.session,
|
|
207
|
+
onFinish(snapshot) {
|
|
208
|
+
localStorage.setItem(
|
|
209
|
+
"eve-chat",
|
|
210
|
+
JSON.stringify({
|
|
211
|
+
events: snapshot.events,
|
|
212
|
+
session: snapshot.session,
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
201
215
|
},
|
|
202
216
|
});
|
|
203
217
|
```
|
|
204
218
|
|
|
205
|
-
Store the full `session` object (`sessionId`, `continuationToken`, `streamIndex`), not a single field.
|
|
219
|
+
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`.
|
|
220
|
+
|
|
221
|
+
For multiple chat threads, keep one saved event log and session cursor per thread. `host`, `reducer`, `session`, `initialEvents`, `initialSession`, `auth`, `headers`, `maxReconnectAttempts`, and `optimistic` are read when the hook creates its store, so remount the chat component when switching threads, for example with `key={chat.id}`.
|
|
222
|
+
|
|
223
|
+
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
|
+
|
|
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.
|
|
206
226
|
|
|
207
227
|
## Custom hosts and headers
|
|
208
228
|
|
package/docs/schedules.mdx
CHANGED
|
@@ -58,17 +58,17 @@ Sweep stale workflow state.
|
|
|
58
58
|
|
|
59
59
|
Use a handler when the schedule needs to deliver to a channel, branch on conditions, or compute its arguments at fire time. The handler is in full control. It has no channel of its own, so it passes the work to one with `receive`.
|
|
60
60
|
|
|
61
|
-
```ts title="agent/schedules/
|
|
61
|
+
```ts title="agent/schedules/critical-alerts.ts"
|
|
62
62
|
import { defineSchedule } from "eve/schedules";
|
|
63
63
|
|
|
64
64
|
import slack from "../channels/slack.js";
|
|
65
65
|
|
|
66
66
|
export default defineSchedule({
|
|
67
|
-
cron: "
|
|
67
|
+
cron: "* * * * *",
|
|
68
68
|
async run({ receive, waitUntil, appAuth }) {
|
|
69
69
|
waitUntil(
|
|
70
70
|
receive(slack, {
|
|
71
|
-
message: "
|
|
71
|
+
message: "Check for new critical alerts. Report only when there are any.",
|
|
72
72
|
target: { channelId: "C0123ABC" },
|
|
73
73
|
auth: appAuth,
|
|
74
74
|
}),
|
|
@@ -77,6 +77,8 @@ export default defineSchedule({
|
|
|
77
77
|
});
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
The agent does not have to deliver a message on every run. When a prompt makes delivery conditional, as in the alert check above, eve tells the agent how to finish successfully without sending anything to the channel. Frequent polling schedules do not need a separate filter or delivery setting.
|
|
81
|
+
|
|
80
82
|
- `receive(channel, { message, target, auth })`: starts a session on another channel. Same contract as a route handler's `args.receive`.
|
|
81
83
|
- `waitUntil(promise)`: extends the cron task's lifetime so the parked session and any in-flight fetches settle before the task ends. Wrap the `receive` call in it.
|
|
82
84
|
- `appAuth`: the app principal (`{ authenticator: "app", principalId: "eve:app", principalType: "runtime" }`). Pass it as `receive(..., { auth: appAuth })` for work the agent does on its own behalf.
|
package/docs/tools/overview.mdx
CHANGED
|
@@ -77,6 +77,8 @@ toModelOutput(output) {
|
|
|
77
77
|
|
|
78
78
|
`toModelOutput` receives the full, typed `execute` return and only affects the model. Channel event handlers and hooks still get the full output on `action.result`, so a channel can render rich platform output (Slack Block Kit, say) the model never sees. Return `{ type: "text", value }` for a summary, or `{ type: "json", value }` for a smaller object.
|
|
79
79
|
|
|
80
|
+
Tool outputs must be JSON-serializable. Return plain objects, arrays, strings, numbers, booleans, or `null`; convert values like `Date`, `Map`, `Set`, `NaN`, and cyclic objects before returning them from `execute` or from a `{ type: "json" }` `toModelOutput`.
|
|
81
|
+
|
|
80
82
|
Do not return secrets, credentials, unnecessary personal data, or unbounded sensitive content from tools. Filter, minimize, and redact tool outputs before returning them.
|
|
81
83
|
|
|
82
84
|
## What to read next
|