eve 0.45.0 → 0.45.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/src/chunks/{use-eve-agent-OtHRoxIS.js → use-eve-agent-BH7Z6SDu.js} +13 -1
- package/dist/src/chunks/{use-eve-agent-C46Kan_I.js → use-eve-agent-DI2j5XK8.js} +13 -1
- package/dist/src/cli/commands/integration-connect.d.ts +2 -0
- package/dist/src/cli/commands/integration-connect.js +1 -1
- package/dist/src/cli/commands/register-integration-commands.js +1 -1
- package/dist/src/client/agent-info-schema.d.ts +191 -2
- package/dist/src/client/agent-info-schema.js +1 -1
- package/dist/src/client/types.d.ts +1 -1
- package/dist/src/compiler/extension-compatibility.d.ts +4 -4
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/load-binding-namespace.js +1 -1
- package/dist/src/compiler/manifest.d.ts +10 -0
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/module-map.js +1 -1
- package/dist/src/compiler/normalize-helpers.d.ts +2 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/normalize-memory.d.ts +5 -0
- package/dist/src/compiler/normalize-memory.js +1 -0
- package/dist/src/compiler/normalize-tool.js +1 -1
- package/dist/src/compiler/project-sources.d.ts +3 -4
- package/dist/src/compiler/project-sources.js +1 -1
- package/dist/src/compiler/source-graph.d.ts +2 -0
- package/dist/src/compiler/source-graph.js +1 -1
- package/dist/src/compiler/validate-artifact.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.d.ts +8 -1
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/keys.d.ts +25 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/context/memory-event-lifecycle.d.ts +13 -0
- package/dist/src/context/memory-event-lifecycle.js +1 -0
- package/dist/src/context/memory-lifecycle.d.ts +52 -0
- package/dist/src/context/memory-lifecycle.js +1 -0
- package/dist/src/context/memory-tools.d.ts +12 -0
- package/dist/src/context/memory-tools.js +1 -0
- package/dist/src/discover/discover-agent.js +1 -1
- package/dist/src/discover/discover-subagent.js +1 -1
- package/dist/src/discover/extensions.d.ts +6 -0
- package/dist/src/discover/extensions.js +1 -1
- package/dist/src/discover/filesystem.d.ts +2 -2
- package/dist/src/discover/filesystem.js +1 -1
- package/dist/src/discover/manifest.d.ts +6 -1
- package/dist/src/discover/manifest.js +1 -1
- package/dist/src/discover/memory.d.ts +14 -0
- package/dist/src/discover/memory.js +1 -0
- package/dist/src/discover/project.js +1 -1
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/evals/target.js +1 -1
- package/dist/src/execution/history-view.d.ts +2 -2
- package/dist/src/execution/history-view.js +1 -1
- package/dist/src/execution/tools/connection-search.js +2 -2
- package/dist/src/execution/workflow-steps.d.ts +1 -3
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/framework/sources/modules/memory-wrapper.d.ts +2 -0
- package/dist/src/framework/sources/modules/memory-wrapper.js +1 -0
- package/dist/src/framework/sources/registry.d.ts +1 -0
- package/dist/src/framework/sources/registry.js +1 -1
- package/dist/src/harness/emission.d.ts +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/memory.d.ts +2 -0
- package/dist/src/internal/authored-definition/memory.js +1 -0
- package/dist/src/internal/authored-definition/schema-backed.d.ts +1 -0
- package/dist/src/internal/authored-definition/schema-backed.js +1 -1
- package/dist/src/internal/authored-module-map-loader.js +1 -1
- package/dist/src/internal/dynamic-tool-rebind.d.ts +3 -0
- package/dist/src/internal/dynamic-tool-rebind.js +1 -0
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +1 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
- package/dist/src/internal/nitro/routes/index.js +1 -0
- package/dist/src/internal/programmatic-source-loader.d.ts +1 -0
- package/dist/src/internal/programmatic-source-loader.js +1 -1
- package/dist/src/public/memory/index.d.ts +117 -0
- package/dist/src/public/memory/index.js +1 -0
- package/dist/src/public/memory/scope.d.ts +2 -0
- package/dist/src/public/memory/scope.js +1 -0
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/resolve-dynamic-tool.d.ts +1 -0
- package/dist/src/runtime/resolve-dynamic-tool.js +1 -1
- package/dist/src/runtime/resolve-memory.d.ts +4 -0
- package/dist/src/runtime/resolve-memory.js +1 -0
- package/dist/src/runtime/types.d.ts +7 -0
- package/dist/src/setup/connection-connector.d.ts +2 -0
- package/dist/src/setup/connection-connector.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +2 -0
- package/dist/src/setup/scaffold/create/web-template.js +28 -0
- package/dist/src/shared/memory-definition.d.ts +2 -0
- package/dist/src/shared/memory-definition.js +1 -0
- package/dist/src/shared/memory-state.d.ts +55 -0
- package/dist/src/shared/memory-state.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/eve.mdx +1 -1
- package/docs/concepts/context-control.md +7 -0
- package/docs/concepts/default-harness.md +8 -0
- package/docs/concepts/sessions-runs-and-streaming.md +3 -3
- package/docs/concepts/state.md +8 -1
- package/docs/extensions.md +6 -2
- package/docs/guides/client/overview.mdx +2 -2
- package/docs/guides/dynamic-capabilities.md +3 -2
- package/docs/memory.md +255 -0
- package/docs/meta.json +1 -0
- package/docs/patterns/multi-tenant-memory.md +108 -136
- package/package.json +11 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const DISABLED_PRINCIPAL_TYPES=new Set([`anonymous`,`runtime`]);function byPrincipal(e){let t=e.session.auth.current;return t===null||DISABLED_PRINCIPAL_TYPES.has(t.principalType)?null:t.principalType===`local-dev`?`local-dev`:JSON.stringify([t.principalType,t.authenticator,t.issuer??null,t.principalId])}export{byPrincipal};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ResolveAgentError,createResolvedModuleSourceRef}from"#runtime/resolve-helpers.js";import{resolveChannelDefinition}from"#runtime/resolve-channel.js";import{resolveConnectionDefinition}from"#runtime/resolve-connection.js";import{resolveHookDefinition}from"#runtime/resolve-hook.js";import{resolveSandboxDefinition}from"#runtime/resolve-sandbox.js";import{resolveDynamicInstructionsDefinition}from"#runtime/resolve-dynamic-instructions.js";import{resolveDynamicSkillDefinition}from"#runtime/resolve-dynamic-skill.js";import{resolveDynamicToolDefinition}from"#runtime/resolve-dynamic-tool.js";import{resolveToolDefinition}from"#runtime/resolve-tool.js";async function resolveAgent(e){let t=e.manifest.skills.map(t=>({...t,owner:requireCompiledSourceOwner(e.manifest,t),metadata:t.metadata===void 0?void 0:{...t.metadata}})),i=await Promise.all(e.manifest.channelRoutes.effective.map(t=>resolveChannelDefinition(t,e.moduleMap,e.nodeId))),a=await Promise.all(e.manifest.tools.map(t=>resolveToolDefinition(t,e.moduleMap,e.nodeId,requireBindingOwner(e.manifest,t.sourceId)))),o=await Promise.all((e.manifest.dynamicInstructions??[]).map(t=>resolveDynamicInstructionsDefinition(t,e.moduleMap,e.nodeId))),s=await Promise.all((e.manifest.dynamicSkills??[]).map(t=>resolveDynamicSkillDefinition(t,e.moduleMap,e.nodeId))),c=await Promise.all(e.manifest.dynamicTools.map(t=>resolveDynamicToolDefinition(t,e.moduleMap,e.nodeId))),l=await Promise.all(e.manifest.hooks.map(t=>resolveHookDefinition(t,e.moduleMap,e.nodeId))),u=await Promise.all(e.manifest.connections.map(t=>resolveConnectionDefinition(t,e.moduleMap,e.nodeId))),d=await resolveSandboxDefinition(e.manifest.sandbox,e.moduleMap,e.nodeId),
|
|
1
|
+
import{ResolveAgentError,createResolvedModuleSourceRef}from"#runtime/resolve-helpers.js";import{resolveChannelDefinition}from"#runtime/resolve-channel.js";import{resolveConnectionDefinition}from"#runtime/resolve-connection.js";import{resolveHookDefinition}from"#runtime/resolve-hook.js";import{resolveSandboxDefinition}from"#runtime/resolve-sandbox.js";import{resolveDynamicInstructionsDefinition}from"#runtime/resolve-dynamic-instructions.js";import{resolveDynamicSkillDefinition}from"#runtime/resolve-dynamic-skill.js";import{resolveDynamicToolDefinition}from"#runtime/resolve-dynamic-tool.js";import{resolveToolDefinition}from"#runtime/resolve-tool.js";import{resolveMemoryDefinition}from"#runtime/resolve-memory.js";async function resolveAgent(e){let t=e.manifest.skills.map(t=>({...t,owner:requireCompiledSourceOwner(e.manifest,t),metadata:t.metadata===void 0?void 0:{...t.metadata}})),i=await Promise.all(e.manifest.channelRoutes.effective.map(t=>resolveChannelDefinition(t,e.moduleMap,e.nodeId))),a=await Promise.all(e.manifest.tools.map(t=>resolveToolDefinition(t,e.moduleMap,e.nodeId,requireBindingOwner(e.manifest,t.sourceId)))),o=await Promise.all((e.manifest.dynamicInstructions??[]).map(t=>resolveDynamicInstructionsDefinition(t,e.moduleMap,e.nodeId))),s=await Promise.all((e.manifest.dynamicSkills??[]).map(t=>resolveDynamicSkillDefinition(t,e.moduleMap,e.nodeId))),c=await Promise.all(e.manifest.dynamicTools.map(t=>resolveDynamicToolDefinition(t,e.moduleMap,e.nodeId))),l=await Promise.all(e.manifest.hooks.map(t=>resolveHookDefinition(t,e.moduleMap,e.nodeId))),u=await Promise.all(e.manifest.connections.map(t=>resolveConnectionDefinition(t,e.moduleMap,e.nodeId))),d=await Promise.all(e.manifest.memories.map(t=>resolveMemoryDefinition(t,e.moduleMap,e.nodeId))),f=await resolveSandboxDefinition(e.manifest.sandbox,e.moduleMap,e.nodeId),p=e.manifest.instructions.map(t=>createResolvedInstructionsDefinition(e.manifest,t)),m=e.manifest.workspaceResourceRoot,h={channels:i,connections:u,workflowTool:e.manifest.workflowTool===void 0?void 0:{maxSubagents:e.manifest.workflowTool.maxSubagents},webSearchProvider:e.manifest.webSearchProvider,dynamicInstructionsResolvers:o,dynamicSkillResolvers:s,dynamicToolResolvers:c,hooks:l,instructions:p,metadata:{agentRoot:e.manifest.agentRoot,appRoot:e.manifest.appRoot,diagnosticsSummary:e.manifest.diagnosticsSummary},memories:d,sandbox:f,workspaceResourceRoot:m,skills:t,tools:a,workspaceSpec:{rootEntries:[...m.rootEntries]}};return`config`in e.manifest?{...h,config:createResolvedAgentConfig(e.manifest)}:h}function requireBindingOwner(e,t){let n=e.bindings[t];if(n===void 0)throw Error(`Compiled source "${t}" has no binding.`);return n.owner}function createResolvedInstructionsDefinition(e,t){return{content:t.content,name:t.name,owner:requireCompiledSourceOwner(e,t),logicalPath:t.logicalPath,role:t.role,sourceId:t.sourceId,sourceKind:t.sourceKind}}function requireCompiledSourceOwner(e,t){let n=e.bindings[t.sourceId]?.owner??t.owner;if(n===void 0)throw Error(`Compiled source "${t.sourceId}" has no owner.`);return n}function createResolvedAgentConfig(e){let n={name:e.config.name};if(e.config.compaction!==void 0){let t={};e.config.compaction.model!==void 0&&(t.model=e.config.compaction.model.source===void 0?{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,maxOutputTokens:e.config.compaction.model.maxOutputTokens,providerOptions:e.config.compaction.model.providerOptions}:{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,maxOutputTokens:e.config.compaction.model.maxOutputTokens,providerOptions:e.config.compaction.model.providerOptions,source:{exportName:e.config.compaction.model.source.exportName,sourceKind:`module`,logicalPath:e.config.compaction.model.source.logicalPath,sourceId:e.config.compaction.model.source.sourceId}}),e.config.compaction.thresholdPercent!==void 0&&(t.thresholdPercent=e.config.compaction.thresholdPercent),n.compaction=t}if(e.config.experimental!==void 0&&(n.experimental={instrumentationProviders:e.config.experimental.instrumentationProviders,tasks:e.config.experimental.tasks,workflow:e.config.experimental.workflow===void 0?void 0:{world:e.config.experimental.workflow.world}}),e.config.outputSchema!==void 0&&(n.outputSchema=e.config.outputSchema),e.config.reasoning!==void 0&&(n.reasoning=e.config.reasoning),e.config.source!==void 0&&(n.source=createResolvedModuleSourceRef(e.config.source)),e.config.limits!==void 0&&(n.limits={maxInputTokensPerSession:e.config.limits.maxInputTokensPerSession,maxOutputTokensPerSession:e.config.limits.maxOutputTokensPerSession,sessionTimeoutMs:e.config.limits.sessionTimeoutMs}),e.config.dynamicModel!==void 0)return{...n,dynamicModel:{...createResolvedModuleSourceRef(e.config.dynamicModel),eventNames:[...e.config.dynamicModel.eventNames]}};let r=e.config.model;return{...n,model:r.source===void 0?{id:r.id,contextWindowTokens:r.contextWindowTokens,maxOutputTokens:r.maxOutputTokens,providerOptions:r.providerOptions}:{contextWindowTokens:r.contextWindowTokens,id:r.id,maxOutputTokens:r.maxOutputTokens,providerOptions:r.providerOptions,source:{exportName:r.source.exportName,sourceKind:`module`,logicalPath:r.source.logicalPath,sourceId:r.source.sourceId}}}}export{ResolveAgentError,resolveAgent};
|
|
@@ -5,6 +5,7 @@ import type { ResolvedDynamicToolResolver } from "#runtime/types.js";
|
|
|
5
5
|
type DynamicToolResolverSource = Readonly<ModuleSourceRef & {
|
|
6
6
|
readonly extensionNamespace?: string;
|
|
7
7
|
readonly slug: string;
|
|
8
|
+
readonly rebindMissingCallbacks?: boolean;
|
|
8
9
|
}>;
|
|
9
10
|
/**
|
|
10
11
|
* Resolves one compiled dynamic tool entry into a runtime-owned resolver
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{isDynamicSentinel}from"#dynamic/definition.js";import{registerDefinitionSource,stampDefinitionKey}from"#internal/authored-definition/source-identity.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function resolveDynamicToolDefinition(e,t,r){try{return resolveLoadedDynamicToolDefinition(await loadResolvedModuleExport({definition:e,kindLabel:`dynamic-tool`,moduleMap:t,nodeId:r}),e,e.eventNames)}catch(t){throw t instanceof ResolveAgentError?t:new ResolveAgentError(`Failed to resolve dynamic tool from "${e.logicalPath}": ${toErrorMessage(t)}`,{logicalPath:e.logicalPath,sourceId:e.sourceId})}}function resolveLoadedDynamicToolDefinition(e,t,n){let r=expectDynamicToolValue(e,t);return createResolvedDynamicToolResolver(r,t,n??Object.keys(r.events))}function createResolvedDynamicToolResolver(t,n,r){let a={};for(let i of r)a[i]=expectFunction(t.events[i],describe(n,`to provide a handler for event "${i}"`));let o=`dynamic-tool-source:${n.sourceId}`;return stampDefinitionKey(t,o),registerDefinitionSource(o,{kind:`tool`,logicalPath:n.logicalPath,name:n.slug}),{eventNames:[...r],events:a,exportName:n.exportName,extensionNamespace:n.extensionNamespace,logicalPath:n.logicalPath,slug:n.slug,sourceId:n.sourceId,sourceKind:`module`}}function expectDynamicToolValue(e,n){let i=expectObjectRecord(e,describe(n,`to return an object`));if(!isDynamicSentinel(i))throw Error(describe(n,`to be created by defineDynamic()`));return expectObjectRecord(i.events,describe(n,`to provide an events object`)),i}function describe(e,t){return`Expected the dynamic tool export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}export{resolveDynamicToolDefinition,resolveLoadedDynamicToolDefinition};
|
|
1
|
+
import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{isDynamicSentinel}from"#dynamic/definition.js";import{registerDefinitionSource,stampDefinitionKey}from"#internal/authored-definition/source-identity.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function resolveDynamicToolDefinition(e,t,r){try{return resolveLoadedDynamicToolDefinition(await loadResolvedModuleExport({definition:e,kindLabel:`dynamic-tool`,moduleMap:t,nodeId:r}),e,e.eventNames)}catch(t){throw t instanceof ResolveAgentError?t:new ResolveAgentError(`Failed to resolve dynamic tool from "${e.logicalPath}": ${toErrorMessage(t)}`,{logicalPath:e.logicalPath,sourceId:e.sourceId})}}function resolveLoadedDynamicToolDefinition(e,t,n){let r=expectDynamicToolValue(e,t);return createResolvedDynamicToolResolver(r,t,n??Object.keys(r.events))}function createResolvedDynamicToolResolver(t,n,r){let a={};for(let i of r)a[i]=expectFunction(t.events[i],describe(n,`to provide a handler for event "${i}"`));let o=`dynamic-tool-source:${n.sourceId}`;return stampDefinitionKey(t,o),registerDefinitionSource(o,{kind:`tool`,logicalPath:n.logicalPath,name:n.slug}),{eventNames:[...r],events:a,exportName:n.exportName,extensionNamespace:n.extensionNamespace,logicalPath:n.logicalPath,rebindMissingCallbacks:n.rebindMissingCallbacks,slug:n.slug,sourceId:n.sourceId,sourceKind:`module`}}function expectDynamicToolValue(e,n){let i=expectObjectRecord(e,describe(n,`to return an object`));if(!isDynamicSentinel(i))throw Error(describe(n,`to be created by defineDynamic()`));return expectObjectRecord(i.events,describe(n,`to provide an events object`)),i}function describe(e,t){return`Expected the dynamic tool export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}export{resolveDynamicToolDefinition,resolveLoadedDynamicToolDefinition};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledMemoryDefinition } from "#compiler/manifest.js";
|
|
2
|
+
import type { CompiledModuleMap } from "#compiler/module-map.js";
|
|
3
|
+
import type { ResolvedMemoryDefinition } from "#runtime/types.js";
|
|
4
|
+
export declare function resolveMemoryDefinition(compiled: CompiledMemoryDefinition, moduleMap: CompiledModuleMap, nodeId: string | undefined): Promise<ResolvedMemoryDefinition>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{toErrorMessage}from"#shared/errors.js";import{normalizeMemoryDefinition}from"#internal/authored-definition/memory.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function resolveMemoryDefinition(t,n,r){try{return{...normalizeMemoryDefinition(await loadResolvedModuleExport({definition:t,kindLabel:`memory`,moduleMap:n,nodeId:r}),`Expected the memory export "${t.exportName??`default`}" from "${t.logicalPath}" to be created with defineMemory().`),description:t.description,exportName:t.exportName,logicalPath:t.logicalPath,slot:t.slot,sourceId:t.sourceId,sourceKind:`module`,visibility:t.visibility}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to resolve memory from "${t.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:t.logicalPath,sourceId:t.sourceId})}}export{resolveMemoryDefinition};
|
|
@@ -28,6 +28,7 @@ import type { SandboxBackend } from "#shared/sandbox-backend.js";
|
|
|
28
28
|
import type { SandboxBootstrapContext, SandboxSessionContext } from "#shared/sandbox-definition.js";
|
|
29
29
|
import type { ToolSchema } from "#tools/schema.js";
|
|
30
30
|
import type { AgentSourceOwner } from "#compiler/source-graph.js";
|
|
31
|
+
import type { MemoryDefinition } from "#public/memory/index.js";
|
|
31
32
|
/**
|
|
32
33
|
* Runtime-owned source ref describing one additive config module import.
|
|
33
34
|
*/
|
|
@@ -301,12 +302,17 @@ export interface ResolvedDynamicToolResolver extends Readonly<ModuleSourceRef> {
|
|
|
301
302
|
readonly slug: string;
|
|
302
303
|
readonly eventNames: readonly string[];
|
|
303
304
|
readonly events: Readonly<Record<string, (event: unknown, ctx: unknown) => unknown | Promise<unknown>>>;
|
|
305
|
+
readonly rebindMissingCallbacks?: boolean;
|
|
304
306
|
/**
|
|
305
307
|
* Mount namespace when this resolver comes from an extension. Names of tools
|
|
306
308
|
* the resolver produces are prefixed with `${extensionNamespace}__`.
|
|
307
309
|
*/
|
|
308
310
|
readonly extensionNamespace?: string;
|
|
309
311
|
}
|
|
312
|
+
export type ResolvedMemoryDefinition = Readonly<MemoryDefinition & ModuleSourceRef & {
|
|
313
|
+
readonly slot: string;
|
|
314
|
+
readonly visibility: "scope" | "session";
|
|
315
|
+
}>;
|
|
310
316
|
/**
|
|
311
317
|
* Runtime resolver for dynamic skills declared via `defineDynamic({ events })`
|
|
312
318
|
* in `agent/skills/`. Carries the live event handler functions loaded from the
|
|
@@ -368,6 +374,7 @@ export interface ResolvedAgent {
|
|
|
368
374
|
*/
|
|
369
375
|
readonly workspaceResourceRoot: CompiledWorkspaceResourceRoot;
|
|
370
376
|
readonly hooks: readonly ResolvedHookDefinition[];
|
|
377
|
+
readonly memories: readonly ResolvedMemoryDefinition[];
|
|
371
378
|
readonly skills: readonly ResolvedSkillDefinition[];
|
|
372
379
|
readonly tools: readonly ResolvedToolDefinition[];
|
|
373
380
|
readonly workspaceSpec: WorkspaceRuntimeSpec;
|
|
@@ -8,6 +8,8 @@ export interface SetupConnectionConnectorOptions {
|
|
|
8
8
|
projectRoot: string;
|
|
9
9
|
slug: string;
|
|
10
10
|
service: string;
|
|
11
|
+
creationType?: string;
|
|
12
|
+
connectionMethod?: "mcp" | "oauth";
|
|
11
13
|
canonicalConnectorName: string;
|
|
12
14
|
project: VercelProjectReference;
|
|
13
15
|
signal?: AbortSignal;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import{readProjectLink}from"#setup/project-resolution.js";import{captureVercel,runVercel,runVercelCaptureStdout}from"#setup/primitives/run-vercel.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";const CREATED_CONNECTOR=/\bConnector created:\s*(scl_[A-Za-z0-9_-]+)\b/u;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function parseJson(e){try{return JSON.parse(e)}catch{return}}function connectorCreationFailure(e,t){let n=t?.split(`
|
|
2
|
-
`).map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith(`Vercel CLI `)).at(-1);return n===void 0?`Could not create the ${e} connector.`:`Could not create the ${e} connector. Vercel returned: ${n}`}function parseConnectorRef(e){if(!isRecord(e)||typeof e.uid!=`string`||typeof e.id!=`string`)return;let t={uid:e.uid,id:e.id};return typeof e.name==`string`&&(t.name=e.name),t}function parseCreatedConnector(e){let t=parseJson(e),n=parseConnectorRef(t);if(!isRecord(t)||n===void 0)return;let r=t.supportedSubjectTypes;return Array.isArray(r)&&r.includes(`user`)?n:void 0}function parseConnectorList(e,t){let n=[];for(let r of e){if(!isRecord(r)||typeof r.service==`string`&&r.service!==t)continue;let e=parseConnectorRef(r);e!==void 0&&n.push(e)}return n}function parseConnectorListPage(e,t){if(!isRecord(e)||!Array.isArray(e.connectors))return;let n=typeof e.cursor==`string`?e.cursor:void 0;return n===void 0?{connectors:parseConnectorList(e.connectors,t)}:{connectors:parseConnectorList(e.connectors,t),cursor:n}}async function listConnectors(e,n,r){let i=[],a=new Set,o;do{let s=[`connect`,`list`,`-F`,`json`,`--all-projects`,`--service`,e.service,`--scope`,n.orgId];o!==void 0&&s.push(`--next`,o);let c=await captureVercel(s,{cwd:e.projectRoot,onOutput:r,signal:e.signal});if(!c.ok)throw Error(c.failure.message);let l=parseConnectorListPage(parseJson(c.stdout),e.service);if(l===void 0)throw Error(`Vercel returned an invalid connector list for ${e.service}.`);i.push(...l.connectors);let u=l.cursor;if(u!==void 0&&a.has(u))throw Error(`The connector list repeated cursor ${u}.`);u!==void 0&&a.add(u),o=u}while(o!==void 0);return i}async function supportsUserAuthorization(e,n,r,i){let a=await captureVercel([`api`,`/v1/connect/connectors/${encodeURIComponent(r.id)}`,`--scope`,n.orgId,`--raw`],{cwd:e.projectRoot,onOutput:i,signal:e.signal});if(!a.ok)throw Error(`Could not verify connector ${r.uid}.`);let o=parseJson(a.stdout);if(!isRecord(o)||o.id!==r.id||o.uid!==r.uid||typeof o.service==`string`&&o.service!==e.service)throw Error(`Vercel returned invalid details for connector ${r.uid}.`);let s=o.supportedSubjectTypes;return Array.isArray(s)&&s.includes(`user`)}function connectorNames(e){let t=new Set;for(let n of e){n.name!==void 0&&t.add(n.name.toLowerCase());let e=n.uid.slice(n.uid.lastIndexOf(`/`)+1).trim();e.length>0&&t.add(e.toLowerCase())}return t}function connectorMatchesCanonicalName(e,t){let n=t.toLowerCase();return e.name?.toLowerCase()===n||e.uid.slice(e.uid.lastIndexOf(`/`)+1).trim().toLowerCase()===n}function nextConnectorName(e,t){if(!t.has(e.toLowerCase()))return e;let n=2;for(;t.has(`${e}-${n}`.toLowerCase());)n+=1;return`${e}-${n}`}async function cleanupCreatedConnectionConnector(t){let r=t.orgId??(await readProjectLink(t.projectRoot))?.orgId,a=[`connect`,`remove`,t.connectorId,`--disconnect-all`,`--yes`];if(r!==void 0&&a.push(`--scope`,r),!await runVercel(a,{cwd:t.projectRoot,onOutput:createPromptCommandOutput(t.log)}))throw Error(`Could not remove connector ${t.connectorId}; run \`vercel connect remove ${t.connectorId} --disconnect-all --yes\`.`)}async function attach(e,t,r,i){return runVercel([`connect`,`attach`,r,`--yes`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:i,signal:e.signal})}async function resolveFallbackConnector(e,t,n,i,s){let c=s;for(;;){if(await e.prompter.select({message:`Which connector should ${e.slug} use?`,hintLayout:`inline`,notices:[{tone:`warning`,text:c}],options:[{value:`find`,label:`Find a new one`,hint:`Browse existing connectors`},{value:`create`,label:`Create a new one`,hint:`Register another connector`}]})===`find`){let r=[];for(let a of i)await supportsUserAuthorization(e,t,a,n)&&r.push(a);if(r.length===0){c=`No existing ${e.service} connectors support user authorization.`;continue}let a=new Map(r.map(e=>[e.uid,e])),o=await e.prompter.select({message:`Select a connector for ${e.slug}`,hintLayout:`inline`,search:!0,placeholder:`type to search connectors`,options:r.map(e=>({value:e.uid,label:e.uid,hint:e.name??e.id}))}),s=a.get(o);if(s===void 0)throw Error(`Connector ${o} is no longer available.`);return{kind:`existing`,connector:s}}let s=connectorNames(i),l=(await e.prompter.text({message:`New connector name`,defaultValue:nextConnectorName(e.slug,s),validate:e=>{let t=e.trim().toLowerCase();return t.length===0?`A name is required.`:s.has(t)?`A connector with this name already exists.`:void 0}})).trim(),u=[],createOutput=e=>{u.push(e.text),n(e)},d=await withPhase(e.log,`Waiting for you to complete setup in the browser…`,()=>runVercelCaptureStdout([`connect`,`create`,e.service,`--name`,l,`-F`,`json`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:createOutput,signal:e.signal}),{kind:`external-action`,emphasis:`browser`}),f=parseConnectorRef(parseJson(d.stdout))?.id??CREATED_CONNECTOR.exec(u.join(`
|
|
2
|
+
`).map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith(`Vercel CLI `)).at(-1);return n===void 0?`Could not create the ${e} connector.`:`Could not create the ${e} connector. Vercel returned: ${n}`}function parseConnectorRef(e){if(!isRecord(e)||typeof e.uid!=`string`||typeof e.id!=`string`)return;let t={uid:e.uid,id:e.id};return typeof e.name==`string`&&(t.name=e.name),t}function parseCreatedConnector(e){let t=parseJson(e),n=parseConnectorRef(t);if(!isRecord(t)||n===void 0)return;let r=t.supportedSubjectTypes;return Array.isArray(r)&&r.includes(`user`)?n:void 0}function parseConnectorList(e,t){let n=[];for(let r of e){if(!isRecord(r)||typeof r.service==`string`&&r.service!==t)continue;let e=parseConnectorRef(r);e!==void 0&&n.push(e)}return n}function parseConnectorListPage(e,t){if(!isRecord(e)||!Array.isArray(e.connectors))return;let n=typeof e.cursor==`string`?e.cursor:void 0;return n===void 0?{connectors:parseConnectorList(e.connectors,t)}:{connectors:parseConnectorList(e.connectors,t),cursor:n}}async function listConnectors(e,n,r){let i=[],a=new Set,o;do{let s=[`connect`,`list`,`-F`,`json`,`--all-projects`,`--service`,e.service,`--scope`,n.orgId];o!==void 0&&s.push(`--next`,o);let c=await captureVercel(s,{cwd:e.projectRoot,onOutput:r,signal:e.signal});if(!c.ok)throw Error(c.failure.message);let l=parseConnectorListPage(parseJson(c.stdout),e.service);if(l===void 0)throw Error(`Vercel returned an invalid connector list for ${e.service}.`);i.push(...l.connectors);let u=l.cursor;if(u!==void 0&&a.has(u))throw Error(`The connector list repeated cursor ${u}.`);u!==void 0&&a.add(u),o=u}while(o!==void 0);return i}async function supportsUserAuthorization(e,n,r,i){let a=await captureVercel([`api`,`/v1/connect/connectors/${encodeURIComponent(r.id)}`,`--scope`,n.orgId,`--raw`],{cwd:e.projectRoot,onOutput:i,signal:e.signal});if(!a.ok)throw Error(`Could not verify connector ${r.uid}.`);let o=parseJson(a.stdout);if(!isRecord(o)||o.id!==r.id||o.uid!==r.uid||typeof o.service==`string`&&o.service!==e.service)throw Error(`Vercel returned invalid details for connector ${r.uid}.`);let s=o.supportedSubjectTypes;return Array.isArray(s)&&s.includes(`user`)}function connectorNames(e){let t=new Set;for(let n of e){n.name!==void 0&&t.add(n.name.toLowerCase());let e=n.uid.slice(n.uid.lastIndexOf(`/`)+1).trim();e.length>0&&t.add(e.toLowerCase())}return t}function connectorMatchesCanonicalName(e,t){let n=t.toLowerCase();return e.name?.toLowerCase()===n||e.uid.slice(e.uid.lastIndexOf(`/`)+1).trim().toLowerCase()===n}function nextConnectorName(e,t){if(!t.has(e.toLowerCase()))return e;let n=2;for(;t.has(`${e}-${n}`.toLowerCase());)n+=1;return`${e}-${n}`}async function cleanupCreatedConnectionConnector(t){let r=t.orgId??(await readProjectLink(t.projectRoot))?.orgId,a=[`connect`,`remove`,t.connectorId,`--disconnect-all`,`--yes`];if(r!==void 0&&a.push(`--scope`,r),!await runVercel(a,{cwd:t.projectRoot,onOutput:createPromptCommandOutput(t.log)}))throw Error(`Could not remove connector ${t.connectorId}; run \`vercel connect remove ${t.connectorId} --disconnect-all --yes\`.`)}async function attach(e,t,r,i){return runVercel([`connect`,`attach`,r,`--yes`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:i,signal:e.signal})}async function resolveFallbackConnector(e,t,n,i,s){let c=s;for(;;){if(await e.prompter.select({message:`Which connector should ${e.slug} use?`,hintLayout:`inline`,notices:[{tone:`warning`,text:c}],options:[{value:`find`,label:`Find a new one`,hint:`Browse existing connectors`},{value:`create`,label:`Create a new one`,hint:`Register another connector`}]})===`find`){let r=[];for(let a of i)await supportsUserAuthorization(e,t,a,n)&&r.push(a);if(r.length===0){c=`No existing ${e.service} connectors support user authorization.`;continue}let a=new Map(r.map(e=>[e.uid,e])),o=await e.prompter.select({message:`Select a connector for ${e.slug}`,hintLayout:`inline`,search:!0,placeholder:`type to search connectors`,options:r.map(e=>({value:e.uid,label:e.uid,hint:e.name??e.id}))}),s=a.get(o);if(s===void 0)throw Error(`Connector ${o} is no longer available.`);return{kind:`existing`,connector:s}}let s=connectorNames(i),l=(await e.prompter.text({message:`New connector name`,defaultValue:nextConnectorName(e.slug,s),validate:e=>{let t=e.trim().toLowerCase();return t.length===0?`A name is required.`:s.has(t)?`A connector with this name already exists.`:void 0}})).trim(),u=[],createOutput=e=>{u.push(e.text),n(e)},d=await withPhase(e.log,`Waiting for you to complete setup in the browser…`,()=>runVercelCaptureStdout([`connect`,`create`,e.creationType??e.service,`--name`,l,...e.connectionMethod===void 0?[]:[`--connection-method`,e.connectionMethod],`-F`,`json`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:createOutput,signal:e.signal}),{kind:`external-action`,emphasis:`browser`}),f=parseConnectorRef(parseJson(d.stdout))?.id??CREATED_CONNECTOR.exec(u.join(`
|
|
3
3
|
`))?.[1],p=d.ok?parseCreatedConnector(d.stdout):void 0;if(p!==void 0)return{kind:`created`,connector:p};let m=d.ok?`The ${e.service} connector does not support user authorization.`:connectorCreationFailure(e.service,d.stderr);if(f!==void 0){try{await cleanupCreatedConnectionConnector({log:e.log,projectRoot:e.projectRoot,connectorId:f,orgId:t.orgId})}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`${m} ${t}`)}e.signal?.throwIfAborted()}throw Error(m)}}async function setupConnectionConnector(e){let t=createPromptCommandOutput(e.log),n=e.project,r=await listConnectors(e,n,t),a=r.find(t=>connectorMatchesCanonicalName(t,e.canonicalConnectorName)),o=`Could not find a connector named ${e.canonicalConnectorName}.`;if(a!==void 0)if(await supportsUserAuthorization(e,n,a,t)){if(await attach(e,n,a.uid,t))return e.log.success(`Attached ${a.uid} connector`),{kind:`existing`,connectorUid:a.uid};e.signal?.throwIfAborted(),o=`Could not attach ${a.uid}.`}else o=`${a.uid} does not support user authorization.`;let s=await resolveFallbackConnector(e,n,t,r,o);if(!await attach(e,n,s.connector.uid,t)){if(s.kind===`created`){let t=`Could not attach ${s.connector.uid} to the linked project.`;try{await cleanupCreatedConnectionConnector({log:e.log,projectRoot:e.projectRoot,connectorId:s.connector.id,orgId:n.orgId})}catch(e){let n=e instanceof Error?e.message:String(e);throw Error(`${t} ${n}`)}throw e.signal?.throwIfAborted(),Error(t)}throw Error(`Could not attach ${s.connector.uid} to the linked project.`)}return e.log.success(`Attached ${s.connector.uid} connector`),s.kind===`created`?{kind:`created`,connectorUid:s.connector.uid,connectorId:s.connector.id}:{kind:`existing`,connectorUid:s.connector.uid}}export{cleanupCreatedConnectionConnector,parseCreatedConnector,setupConnectionConnector};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.45.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.45.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,n){let r=parseChatGptModelSelection(e);return r===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(r)}),\n${reasoningTemplateLine(n)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,n){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(n.model)!==void 0?renderAgentTemplate(n.model,n.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,n.appName).replaceAll(`__EVE_INIT_MODEL__`,n.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(n.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(n.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(n.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,n.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,n.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,n.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,n.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,n.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,n.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
|
|
2
2
|
|
|
3
3
|
export default defineAgent({
|
|
4
4
|
model: "__EVE_INIT_MODEL__",
|
|
@@ -2,7 +2,9 @@ export declare const WEB_APP_TEMPLATE_FILES: {
|
|
|
2
2
|
readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, placeholderAuth, vercelOidc } from "eve/channels/auth";\n\nexport default eveChannel({\n auth: [\n // Lets the eve TUI and your Vercel deployments reach the deployed agent.\n vercelOidc(),\n // Open on localhost for `eve dev` and the REPL; ignored in production.\n localDev(),\n // This placeholder will not allow browser requests in production.\n // Replace it with your app\'s auth provider, like Auth.js or Clerk,\n // or use none() for a public demo.\n placeholderAuth(),\n ],\n});\n';
|
|
3
3
|
readonly "app/_components/agent-chat.tsx": '"use client";\n\nimport type { UserContent } from "ai";\nimport { useEveAgent } from "eve/react";\nimport { AlertCircleIcon, BrainIcon, PlusIcon, SquareIcon } from "lucide-react";\nimport { useState } from "react";\nimport {\n Conversation,\n ConversationContent,\n ConversationScrollButton,\n ConversationTopFade,\n} from "@/components/ai-elements/conversation";\nimport { Message, MessageContent } from "@/components/ai-elements/message";\nimport {\n PromptInput,\n PromptInputButton,\n type PromptInputMessage,\n PromptInputSubmit,\n PromptInputTextarea,\n usePromptInputAttachments,\n} from "@/components/ai-elements/prompt-input";\nimport { Shimmer } from "@/components/ai-elements/shimmer";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\nimport { AgentMessage } from "./agent-message";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\nexport function AgentChat({\n sessionId,\n sessionless = false,\n}: {\n readonly sessionId?: string;\n readonly sessionless?: boolean;\n}) {\n const [cancellationError, setCancellationError] = useState<string>();\n const [hasInputText, setHasInputText] = useState(false);\n const agent = useEveAgent({\n initialSession:\n sessionId === undefined\n ? undefined\n : {\n sessionId,\n streamIndex: 0,\n },\n resume: sessionId !== undefined,\n onSessionChange(session) {\n if (sessionId === undefined && session !== undefined) {\n // Next patches window.history to navigate, which would detach the active stream.\n History.prototype.replaceState.call(\n window.history,\n window.history.state,\n "",\n `/s/${encodeURIComponent(session.sessionId)}`,\n );\n }\n },\n });\n\n const isBusy = agent.status === "submitted" || agent.status === "streaming";\n const isResuming = agent.status === "resuming";\n const isEmpty = agent.data.messages.length === 0;\n const lastMessage = agent.data.messages.at(-1);\n const isPendingAssistantShell =\n lastMessage?.role === "assistant" &&\n lastMessage.parts.every((part) => part.type === "step-start");\n const showPendingThinking =\n isBusy &&\n (agent.status === "submitted" || lastMessage?.role !== "assistant" || isPendingAssistantShell);\n const turnFailure = isBusy || isResuming ? undefined : getLatestTurnFailure(agent.events);\n const errorMessage = cancellationError ?? agent.error?.message ?? turnFailure;\n const hasConversationContent = sessionless || !isEmpty || errorMessage !== undefined;\n const showConversationLayout = isResuming || hasConversationContent;\n const activeSessionId = sessionId ?? agent.session?.sessionId;\n\n const requestCancellation = () => {\n setCancellationError(undefined);\n void agent.cancel().catch((error: unknown) => {\n setCancellationError(toErrorMessage(error));\n });\n };\n\n const handleSubmit = async (message: PromptInputMessage) => {\n const text = message.text.trim();\n if ((text.length === 0 && message.files.length === 0) || isResuming) return;\n\n setHasInputText(false);\n setCancellationError(undefined);\n const options = isBusy ? { turnPolicy: "steer" as const } : undefined;\n\n if (message.files.length === 0) {\n await agent.send(text, options);\n return;\n }\n\n const parts: UserContent = [];\n if (text.length > 0) {\n parts.push({ text, type: "text" });\n }\n for (const file of message.files) {\n parts.push({\n data: file.url,\n filename: file.filename,\n mediaType: file.mediaType,\n type: "file",\n });\n }\n\n await agent.send(parts, options);\n };\n\n const composer = (\n <PromptInput onSubmit={handleSubmit}>\n <PromptInputTextarea\n disabled={isResuming}\n onChange={(event) => setHasInputText(event.currentTarget.value.trim().length > 0)}\n placeholder="Send a message…"\n />\n <ComposerAction\n hasInputText={hasInputText}\n isBusy={isBusy}\n isResuming={isResuming}\n onCancel={requestCancellation}\n />\n </PromptInput>\n );\n\n return (\n <main className="flex h-dvh flex-col overflow-hidden bg-background text-foreground">\n {showConversationLayout ? (\n <ChatHeader canStartNewChat={activeSessionId !== undefined} />\n ) : null}\n\n {showConversationLayout ? (\n <Conversation\n className="min-h-0 flex-1"\n initial={sessionId === undefined ? undefined : false}\n resize={activeSessionId === undefined ? "smooth" : "instant"}\n scrollRestorationKey={\n isEmpty || activeSessionId === undefined\n ? undefined\n : `eve:web-chat-scroll:${activeSessionId}`\n }\n >\n <ConversationTopFade className="top-14" />\n <ConversationContent className="mx-auto w-full max-w-3xl gap-6 px-4 pt-20 pb-36 sm:px-6">\n {agent.data.messages.map((message, index) =>\n showPendingThinking &&\n isPendingAssistantShell &&\n message.id === lastMessage.id ? null : (\n <AgentMessage\n canRespond={!isBusy && !isResuming}\n isStreaming={\n agent.status === "streaming" && index === agent.data.messages.length - 1\n }\n key={message.id}\n message={message}\n onInputResponses={(inputResponses) => {\n setCancellationError(undefined);\n return agent.respond(inputResponses);\n }}\n />\n ),\n )}\n {showPendingThinking ? <PendingThinking /> : null}\n {errorMessage ? <ErrorMessage message={errorMessage} /> : null}\n </ConversationContent>\n <ConversationScrollButton />\n </Conversation>\n ) : null}\n\n <div\n className={cn(\n "mx-auto w-full px-4 sm:px-6",\n showConversationLayout\n ? "fixed bottom-0 left-1/2 z-20 max-w-3xl -translate-x-1/2 bg-gradient-to-t from-background via-background to-transparent pt-4 pb-6"\n : "flex max-w-xl flex-1 flex-col items-center justify-center gap-8 pb-[10vh]",\n )}\n >\n {showConversationLayout ? null : (\n <div className="flex flex-col items-center gap-3 text-center">\n <h1 className="font-medium text-5xl tracking-tighter">{AGENT_NAME}</h1>\n </div>\n )}\n <div className="w-full">{composer}</div>\n </div>\n </main>\n );\n}\n\nfunction ComposerAction({\n hasInputText,\n isBusy,\n isResuming,\n onCancel,\n}: {\n readonly hasInputText: boolean;\n readonly isBusy: boolean;\n readonly isResuming: boolean;\n readonly onCancel: () => void;\n}) {\n const attachments = usePromptInputAttachments();\n const canSubmit = hasInputText || attachments.files.length > 0;\n\n if (!isBusy || canSubmit) {\n return <PromptInputSubmit disabled={isResuming} />;\n }\n\n return (\n <PromptInputButton\n aria-label="Stop"\n className="absolute right-2.5 bottom-2.5"\n onClick={onCancel}\n variant="outline"\n >\n <SquareIcon className="size-3 fill-current" />\n </PromptInputButton>\n );\n}\n\nfunction ErrorMessage({ message }: { readonly message: string }) {\n return (\n <Message className="max-w-full" from="assistant">\n <MessageContent>\n <div\n className="flex w-full items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-sm"\n role="alert"\n >\n <AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />\n <div>\n <p className="font-medium">Request failed</p>\n <p className="mt-0.5 text-muted-foreground">{message}</p>\n </div>\n </div>\n </MessageContent>\n </Message>\n );\n}\n\nfunction ChatHeader({ canStartNewChat }: { readonly canStartNewChat: boolean }) {\n return (\n <header className="pointer-events-none fixed top-0 right-0 left-0 z-20 h-14">\n <div className="relative mx-auto flex h-full w-full max-w-3xl items-center justify-center bg-background px-24">\n <span className="truncate text-muted-foreground text-sm">{AGENT_NAME}</span>\n {canStartNewChat ? (\n <Button\n aria-label="Start a new chat"\n className="pointer-events-auto fixed top-3 right-6 pr-4"\n onClick={() => window.location.assign("/s")}\n size="sm"\n type="button"\n variant="ghost"\n >\n <PlusIcon className="size-4" />\n <span className="hidden font-normal text-sm sm:inline">New chat</span>\n </Button>\n ) : null}\n </div>\n </header>\n );\n}\n\nfunction PendingThinking() {\n return (\n <Message aria-live="polite" from="assistant">\n <MessageContent>\n <div className="mb-4 flex w-full items-center gap-2 text-muted-foreground text-sm">\n <BrainIcon className="size-4" />\n <Shimmer duration={1}>Thinking</Shimmer>\n </div>\n </MessageContent>\n </Message>\n );\n}\n\nfunction toErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : "Unable to cancel the response.";\n}\n\nfunction getLatestTurnFailure(\n events: ReturnType<typeof useEveAgent>["events"],\n): string | undefined {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n\n if (event.type === "turn.failed") {\n return event.data.code === "MODEL_CALL_FAILED"\n ? "The model is temporarily unavailable. Please try again."\n : event.data.message;\n }\n\n if (event.type === "turn.completed" || event.type === "turn.cancelled") {\n return undefined;\n }\n\n if (event.type === "message.received") {\n return undefined;\n }\n }\n\n return undefined;\n}\n';
|
|
4
4
|
readonly "app/_components/agent-message.tsx": '"use client";\n\nimport type {\n EveAuthorizationPart,\n EveDynamicToolPart,\n EveMessage,\n EveMessageInputRequest,\n EveMessagePart,\n} from "eve/react";\nimport { useState } from "react";\nimport {\n ArrowRightIcon,\n CheckCircleIcon,\n CheckIcon,\n ExternalLinkIcon,\n FileIcon,\n ImageIcon,\n KeyRoundIcon,\n XCircleIcon,\n} from "lucide-react";\nimport { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";\nimport {\n Question,\n QuestionInput,\n QuestionOption,\n QuestionOptions,\n QuestionPrompt,\n type QuestionResponse,\n QuestionSubmit,\n type QuestionValue,\n} from "@/components/ai-elements/question";\nimport { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";\nimport {\n BashToolContent,\n Tool,\n ToolContent,\n ToolHeader,\n ToolInput,\n ToolOutput,\n} from "@/components/ai-elements/tool";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\n\nexport type AgentInputResponse = {\n readonly optionId?: string;\n readonly requestId: string;\n readonly text?: string;\n};\n\ntype EveFilePart = Extract<EveMessagePart, { type: "file" }>;\n\nexport function AgentMessage({\n canRespond,\n isStreaming,\n message,\n onInputResponses,\n}: {\n readonly canRespond: boolean;\n readonly isStreaming: boolean;\n readonly message: EveMessage;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n const lastTextIndex = message.parts.reduce(\n (last, part, index) => (part.type === "text" ? index : last),\n -1,\n );\n const hasAssistantText =\n message.role === "assistant" &&\n message.parts.some((part) => part.type === "text" && part.text.length > 0);\n\n return (\n <Message\n data-optimistic={message.metadata?.optimistic ? "true" : undefined}\n from={message.role}\n >\n <MessageContent>\n {message.parts.map((part, index) =>\n hasAssistantText && part.type === "reasoning" ? null : (\n <AgentMessagePart\n canRespond={canRespond}\n key={partKey(part, index)}\n onInputResponses={onInputResponses}\n part={part}\n showCaret={isStreaming && message.role === "assistant" && index === lastTextIndex}\n />\n ),\n )}\n </MessageContent>\n </Message>\n );\n}\n\nfunction AgentMessagePart({\n canRespond,\n onInputResponses,\n part,\n showCaret,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveMessagePart;\n readonly showCaret: boolean;\n}) {\n switch (part.type) {\n case "step-start":\n return null;\n case "text":\n return (\n <MessageResponse caret="block" isAnimating={showCaret}>\n {part.text}\n </MessageResponse>\n );\n case "reasoning":\n return (\n <Reasoning defaultOpen isStreaming={part.state === "streaming"}>\n <ReasoningTrigger />\n <ReasoningContent>{part.text}</ReasoningContent>\n </Reasoning>\n );\n case "file":\n return <AttachmentPart part={part} />;\n case "authorization":\n return <AuthorizationPrompt part={part} />;\n case "dynamic-tool": {\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n if (inputRequest?.kind === "question") {\n return (\n <QuestionRequest\n canRespond={canRespond}\n inputRequest={inputRequest}\n inputResponse={part.toolMetadata?.eve?.inputResponse}\n onInputResponses={onInputResponses}\n />\n );\n }\n\n return (\n <Tool\n defaultOpen={part.state === "approval-requested" || part.state === "approval-responded"}\n >\n <ToolHeader\n state={part.state}\n title={part.toolName}\n toolName={part.toolName}\n type="dynamic-tool"\n />\n <ToolContent>\n {part.toolName === "bash" ? (\n <BashToolContent errorText={part.errorText} input={part.input} output={part.output} />\n ) : (\n <ToolInput input={part.input} />\n )}\n <InputRequestActions\n canRespond={canRespond}\n part={part}\n onInputResponses={onInputResponses}\n />\n {part.toolName === "bash" ? null : (\n <ToolOutput errorText={part.errorText} output={part.output} />\n )}\n </ToolContent>\n </Tool>\n );\n }\n }\n}\n\nfunction QuestionRequest({\n canRespond,\n inputRequest,\n inputResponse,\n onInputResponses,\n}: {\n readonly canRespond: boolean;\n readonly inputRequest: EveMessageInputRequest;\n readonly inputResponse?: AgentInputResponse;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n const hasOptions = (inputRequest.options?.length ?? 0) > 0;\n const acceptsFreeform = inputRequest.allowFreeform === true || !hasOptions;\n const [questionValue, setQuestionValue] = useState<QuestionValue>({\n selectedValues: inputResponse?.optionId ? [inputResponse.optionId] : [],\n text: inputResponse?.text ?? "",\n });\n\n const submitOption = (optionId: string) => {\n setQuestionValue((value) => ({ ...value, selectedValues: [optionId] }));\n return onInputResponses([\n {\n optionId,\n requestId: inputRequest.requestId,\n },\n ]);\n };\n\n const submitResponse = ({ selectedValues, text }: QuestionResponse) =>\n onInputResponses([\n {\n optionId: selectedValues[0],\n requestId: inputRequest.requestId,\n text,\n },\n ]);\n\n return (\n <Question\n disabled={!canRespond || inputResponse !== undefined}\n onSubmit={submitResponse}\n onValueChange={setQuestionValue}\n value={questionValue}\n >\n <QuestionPrompt>{inputRequest.prompt}</QuestionPrompt>\n {hasOptions ? (\n <QuestionOptions className="flex-col items-stretch" aria-label={inputRequest.prompt}>\n {inputRequest.options?.map((option, index) => (\n <QuestionOption\n className="justify-start px-3 py-2 text-left"\n key={option.id}\n onClick={() => void submitOption(option.id)}\n value={option.id}\n >\n <span className="min-w-0 flex-1">\n <span className="block text-foreground text-sm leading-tight">{option.label}</span>\n {option.description ? (\n <span className="block text-sm text-muted-foreground leading-tight">\n {option.description}\n </span>\n ) : null}\n </span>\n {inputResponse === undefined ? (\n <span aria-hidden="true" className="relative size-6 shrink-0">\n <span className="absolute inset-0 flex items-center justify-center rounded-full bg-foreground/8 text-xs text-muted-foreground transition-opacity group-hover/option:opacity-0 group-focus-visible/option:opacity-0">\n {index + 1}\n </span>\n <ArrowRightIcon className="absolute top-1/2 left-1/2 size-4 -translate-x-1/2 -translate-y-1/2 text-muted-foreground opacity-0 transition-[color,opacity] group-hover/option:text-foreground group-hover/option:opacity-100 group-focus-visible/option:opacity-100" />\n </span>\n ) : (\n <CheckIcon className="size-4 shrink-0 opacity-0 transition-opacity group-data-[state=checked]/option:opacity-100" />\n )}\n </QuestionOption>\n ))}\n </QuestionOptions>\n ) : null}\n {acceptsFreeform ? (\n <div className="relative">\n <QuestionInput\n aria-label="Answer"\n className={inputResponse === undefined ? "pr-12 pb-12" : undefined}\n placeholder="Type your answer…"\n />\n {inputResponse === undefined && questionValue.text.trim().length > 0 ? (\n <QuestionSubmit\n aria-label="Answer"\n className="absolute right-2 bottom-2"\n size="icon-sm"\n >\n <ArrowRightIcon />\n </QuestionSubmit>\n ) : null}\n </div>\n ) : null}\n </Question>\n );\n}\n\nfunction AttachmentPart({ part }: { readonly part: EveFilePart }) {\n const label = part.filename ?? "Attachment";\n const detail = [part.mediaType, formatBytes(part.size)].filter(Boolean).join(" - ");\n const isImage = part.mediaType.startsWith("image/") && part.url !== undefined;\n const Icon = isImage ? ImageIcon : FileIcon;\n const body = (\n <span className="flex max-w-sm items-center gap-3 rounded-md border bg-background/60 p-2 text-sm">\n {isImage ? (\n <img alt={label} className="size-12 shrink-0 rounded-sm object-cover" src={part.url} />\n ) : (\n <span className="flex size-10 shrink-0 items-center justify-center rounded-sm bg-muted text-muted-foreground">\n <Icon className="size-4" />\n </span>\n )}\n <span className="min-w-0 flex-1">\n <span className="block truncate font-medium">{label}</span>\n {detail ? <span className="block truncate text-muted-foreground">{detail}</span> : null}\n </span>\n {part.url ? <ExternalLinkIcon className="size-4 shrink-0 text-muted-foreground" /> : null}\n </span>\n );\n\n return part.url ? (\n <a href={part.url} rel="noreferrer" target="_blank">\n {body}\n </a>\n ) : (\n body\n );\n}\n\nfunction AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {\n const isAuthorized = part.state === "completed" && part.outcome === "authorized";\n const isCompleted = part.state === "completed";\n const Icon = isAuthorized ? CheckCircleIcon : isCompleted ? XCircleIcon : KeyRoundIcon;\n const instructions = part.authorization?.instructions;\n const shouldShowInstructions = instructions !== undefined && instructions !== part.description;\n\n return (\n <div\n className={cn(\n "space-y-3 rounded-md border p-3",\n isAuthorized\n ? "border-emerald-500/30 bg-emerald-500/5"\n : isCompleted\n ? "border-destructive/30 bg-destructive/5"\n : "border-blue-500/30 bg-blue-500/5",\n )}\n >\n <div className="flex items-start gap-3">\n <span\n className={cn(\n "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full",\n isAuthorized\n ? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"\n : isCompleted\n ? "bg-destructive/10 text-destructive"\n : "bg-blue-500/10 text-blue-700 dark:text-blue-300",\n )}\n >\n <Icon className="size-4" />\n </span>\n <div className="min-w-0 flex-1 space-y-2">\n <p className="font-medium text-sm">{authorizationTitle(part)}</p>\n <p className="text-muted-foreground text-sm">{authorizationDescription(part)}</p>\n {shouldShowInstructions ? (\n <p className="text-muted-foreground text-sm">{instructions}</p>\n ) : null}\n {part.state === "required" && part.authorization?.userCode ? (\n <div className="flex flex-wrap items-center gap-2 text-sm">\n <span className="text-muted-foreground">Code</span>\n <code className="rounded-md bg-background px-2 py-1 font-mono">\n {part.authorization.userCode}\n </code>\n </div>\n ) : null}\n {part.state === "required" && part.authorization?.url ? (\n <Button asChild size="sm">\n <a href={part.authorization.url} rel="noreferrer" target="_blank">\n <ExternalLinkIcon className="size-4" />\n Sign in with {part.displayName}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nfunction authorizationTitle(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return `Connect ${part.displayName}`;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected`;\n }\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}`;\n}\n\nfunction authorizationDescription(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return part.description;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected.`;\n }\n const tail = part.reason !== undefined ? ` (${part.reason})` : "";\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}${tail}.`;\n}\n\nfunction formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["outcome"]>): string {\n switch (outcome) {\n case "authorized":\n return "authorized";\n case "declined":\n return "declined";\n case "failed":\n return "failed";\n case "timed-out":\n return "timed out";\n }\n}\n\nfunction formatBytes(size: number | undefined): string | undefined {\n if (size === undefined) {\n return undefined;\n }\n if (size < 1024) {\n return `${size} B`;\n }\n if (size < 1024 * 1024) {\n return `${(size / 1024).toFixed(1)} KB`;\n }\n return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction InputRequestActions({\n canRespond,\n onInputResponses,\n part,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveDynamicToolPart;\n}) {\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n if (!inputRequest) {\n return null;\n }\n\n const inputResponse = part.toolMetadata?.eve?.inputResponse;\n const selectedOption = inputRequest.options?.find(\n (option) => option.id === inputResponse?.optionId,\n );\n\n return (\n <div className="space-y-3 rounded-md border border-yellow-500/30 bg-yellow-500/5 p-3">\n <p className="text-muted-foreground text-sm">{inputRequest.prompt}</p>\n {inputResponse ? (\n <p className="font-medium text-sm">\n Responded: {selectedOption?.label ?? inputResponse.text ?? inputResponse.optionId}\n </p>\n ) : (\n <div className="flex flex-wrap gap-2">\n {inputRequest.options?.map((option) => (\n <Button\n disabled={!canRespond}\n key={option.id}\n onClick={() => {\n void onInputResponses([\n {\n optionId: option.id,\n requestId: inputRequest.requestId,\n },\n ]);\n }}\n size="sm"\n type="button"\n variant={option.style === "danger" ? "destructive" : "default"}\n >\n {option.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction partKey(part: EveMessagePart, index: number): string {\n switch (part.type) {\n case "authorization":\n return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;\n case "dynamic-tool":\n return part.toolCallId;\n default:\n return `${part.type}:${index}`;\n }\n}\n';
|
|
5
|
+
readonly "app/apple-icon.tsx": 'import { ImageResponse } from "next/og";\n\nexport const size = {\n width: 180,\n height: 180,\n};\n\nexport const contentType = "image/png";\n\nexport default function AppleIcon() {\n return new ImageResponse(\n <svg fill="none" viewBox="0 0 102 102" xmlns="http://www.w3.org/2000/svg">\n <path d="M0 0h102v102H0z" fill="#000" />\n <path\n d="M49.28 66.94 75.03 34.96h-6.89L47.91 60.11l-5.49 6.83h6.86ZM0 34.96h42.4v5.11H0zm0 13.32h27.66v5.11H0zm0 13.54h27.66v5.11H0zm69.63-26.86H102v5.11H69.63zm4.71 13.32H102v5.11H74.34zm0 13.54H102v5.11H74.34z"\n fill="#fff"\n />\n </svg>,\n size,\n );\n}\n';
|
|
5
6
|
readonly "app/globals.css": '@import "tailwindcss";\n@source "../node_modules/streamdown/dist/*.js";\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;\n --font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, monospace;\n}\n\n:root {\n color-scheme: light;\n /* Soft neutral page with white elevated surfaces so cards/composer pop. */\n --background: oklch(0.971 0 0);\n --foreground: oklch(0.16 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.16 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.16 0 0);\n --primary: oklch(0.19 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.94 0 0);\n --secondary-foreground: oklch(0.19 0 0);\n --muted: oklch(0.94 0 0);\n --muted-foreground: oklch(0.6 0 0);\n --accent: oklch(0.94 0 0);\n --accent-foreground: oklch(0.19 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.916 0 0);\n --input: oklch(0.916 0 0);\n --ring: oklch(0.708 0 0);\n --radius: 0.625rem;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n color-scheme: dark;\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n }\n}\n\n* {\n border-color: var(--border);\n}\n\nhtml {\n height: 100%;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nbody {\n min-height: 100%;\n margin: 0;\n background: var(--background);\n font-family: var(--font-sans);\n}\n\nbutton,\ninput,\ntextarea {\n font: inherit;\n}\n';
|
|
7
|
+
readonly "app/icon.svg": '<svg width="102" height="102" viewBox="0 0 102 102" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path fill="#000" d="M0 0h102v102H0z" />\n <path\n fill="#fff"\n d="M49.28 66.94 75.03 34.96h-6.89L47.91 60.11l-5.49 6.83h6.86ZM0 34.96h42.4v5.11H0zm0 13.32h27.66v5.11H0zm0 13.54h27.66v5.11H0zm69.63-26.86H102v5.11H69.63zm4.71 13.32H102v5.11H74.34zm0 13.54H102v5.11H74.34z"\n />\n</svg>\n';
|
|
6
8
|
readonly "app/layout.tsx": 'import type { Metadata } from "next";\nimport { Geist, Geist_Mono } from "next/font/google";\nimport type { ReactNode } from "react";\nimport { TooltipProvider } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport "./globals.css";\n\nconst sans = Geist({\n variable: "--font-sans",\n subsets: ["latin"],\n weight: "variable",\n display: "swap",\n});\n\nconst mono = Geist_Mono({\n variable: "--font-mono",\n subsets: ["latin"],\n weight: "variable",\n display: "swap",\n});\n\nexport const metadata: Metadata = {\n title: "__EVE_INIT_APP_NAME__",\n description: "A Next.js starter for eve agents with AI Elements.",\n};\n\nexport default function RootLayout({ children }: { readonly children: ReactNode }) {\n return (\n <html className={cn(sans.variable, mono.variable)} lang="en">\n <body>\n <TooltipProvider>{children}</TooltipProvider>\n </body>\n </html>\n );\n}\n';
|
|
7
9
|
readonly "app/page.tsx": 'import { AgentChat } from "@/app/_components/agent-chat";\n\nexport default function Page() {\n return <AgentChat />;\n}\n';
|
|
8
10
|
readonly "app/s/[sessionId]/page.tsx": 'import { AgentChat } from "@/app/_components/agent-chat";\n\nexport default async function SessionPage({\n params,\n}: {\n readonly params: Promise<{ readonly sessionId: string }>;\n}) {\n const { sessionId } = await params;\n return <AgentChat sessionId={sessionId} />;\n}\n';
|
|
@@ -780,6 +780,27 @@ function partKey(part: EveMessagePart, index: number): string {
|
|
|
780
780
|
return \`\${part.type}:\${index}\`;
|
|
781
781
|
}
|
|
782
782
|
}
|
|
783
|
+
`,"app/apple-icon.tsx":`import { ImageResponse } from "next/og";
|
|
784
|
+
|
|
785
|
+
export const size = {
|
|
786
|
+
width: 180,
|
|
787
|
+
height: 180,
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
export const contentType = "image/png";
|
|
791
|
+
|
|
792
|
+
export default function AppleIcon() {
|
|
793
|
+
return new ImageResponse(
|
|
794
|
+
<svg fill="none" viewBox="0 0 102 102" xmlns="http://www.w3.org/2000/svg">
|
|
795
|
+
<path d="M0 0h102v102H0z" fill="#000" />
|
|
796
|
+
<path
|
|
797
|
+
d="M49.28 66.94 75.03 34.96h-6.89L47.91 60.11l-5.49 6.83h6.86ZM0 34.96h42.4v5.11H0zm0 13.32h27.66v5.11H0zm0 13.54h27.66v5.11H0zm69.63-26.86H102v5.11H69.63zm4.71 13.32H102v5.11H74.34zm0 13.54H102v5.11H74.34z"
|
|
798
|
+
fill="#fff"
|
|
799
|
+
/>
|
|
800
|
+
</svg>,
|
|
801
|
+
size,
|
|
802
|
+
);
|
|
803
|
+
}
|
|
783
804
|
`,"app/globals.css":`@import "tailwindcss";
|
|
784
805
|
@source "../node_modules/streamdown/dist/*.js";
|
|
785
806
|
|
|
@@ -880,6 +901,13 @@ input,
|
|
|
880
901
|
textarea {
|
|
881
902
|
font: inherit;
|
|
882
903
|
}
|
|
904
|
+
`,"app/icon.svg":`<svg width="102" height="102" viewBox="0 0 102 102" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
905
|
+
<path fill="#000" d="M0 0h102v102H0z" />
|
|
906
|
+
<path
|
|
907
|
+
fill="#fff"
|
|
908
|
+
d="M49.28 66.94 75.03 34.96h-6.89L47.91 60.11l-5.49 6.83h6.86ZM0 34.96h42.4v5.11H0zm0 13.32h27.66v5.11H0zm0 13.54h27.66v5.11H0zm69.63-26.86H102v5.11H69.63zm4.71 13.32H102v5.11H74.34zm0 13.54H102v5.11H74.34z"
|
|
909
|
+
/>
|
|
910
|
+
</svg>
|
|
883
911
|
`,"app/layout.tsx":`import type { Metadata } from "next";
|
|
884
912
|
import { Geist, Geist_Mono } from "next/font/google";
|
|
885
913
|
import type { ReactNode } from "react";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const MEMORY_DEFINITION_BRAND=Symbol.for(`eve:memory-definition`);function isMemoryDefinition(e){return typeof e==`object`&&!!e&&Reflect.get(e,MEMORY_DEFINITION_BRAND)===!0}export{MEMORY_DEFINITION_BRAND,isMemoryDefinition};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
import type { LockedMemorySlot } from "#context/keys.js";
|
|
3
|
+
import type { SessionStateMap } from "#harness/types.js";
|
|
4
|
+
import type { MemoryRecallResult, MemoryScopeResolverResult } from "#public/memory/index.js";
|
|
5
|
+
export declare const MEMORY_NAMESPACE_MAX_BYTES = 1024;
|
|
6
|
+
export declare const MEMORY_SCOPE_COMPONENT_MAX_BYTES = 1024;
|
|
7
|
+
export declare const MEMORY_SCOPE_TUPLE_MAX_COMPONENTS = 16;
|
|
8
|
+
export declare const MEMORY_CANONICAL_KEY_INPUT_MAX_BYTES = 4096;
|
|
9
|
+
export declare const MEMORY_ITEM_ID_MAX_BYTES = 1024;
|
|
10
|
+
export declare const MEMORY_RAW_RECORD_MAX_COUNT = 512;
|
|
11
|
+
export declare const MEMORY_RAW_RECORD_MAX_BYTES = 262144;
|
|
12
|
+
export interface InternalMemoryLock extends LockedMemorySlot {
|
|
13
|
+
readonly namespaceKey: string;
|
|
14
|
+
readonly scopeKey: string;
|
|
15
|
+
}
|
|
16
|
+
export interface NormalizedMemoryRecallMessage {
|
|
17
|
+
readonly content: string;
|
|
18
|
+
readonly itemKey?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface MemoryRecallBatch {
|
|
21
|
+
readonly lock: InternalMemoryLock;
|
|
22
|
+
readonly messages: readonly NormalizedMemoryRecallMessage[];
|
|
23
|
+
readonly operationId: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function createMemoryLock(input: {
|
|
26
|
+
readonly namespace: string;
|
|
27
|
+
readonly scope: Exclude<MemoryScopeResolverResult, null>;
|
|
28
|
+
readonly slot: string;
|
|
29
|
+
readonly turn: LockedMemorySlot["turn"];
|
|
30
|
+
readonly visibility: LockedMemorySlot["visibility"];
|
|
31
|
+
}): InternalMemoryLock;
|
|
32
|
+
export declare function validateMemoryRecallResult(result: MemoryRecallResult, slot: string): readonly NormalizedMemoryRecallMessage[];
|
|
33
|
+
export declare function applyMemoryRecallBatches(input: {
|
|
34
|
+
readonly batches: readonly MemoryRecallBatch[];
|
|
35
|
+
readonly history: readonly ModelMessage[];
|
|
36
|
+
readonly state: SessionStateMap | undefined;
|
|
37
|
+
}): {
|
|
38
|
+
readonly history: ModelMessage[];
|
|
39
|
+
readonly state: SessionStateMap;
|
|
40
|
+
};
|
|
41
|
+
export declare function projectMemoryHistory(input: {
|
|
42
|
+
readonly locks: Readonly<Record<string, InternalMemoryLock>>;
|
|
43
|
+
readonly messages: readonly ModelMessage[];
|
|
44
|
+
}): readonly ModelMessage[];
|
|
45
|
+
export declare function projectMemoryHistoryFromSessionState(input: {
|
|
46
|
+
readonly messages: readonly ModelMessage[];
|
|
47
|
+
readonly state: SessionStateMap | undefined;
|
|
48
|
+
}): readonly ModelMessage[];
|
|
49
|
+
export declare function canonicalizeMemoryRecords(messages: readonly ModelMessage[]): {
|
|
50
|
+
readonly memory: ModelMessage[];
|
|
51
|
+
readonly ordinary: ModelMessage[];
|
|
52
|
+
};
|
|
53
|
+
export declare function shouldCanonicalizeMemory(messages: readonly ModelMessage[]): boolean;
|
|
54
|
+
export declare function clearMemorySessionState(state: SessionStateMap | undefined): SessionStateMap;
|
|
55
|
+
export declare function readMemoryLocks(state: SessionStateMap | undefined): Readonly<Record<string, InternalMemoryLock>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash}from"node:crypto";import{identityHistoryViewProjector}from"#shared/history-view.js";const MEMORY_NAMESPACE_MAX_BYTES=1024,MEMORY_SCOPE_COMPONENT_MAX_BYTES=1024,MEMORY_SCOPE_TUPLE_MAX_COMPONENTS=16,MEMORY_CANONICAL_KEY_INPUT_MAX_BYTES=4096,MEMORY_ITEM_ID_MAX_BYTES=1024,MEMORY_RAW_RECORD_MAX_COUNT=512,MEMORY_RAW_RECORD_MAX_BYTES=262144,MEMORY_MESSAGE_METADATA_KEY=`eve.memory`,MEMORY_SESSION_STATE_KEY=`eve.memory`;function createMemoryLock(e){validateMemoryNamespace(e.namespace),validateMemoryScopeValue(e.scope);let t=encodeScalar(`namespace`,e.namespace),n=encodeScope(e.scope);if(t.byteLength+n.byteLength>4096)throw Error(`Memory slot "${e.slot}" namespace and scope encoding exceeds ${MEMORY_CANONICAL_KEY_INPUT_MAX_BYTES} UTF-8 bytes.`);let r=digest(`memns1_`,t),i=digest(`memscope1_`,n),o=Buffer.concat([Buffer.from(`eve-memory-composite-v1\0`),lengthPrefix(Buffer.from(r)),lengthPrefix(Buffer.from(i))]),s=Object.freeze({key:digest(`memscope1_`,o),namespace:e.namespace,value:Array.isArray(e.scope)?Object.freeze([...e.scope]):e.scope});return Object.freeze({namespaceKey:r,scope:s,scopeKey:i,slot:e.slot,turn:e.turn,visibility:e.visibility})}function validateMemoryRecallResult(e,t){if(e==null)return[];if(typeof e!=`object`||Array.isArray(e))throw Error(`Memory slot "${t}" recall() must return { messages }, null, or undefined.`);let n=Object.keys(e).filter(e=>e!==`messages`);if(n.length>0)throw Error(`Memory slot "${t}" recall() returned unknown key(s): ${n.join(`, `)}.`);if(!Array.isArray(e.messages))throw Error(`Memory slot "${t}" recall().messages must be an array.`);let r=new Set;return e.messages.map((e,n)=>{if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Memory slot "${t}" recall message ${n} must be an object.`);let i=Object.keys(e).filter(e=>e!==`content`&&e!==`id`);if(i.length>0)throw Error(`Memory slot "${t}" recall message ${n} has unknown key(s): ${i.join(`, `)}.`);if(typeof e.content!=`string`||e.content.trim().length===0)throw Error(`Memory slot "${t}" recall message ${n} content must be non-blank.`);if(e.id===void 0)return Object.freeze({content:e.content});if(typeof e.id!=`string`||e.id.length===0)throw Error(`Memory slot "${t}" recall message ${n} id must be non-empty.`);if(utf8Bytes(e.id)>1024)throw Error(`Memory slot "${t}" recall message ${n} id exceeds ${MEMORY_ITEM_ID_MAX_BYTES} UTF-8 bytes.`);if(r.has(e.id))throw Error(`Memory slot "${t}" recall() returned duplicate id "${e.id}".`);return r.add(e.id),Object.freeze({content:e.content,itemKey:digest(`memitem1_`,encodeScalar(`item`,e.id))})})}function applyMemoryRecallBatches(e){let t={...readMemorySessionState(e.state).operationDigests},n=latestKeyedRecords(e.history),r=[];for(let i of e.batches){let e=recallBatchDigest(i.messages),a=t[i.operationId];if(a!==void 0){if(a!==e)throw Error(`Memory recall operation "${i.operationId}" replayed with a different result.`);continue}t[i.operationId]=e;for(let[e,t]of i.messages.entries()){let a={batchIndex:e,itemKey:t.itemKey,namespaceKey:i.lock.namespaceKey,operationId:i.operationId,scopeKey:i.lock.scopeKey,slot:i.lock.slot,version:1};if(t.itemKey!==void 0){let e=memoryItemIdentity(a);if(n.get(e)?.content===t.content)continue;n.set(e,{attribution:a,content:t.content})}r.push(attributeMemoryRecord(t.content,a))}}let i=Object.fromEntries(Object.entries(t).slice(-1024));return{history:[...e.history,...r],state:writeMemorySessionState(e.state,{locks:Object.fromEntries(e.batches.map(e=>[e.lock.slot,e.lock])),operationDigests:i})}}function projectMemoryHistory(e){let t=latestKeyedRecordIndexes(e.messages);return e.messages.flatMap((n,r)=>{let i=readMemoryRecordAttribution(n);if(i===null)return[n];let a=e.locks[i.slot];return a===void 0||a.namespaceKey!==i.namespaceKey||a.visibility===`scope`&&a.scopeKey!==i.scopeKey||i.itemKey!==void 0&&t.get(memoryItemIdentity(i))!==r?[]:[stripMemoryRecordAttribution(n)]})}function projectMemoryHistoryFromSessionState(e){let n=identityHistoryViewProjector(e);return projectMemoryHistory({locks:readMemorySessionState(e.state).locks,messages:n})}function canonicalizeMemoryRecords(e){let t=latestKeyedRecordIndexes(e),n=[],r=[];for(let[i,a]of e.entries()){let e=readMemoryRecordAttribution(a);if(e===null){r.push(a);continue}(e.itemKey===void 0||t.get(memoryItemIdentity(e))===i)&&n.push(a)}return{memory:n,ordinary:r}}function shouldCanonicalizeMemory(e){let t=0,n=0;for(let r of e)readMemoryRecordAttribution(r)!==null&&(t+=1,n+=serializedBytes(r));return t>512||n>262144}function clearMemorySessionState(e){if(e===void 0||!Object.hasOwn(e,MEMORY_SESSION_STATE_KEY))return e??{};let{[MEMORY_SESSION_STATE_KEY]:t,...n}=e;return n}function readMemoryLocks(e){return readMemorySessionState(e).locks}function validateMemoryNamespace(e){if(e.trim().length===0)throw Error(`Memory namespace must be non-empty.`);if(utf8Bytes(e)>1024)throw Error(`Memory namespace exceeds ${MEMORY_NAMESPACE_MAX_BYTES} UTF-8 bytes.`)}function validateMemoryScopeValue(e){let t=Array.isArray(e)?e:[e];if(Array.isArray(e)&&t.length>16)throw Error(`Memory scope tuple exceeds 16 components.`);if(t.length===0)throw Error(`Memory scope tuple must not be empty.`);for(let[e,n]of t.entries()){if(typeof n!=`string`||n.trim().length===0)throw Error(`Memory scope component ${e} must be a non-empty string.`);if(utf8Bytes(n)>1024)throw Error(`Memory scope component ${e} exceeds ${MEMORY_SCOPE_COMPONENT_MAX_BYTES} UTF-8 bytes.`)}}function encodeScope(e){return typeof e==`string`?encodeScalar(`scope-scalar`,e):Buffer.concat([Buffer.from(`scope-tuple-v1\0`),uint32(e.length),...e.map(e=>lengthPrefix(Buffer.from(e,`utf8`)))])}function encodeScalar(e,t){return Buffer.concat([Buffer.from(`${e}-v1\0`),lengthPrefix(Buffer.from(t,`utf8`))])}function lengthPrefix(e){return Buffer.concat([uint32(e.byteLength),e])}function uint32(e){let t=Buffer.allocUnsafe(4);return t.writeUInt32BE(e),t}function digest(t,n){return`${t}${createHash(`sha256`).update(n).digest(`base64url`)}`}function recallBatchDigest(t){return createHash(`sha256`).update(JSON.stringify(t)).digest(`base64url`)}function attributeMemoryRecord(e,t){return{content:e,metadata:{[MEMORY_MESSAGE_METADATA_KEY]:t},role:`user`}}function readMemoryRecordAttribution(e){if(typeof e!=`object`||!e)return null;let t=Reflect.get(e,`metadata`);if(typeof t!=`object`||!t)return null;let n=Reflect.get(t,MEMORY_MESSAGE_METADATA_KEY);if(typeof n!=`object`||!n)return null;let r=n;if(r.version!==1||typeof r.batchIndex!=`number`||typeof r.namespaceKey!=`string`||typeof r.operationId!=`string`||typeof r.scopeKey!=`string`||typeof r.slot!=`string`||r.itemKey!==void 0&&typeof r.itemKey!=`string`)throw Error(`Durable history contains invalid eve memory attribution.`);return r}function stripMemoryRecordAttribution(e){let t=Reflect.get(e,`metadata`);if(typeof t!=`object`||!t)return e;let{[MEMORY_MESSAGE_METADATA_KEY]:n,...r}=t,{metadata:i,...a}=e;return Object.keys(r).length===0?a:Object.assign(a,{metadata:r})}function latestKeyedRecordIndexes(e){let t=new Map;for(let[n,r]of e.entries()){let e=readMemoryRecordAttribution(r);e?.itemKey!==void 0&&t.set(memoryItemIdentity(e),n)}return t}function latestKeyedRecords(e){let t=new Map;for(let n of e){let e=readMemoryRecordAttribution(n);if(e?.itemKey===void 0)continue;let r=Reflect.get(n,`content`),i=typeof r==`string`?r:``;t.set(memoryItemIdentity(e),{attribution:e,content:i})}return t}function memoryItemIdentity(e){return JSON.stringify([e.slot,e.namespaceKey,e.scopeKey,e.itemKey])}function readMemorySessionState(e){let t=e?.[MEMORY_SESSION_STATE_KEY];if(typeof t!=`object`||!t||Array.isArray(t))return{locks:{},operationDigests:{}};let n=Reflect.get(t,`locks`),r=Reflect.get(t,`operationDigests`);return{locks:typeof n==`object`&&n&&!Array.isArray(n)?n:{},operationDigests:typeof r==`object`&&r&&!Array.isArray(r)?r:{}}}function writeMemorySessionState(e,t){return{...e,[MEMORY_SESSION_STATE_KEY]:t}}function serializedBytes(e){return Buffer.byteLength(JSON.stringify(e),`utf8`)}function utf8Bytes(e){return Buffer.byteLength(e,`utf8`)}export{MEMORY_CANONICAL_KEY_INPUT_MAX_BYTES,MEMORY_ITEM_ID_MAX_BYTES,MEMORY_NAMESPACE_MAX_BYTES,MEMORY_RAW_RECORD_MAX_BYTES,MEMORY_RAW_RECORD_MAX_COUNT,MEMORY_SCOPE_COMPONENT_MAX_BYTES,MEMORY_SCOPE_TUPLE_MAX_COMPONENTS,applyMemoryRecallBatches,canonicalizeMemoryRecords,clearMemorySessionState,createMemoryLock,projectMemoryHistory,projectMemoryHistoryFromSessionState,readMemoryLocks,shouldCanonicalizeMemory,validateMemoryRecallResult};
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.js
CHANGED
package/docs/channels/eve.mdx
CHANGED
|
@@ -34,7 +34,7 @@ The default eve channel inspects the agent, creates sessions, accepts callbacks
|
|
|
34
34
|
|
|
35
35
|
The session routes use only durable session IDs. Create a session explicitly, then put its returned ID in every follow-up, control, and stream path.
|
|
36
36
|
|
|
37
|
-
`GET /eve/v1/health` is public and returns `{ ok: true, status: "ready", workflowId: string }`. `GET /eve/v1/info` uses the channel's auth policy and returns agent-info version
|
|
37
|
+
`GET /eve/v1/health` is public and returns `{ ok: true, status: "ready", workflowId: string }`. `GET /eve/v1/info` uses the channel's auth policy and returns agent-info version 4. The TypeScript client validates both successful payloads: malformed health JSON throws `HealthResponseError`, malformed inspection JSON throws `AgentInfoResponseError`, and a non-success response from either route throws `ClientError`.
|
|
38
38
|
|
|
39
39
|
### Start and continue a session
|
|
40
40
|
|
|
@@ -16,6 +16,7 @@ Control context by putting information in the narrowest surface that needs it. K
|
|
|
16
16
|
| Files or command execution | The [sandbox workspace](../sandbox) | A workspace hint, then files and command output the model requests through tools |
|
|
17
17
|
| A specialist with a separate prompt and capabilities | A [subagent](../subagents) | Only the subagent's final result in the parent context |
|
|
18
18
|
| Instructions or capabilities that vary by caller | A [dynamic capability](../guides/dynamic-capabilities) | The values resolved for the active session |
|
|
19
|
+
| Scoped context retrieved from cross-session storage | [Memory](../memory) | Attributed user-role messages recalled before the current delivery |
|
|
19
20
|
|
|
20
21
|
## Base identity with `instructions.md`
|
|
21
22
|
|
|
@@ -59,6 +60,11 @@ See [Dynamic capabilities](../guides/dynamic-capabilities) for the resolver API,
|
|
|
59
60
|
|
|
60
61
|
User-role instructions follow the normal history lifecycle. Compaction can summarize them, and clear removes them without rerunning their static definitions or dynamic resolvers. System-role instructions remain outside history and continue to apply after either operation.
|
|
61
62
|
|
|
63
|
+
Recalled memory also uses user-role messages, but eve keeps their attribution
|
|
64
|
+
separate. Compaction excludes them from the summary, preserves their canonical
|
|
65
|
+
records, and recalls again after the checkpoint. Clear removes those session
|
|
66
|
+
records without deleting the provider's external data.
|
|
67
|
+
|
|
62
68
|
## What to read next
|
|
63
69
|
|
|
64
70
|
- [Instructions](../instructions): author the always-on system prompt.
|
|
@@ -66,3 +72,4 @@ User-role instructions follow the normal history lifecycle. Compaction can summa
|
|
|
66
72
|
- [Sandbox](../sandbox): give the model files and command execution.
|
|
67
73
|
- [Subagents](../subagents): isolate specialist work.
|
|
68
74
|
- [Dynamic capabilities](../guides/dynamic-capabilities): vary context and capabilities by session.
|
|
75
|
+
- [Memory](../memory): retrieve scoped context from storage that outlives a session.
|
|
@@ -20,6 +20,11 @@ export default defineAgent({
|
|
|
20
20
|
|
|
21
21
|
Compaction also preserves the framework's own tool state automatically. It resets read-before-write tracking (so a write afterward re-reads the file whose read evidence was summarized away) and re-injects the active todo list, so the model keeps its task list across the summary. There is no per-tool hook to configure.
|
|
22
22
|
|
|
23
|
+
First-class [memory](../memory) participates in a separate lifecycle. eve asks
|
|
24
|
+
providers to capture before compaction, excludes attributed recalled records
|
|
25
|
+
from the summarizer, keeps their canonical latest values, and recalls again
|
|
26
|
+
after the checkpoint.
|
|
27
|
+
|
|
23
28
|
Clients and channels can also request compaction between turns. Call
|
|
24
29
|
`ClientSession.compact()`, a channel route's `compact(address)`, or
|
|
25
30
|
`attachSession(sessionId).compact()`. The request does not append a user message;
|
|
@@ -30,6 +35,8 @@ events as automatic compaction, followed by `session.waiting`.
|
|
|
30
35
|
To discard model-message history instead of summarizing it, call the corresponding
|
|
31
36
|
`clear()` method on any of those handles. Clearing preserves the session identity,
|
|
32
37
|
system prompt, configured tools and skills, durable state, limits, and sandbox.
|
|
38
|
+
It removes recalled memory records and framework memory bookkeeping, but it
|
|
39
|
+
does not delete data from a memory provider's external store.
|
|
33
40
|
Its stream boundary is `context.cleared` followed by `session.waiting`.
|
|
34
41
|
|
|
35
42
|
## What to read next
|
|
@@ -37,3 +44,4 @@ Its stream boundary is `context.cleared` followed by `session.waiting`.
|
|
|
37
44
|
- [Built-in tools](./built-in-tools): review the default and opt-in framework tools and configure the model-facing tool set
|
|
38
45
|
- [Execution model and durability](./execution-model-and-durability): understand how turns checkpoint and resume
|
|
39
46
|
- [Context control](./context-control): choose what the model sees and when
|
|
47
|
+
- [Memory](../memory): connect scoped, cross-session context to the harness lifecycle
|
|
@@ -201,9 +201,9 @@ curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId>/reset \
|
|
|
201
201
|
-d '{"reason":"Start over"}'
|
|
202
202
|
```
|
|
203
203
|
|
|
204
|
-
Compaction summarizes context without adding a user message. User-role instructions are ordinary history and may be represented by the summary; system-role instructions remain outside it. If a turn is active, eve queues the request until that turn settles. A successful compaction emits `compaction.requested` and `compaction.completed`, followed by `session.waiting`; if summarization fails, the session returns to waiting with its previous history.
|
|
204
|
+
Compaction summarizes context without adding a user message. User-role instructions are ordinary history and may be represented by the summary; system-role instructions remain outside it. Attributed [memory](../memory) records are excluded from the summary, canonicalized, and recalled again after the checkpoint. If a turn is active, eve queues the request until that turn settles. A successful compaction emits `compaction.requested` and `compaction.completed`, followed by `session.waiting`; if summarization fails before a checkpoint, the session returns to waiting with its previous history.
|
|
205
205
|
|
|
206
|
-
Clear removes model-message history in place, including static and dynamic user-role instructions, while preserving the session identity, system-role instructions, tools, skills, durable state, limits, and sandbox. It does not rerun instruction definitions or resolvers. It emits `context.cleared` followed by `session.waiting`.
|
|
206
|
+
Clear removes model-message history in place, including static and dynamic user-role instructions and recalled memory records, while preserving the session identity, system-role instructions, tools, skills, application-defined durable state, limits, and sandbox. It clears framework memory locks and replay bookkeeping but does not delete data from a provider's external store. It does not rerun instruction definitions or resolvers. It emits `context.cleared` followed by `session.waiting`.
|
|
207
207
|
|
|
208
208
|
Reset terminally retires the exact session ID. A reset ID never becomes a new session; create another session explicitly for a fresh conversation. Compact, clear, and reset return `"no_active_session"` when the target is already inactive.
|
|
209
209
|
|
|
@@ -244,7 +244,7 @@ Start with the [Client SDK](../guides/client/overview) guide. It covers basic us
|
|
|
244
244
|
|
|
245
245
|
## Inspect the agent over HTTP
|
|
246
246
|
|
|
247
|
-
`GET /eve/v1/info` returns agent-info version
|
|
247
|
+
`GET /eve/v1/info` returns agent-info version 4, a JSON inspection snapshot of the effective compiled agent. It reports the selected config; active tools, instructions, memory slots, skills, channels, schedules, sandbox, connections, hooks, and instrumentation with explicit source ownership; dynamic resolvers separately from their session-specific output; local and remote agents in separate collections; prepared built-in effects; and shadowed or disabled source diagnostics. Memory tool wrappers include their selected memory-source dependency. Channel routes appear in the same effective order used by the HTTP host. Static instructions remain an ordered array whose entries expose `content` and `role`.
|
|
248
248
|
|
|
249
249
|
The info route belongs to the selected `channels/eve.ts` source and uses its resolved auth policy. Without an authored replacement, eve selects the default channel source with Vercel OIDC, local development access, and the production placeholder. Replacing or disabling that source replaces or removes the info route too; no native fallback serves it.
|
|
250
250
|
|
package/docs/concepts/state.md
CHANGED
|
@@ -69,7 +69,13 @@ Every [subagent](../subagents) starts with its own fresh state, whether it's a b
|
|
|
69
69
|
|
|
70
70
|
## State vs. connection-side storage
|
|
71
71
|
|
|
72
|
-
`defineState` holds conversation-scoped working memory that lives and dies with
|
|
72
|
+
`defineState` holds conversation-scoped working memory that lives and dies with
|
|
73
|
+
the session, including counters, the current plan, and what the user has told
|
|
74
|
+
you this conversation. It is the agent's short-term memory, persisted durably
|
|
75
|
+
for the life of the session. For context that must outlive a session, connect a
|
|
76
|
+
first-class [memory provider](../memory) to your own application store. Use a
|
|
77
|
+
general [connection](../connections) instead when the data should be queried
|
|
78
|
+
only through explicit model tool calls rather than recalled automatically.
|
|
73
79
|
|
|
74
80
|
## What to read next
|
|
75
81
|
|
|
@@ -77,3 +83,4 @@ Every [subagent](../subagents) starts with its own fresh state, whether it's a b
|
|
|
77
83
|
- How step durability works → [Execution model & durability](../concepts/execution-model-and-durability)
|
|
78
84
|
- The `ctx` accessors available alongside state → [TypeScript API Reference](../reference/typescript-api)
|
|
79
85
|
- Tenant-scoped long-term memory in your own store → [Multi-tenant memory](../patterns/multi-tenant-memory)
|
|
86
|
+
- First-class recall, capture, and provider tools → [Memory](../memory)
|
package/docs/extensions.md
CHANGED
|
@@ -7,7 +7,7 @@ Extensions package eve tools, channels, connections, skills, schedules, subagent
|
|
|
7
7
|
|
|
8
8
|
Ready-made extensions can also be distributed through an eve integration registry. See [Add Integrations](./install-integrations) to discover and add one with `eve add`; this page explains how extension packages are authored, mounted, configured, and overridden.
|
|
9
9
|
|
|
10
|
-
This enables sharing many different capability sets. A browser extension might include several tools for navigating a site. A
|
|
10
|
+
This enables sharing many different capability sets. A browser extension might include several tools for navigating a site. A self-improving extension could pair hooks with dynamic instructions.
|
|
11
11
|
|
|
12
12
|
## Author: create an extension
|
|
13
13
|
|
|
@@ -43,7 +43,11 @@ Each listed slot accepts the same authored forms as its agent counterpart. Stati
|
|
|
43
43
|
|
|
44
44
|
Names come from paths, so call the tool `search`, not `crm_search`; the consumer's mount adds the `crm__` prefix. The same prefix applies to channel, schedule, and parent-visible subagent IDs, while channel route paths and schedule cron expressions stay unchanged. Keep shared code in `extension/lib/`.
|
|
45
45
|
|
|
46
|
-
The extension root cannot declare agent configuration,
|
|
46
|
+
The extension root cannot declare agent configuration, instrumentation,
|
|
47
|
+
[memory](./memory), a sandbox, or nested extensions. Those agent-level concerns
|
|
48
|
+
belong to the consuming application. A subagent contributed under
|
|
49
|
+
`extension/subagents/` owns its own agent configuration, memory, and sandbox
|
|
50
|
+
like any other [declared subagent](./subagents).
|
|
47
51
|
|
|
48
52
|
### Add configuration and contributions
|
|
49
53
|
|
|
@@ -34,14 +34,14 @@ The client requires the successful response to match `{ ok: true, status: "ready
|
|
|
34
34
|
|
|
35
35
|
## Inspect an agent
|
|
36
36
|
|
|
37
|
-
Use `info()` to inspect an agent. The client requires the complete agent-info version
|
|
37
|
+
Use `info()` to inspect an agent. The client requires the complete agent-info version 4 response before returning it:
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
40
|
const info = await client.info();
|
|
41
41
|
console.log(info.agent.name, info.agent.model.id);
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Version
|
|
44
|
+
Version 4 separates active static definitions from dynamic resolvers, includes binding-backed source ownership and composition history, reports first-class memory slots and their provider-tool wrapper dependencies, reports local and remote agents separately, and returns the exact compiled channel route order. A non-success response throws `ClientError`; invalid JSON, an earlier schema version, duplicate identities, inconsistent totals, or mismatched source provenance throws `AgentInfoResponseError`.
|
|
45
45
|
|
|
46
46
|
## Authentication
|
|
47
47
|
|
|
@@ -166,7 +166,7 @@ Write callback properties as inline function expressions, arrows, method shortha
|
|
|
166
166
|
|
|
167
167
|
Closure values must be JSON-serializable. Plain objects, arrays, strings, finite numbers, booleans, and `null` are supported; `undefined` object properties are omitted. Functions, class instances, `Date`, `Map`, symbols, non-finite numbers, and cyclic values fail resolution with the tool name and callback phase instead of being serialized lossily.
|
|
168
168
|
|
|
169
|
-
Call expressions such as `execute: makeExecutor()` are not transformed. Put the callback body directly in `defineTool()` inside an authored module; eve-provided factories may also supply pre-registered callbacks. eve rejects a dynamic tool if any present callback lacks durable metadata.
|
|
169
|
+
Call expressions such as `execute: makeExecutor()` are not transformed. Put the callback body directly in `defineTool()` inside an authored module; eve-provided factories, including [memory provider tools](../memory), may also supply pre-registered callbacks. eve rejects a dynamic tool if any present callback lacks durable metadata.
|
|
170
170
|
|
|
171
171
|
### Identity and redeploys
|
|
172
172
|
|
|
@@ -174,7 +174,7 @@ A parked call binds to its callback by **tool name and phase** — the same iden
|
|
|
174
174
|
|
|
175
175
|
- Editing a callback body (or anything else that does not change tool names) is safe: replaying a parked call runs the latest deployed code with the closure values snapshotted when the call was made.
|
|
176
176
|
- If a persisted callback has no registered implementation (fresh process after a crash, or after a redeploy), eve re-runs `session.started` resolvers once to rebind it, then replays.
|
|
177
|
-
- If the tool no longer exists under that name, replay fails closed with an explicit error instead of invoking something else.
|
|
177
|
+
- If the tool no longer exists under that name, replay fails closed with an explicit error instead of invoking something else. Ordinary turn-scoped and step-scoped tools are not rebound; a parked call to a missing one errors. Framework-provided resolvers such as memory provider-tool wrappers opt into the same generic missing-callback rebind while preserving their locked scope.
|
|
178
178
|
|
|
179
179
|
### Naming
|
|
180
180
|
|
|
@@ -312,3 +312,4 @@ Dynamic system content that changes frequently can reduce provider prompt-cache
|
|
|
312
312
|
- The built-in tools and how to override them → [Built-in tools](../concepts/built-in-tools)
|
|
313
313
|
- Authenticate a tool or connection to an external service → [Auth & route protection](./auth-and-route-protection)
|
|
314
314
|
- Durable per-session memory for resolvers to read → [State](../concepts/state)
|
|
315
|
+
- Cross-session recall and provider-generated tools → [Memory](../memory)
|