eve 0.66.0 → 0.66.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/src/channel/forwarded-principal.d.ts +26 -6
- package/dist/src/channel/forwarded-principal.js +1 -1
- package/dist/src/chunks/{use-eve-agent-BUeSjwIk.js → use-eve-agent-Di1u2zKu.js} +24 -4
- package/dist/src/chunks/{use-eve-agent-ydPlURM4.js → use-eve-agent-PbSMyJ6e.js} +24 -4
- package/dist/src/cli/commands/deploy.d.ts +3 -1
- package/dist/src/cli/commands/deploy.js +1 -1
- package/dist/src/cli/commands/extension-build.js +1 -1
- package/dist/src/cli/commands/integration-connect.js +1 -1
- package/dist/src/cli/commands/register-project-commands.js +1 -1
- package/dist/src/cli/commands/registry-project.d.ts +2 -1
- package/dist/src/cli/commands/registry-project.js +2 -2
- package/dist/src/cli/commands/registry.js +1 -1
- package/dist/src/cli/commands/trace-detail.d.ts +5 -25
- package/dist/src/cli/commands/trace-detail.js +1 -1
- package/dist/src/cli/commands/trace.js +2 -2
- package/dist/src/cli/commands/vercel-non-interactive.d.ts +7 -0
- package/dist/src/cli/commands/vercel-non-interactive.js +1 -1
- package/dist/src/cli/dev/run-interactive-ui.js +1 -1
- package/dist/src/cli/dev/tui/argument-typeahead.d.ts +1 -1
- package/dist/src/cli/dev/tui/argument-typeahead.js +1 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
- package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
- package/dist/src/cli/dev/tui/registry-result-message.js +1 -1
- package/dist/src/cli/dev/tui/remote-auth.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +2 -2
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +3 -1
- package/dist/src/cli/dev/tui/setup-commands.js +1 -1
- package/dist/src/cli/dev/tui/setup-panel.d.ts +14 -0
- package/dist/src/cli/dev/tui/setup-panel.js +4 -4
- package/dist/src/cli/dev/tui/subagent-pump.d.ts +2 -10
- package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +2 -2
- package/dist/src/cli/dev/tui/terminal-renderer.js +10 -10
- package/dist/src/cli/dev/tui/traces/trace-conversation.js +1 -1
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/client/client-error.js +1 -1
- package/dist/src/client/open-stream.d.ts +3 -2
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/session.d.ts +16 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/discover/filesystem.d.ts +2 -0
- package/dist/src/discover/filesystem.js +1 -1
- package/dist/src/discover/grammar.d.ts +4 -2
- package/dist/src/discover/grammar.js +1 -1
- package/dist/src/discover/sandbox.js +1 -1
- package/dist/src/evals/session.d.ts +3 -2
- package/dist/src/evals/session.js +1 -1
- package/dist/src/evals/types.d.ts +8 -2
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/eve-channel/types.d.ts +12 -4
- package/dist/src/execution/cancel-indexed-session-tasks-step.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/proxied-deliver-step.js +1 -1
- package/dist/src/execution/route-child-delivery.js +2 -2
- package/dist/src/execution/session/admission.js +1 -1
- package/dist/src/execution/session/finalization.js +1 -1
- package/dist/src/execution/session/handoff-steps.js +1 -1
- package/dist/src/execution/session/input-queue.d.ts +12 -10
- package/dist/src/execution/session/input-queue.js +1 -1
- package/dist/src/execution/session/next-input.js +1 -1
- package/dist/src/execution/session/program.js +1 -1
- package/dist/src/execution/session/turn-step-result.d.ts +3 -1
- package/dist/src/execution/session/turn-step-result.js +1 -1
- package/dist/src/execution/session/turn-step-types.d.ts +7 -2
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/tasks/parent/control-shared.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch.js +1 -1
- package/dist/src/execution/tasks/parent/hitl-proxy-steps.d.ts +1 -0
- package/dist/src/execution/tasks/parent/hitl-proxy-steps.js +1 -1
- package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/ask-question-workflow.js +1 -1
- package/dist/src/execution/tools/sleep-workflow.js +1 -1
- package/dist/src/execution/tools/subagent/accept-event-step.js +1 -1
- package/dist/src/execution/tools/subagent/invoke-preparation.js +1 -1
- package/dist/src/execution/tools/subagent/invoke-step.js +1 -1
- package/dist/src/execution/tools/subagent/task-cancel.d.ts +1 -1
- package/dist/src/execution/tools/subagent/task-cancel.js +1 -1
- package/dist/src/harness/session-limit-enforcement.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/harness/turn-tag-state.d.ts +2 -2
- package/dist/src/harness/workflow-tool-runs.d.ts +33 -5
- package/dist/src/harness/workflow-tool-runs.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/instrumentation-layout.js +1 -1
- package/dist/src/internal/model-auth/vercel-cli.d.ts +2 -0
- package/dist/src/internal/model-auth/vercel-cli.js +1 -1
- package/dist/src/internal/nitro/host/build-extension.js +1 -1
- package/dist/src/internal/nitro/host/extension-build-lock.d.ts +9 -0
- package/dist/src/internal/nitro/host/extension-build-lock.js +1 -0
- package/dist/src/internal/nitro/host/extension-capability-requirements.d.ts +1 -0
- package/dist/src/internal/nitro/host/extension-capability-requirements.js +1 -1
- package/dist/src/internal/nitro/host/extension-declarations.js +1 -1
- package/dist/src/internal/nitro/host/extension-distribution.js +1 -1
- package/dist/src/internal/nitro/host/extension-state-usage.d.ts +2 -2
- package/dist/src/internal/nitro/host/extension-state-usage.js +1 -1
- package/dist/src/internal/nitro/host/prepare-application-host.d.ts +5 -4
- package/dist/src/internal/nitro/host/prepare-application-host.js +1 -1
- package/dist/src/internal/nitro/host/types.d.ts +2 -2
- package/dist/src/internal/nitro/host/workspace-extensions.d.ts +31 -0
- package/dist/src/internal/nitro/host/workspace-extensions.js +1 -0
- package/dist/src/public/next/index.d.ts +10 -7
- package/dist/src/public/next/index.js +1 -1
- package/dist/src/public/next/server.d.ts +3 -0
- package/dist/src/public/next/server.js +2 -2
- package/dist/src/self-modification/extension/local-only.d.ts +5 -0
- package/dist/src/self-modification/extension/local-only.js +1 -0
- package/dist/src/self-modification/extension/subagents/agent/instructions.js +6 -6
- package/dist/src/self-modification/extension/subagents/agent/skills/trace_analysis.d.ts +10 -0
- package/dist/src/self-modification/extension/subagents/agent/skills/trace_analysis.js +19 -0
- package/dist/src/self-modification/extension/subagents/agent/tools/inspect_trace.d.ts +128 -0
- package/dist/src/self-modification/extension/subagents/agent/tools/inspect_trace.js +1 -0
- package/dist/src/self-modification/extension/subagents/agent/tools/inspect_trace_spans.d.ts +80 -0
- package/dist/src/self-modification/extension/subagents/agent/tools/inspect_trace_spans.js +1 -0
- package/dist/src/self-modification/extension/subagents/agent/tools/registry_add.js +1 -1
- package/dist/src/self-modification/extension/subagents/agent/tools/search_traces.d.ts +53 -0
- package/dist/src/self-modification/extension/subagents/agent/tools/search_traces.js +1 -0
- package/dist/src/self-modification/extension/trace-inspection.d.ts +15 -0
- package/dist/src/self-modification/extension/trace-inspection.js +1 -0
- package/dist/src/self-modification/sandbox.js +1 -1
- package/dist/src/setup/ask.d.ts +2 -0
- package/dist/src/setup/ask.js +1 -1
- package/dist/src/setup/boxes/link-project.d.ts +2 -0
- package/dist/src/setup/boxes/link-project.js +1 -1
- package/dist/src/setup/cli/option-row.d.ts +3 -1
- package/dist/src/setup/cli/option-row.js +1 -1
- package/dist/src/setup/flows/deploy.d.ts +1 -0
- package/dist/src/setup/flows/deploy.js +1 -1
- package/dist/src/setup/flows/install-vercel-cli.js +1 -1
- package/dist/src/setup/flows/login.js +1 -1
- package/dist/src/setup/flows/model-login-connection.js +1 -1
- package/dist/src/setup/flows/model-login.d.ts +4 -0
- package/dist/src/setup/flows/model-login.js +1 -1
- package/dist/src/setup/flows/vercel-model-login.js +1 -1
- package/dist/src/setup/integrations/runner.js +1 -1
- package/dist/src/setup/integrations/web/setup.d.ts +15 -10
- package/dist/src/setup/integrations/web/setup.js +30 -1
- package/dist/src/setup/scaffold/create/project.js +2 -2
- package/dist/src/setup/scaffold/create/web-template.d.ts +7 -3
- package/dist/src/setup/scaffold/create/web-template.js +39 -20
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/slackbot.js +1 -1
- package/dist/src/setup/vercel-project.d.ts +2 -0
- package/dist/src/setup/vercel-project.js +0 -0
- package/dist/src/setup/vercel-trace-sampling.d.ts +3 -0
- package/dist/src/setup/vercel-trace-sampling.js +1 -0
- package/dist/src/subagents/parent-notification.d.ts +1 -1
- package/dist/src/subagents/remote-dispatch.d.ts +1 -0
- package/dist/src/subagents/remote-dispatch.js +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tasks/delivery-context.js +2 -2
- package/dist/src/tasks/notification.d.ts +6 -0
- package/dist/src/tasks/notification.js +1 -1
- package/dist/src/tracing/agent-trace-context-store.js +1 -1
- package/dist/src/tracing/local-trace-analysis.d.ts +51 -0
- package/dist/src/tracing/local-trace-analysis.js +1 -0
- package/dist/src/tracing/local-trace-discovery-index.d.ts +15 -0
- package/dist/src/tracing/local-trace-discovery-index.js +1 -0
- package/dist/src/tracing/local-trace-operations.d.ts +13 -0
- package/dist/src/tracing/local-trace-operations.js +1 -0
- package/dist/src/tracing/local-trace-query.d.ts +17 -0
- package/dist/src/tracing/local-trace-query.js +1 -0
- package/dist/src/tracing/local-trace-span-processor.js +1 -1
- package/dist/src/tracing/local-trace-summary.d.ts +31 -0
- package/dist/src/tracing/local-trace-summary.js +1 -0
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/concepts/project-structure.mdx +2 -4
- package/docs/concepts/sessions-runs-and-streaming.md +2 -2
- package/docs/evals/cases.mdx +1 -0
- package/docs/extensions.md +3 -1
- package/docs/guides/auth-and-route-protection.md +33 -1
- package/docs/guides/client/streaming.mdx +26 -0
- package/docs/guides/deployment/vercel.mdx +5 -5
- package/docs/guides/frontend/nextjs.mdx +20 -7
- package/docs/guides/frontend/overview.mdx +1 -1
- package/docs/guides/instrumentation/agent-runs.mdx +4 -4
- package/docs/guides/remote-agents.md +3 -1
- package/docs/install-integrations.mdx +1 -1
- package/docs/reference/agent-files.md +16 -0
- package/docs/reference/cli.md +1 -1
- package/docs/subagents/index.mdx +8 -2
- package/package.json +1 -1
- package/dist/src/internal/nitro/host/dev-workspace-extensions.d.ts +0 -18
- package/dist/src/internal/nitro/host/dev-workspace-extensions.js +0 -1
- package/dist/src/tasks/session-task-cohorts.d.ts +0 -7
- package/dist/src/tasks/session-task-cohorts.js +0 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { LocalTraceSpan } from "#tracing/local-trace-reader.js";
|
|
2
|
+
import { type LocalTraceSummary } from "#tracing/local-trace-summary.js";
|
|
3
|
+
export interface TraceAnalysisSelector {
|
|
4
|
+
readonly excludeSessionId?: string;
|
|
5
|
+
readonly fromMs?: number;
|
|
6
|
+
readonly sessionId?: string;
|
|
7
|
+
readonly toMs?: number;
|
|
8
|
+
readonly turnId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface TraceTokenUsage {
|
|
11
|
+
readonly inputTokens?: number;
|
|
12
|
+
readonly outputTokens?: number;
|
|
13
|
+
readonly cacheReadTokens?: number;
|
|
14
|
+
readonly cacheWriteTokens?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface TraceTimelineRecord {
|
|
17
|
+
readonly actionDurationMs?: number;
|
|
18
|
+
readonly actionName?: string;
|
|
19
|
+
readonly callId?: string;
|
|
20
|
+
readonly category: "model" | "other" | "tool";
|
|
21
|
+
readonly durationMs: number;
|
|
22
|
+
readonly endOffsetMs: number;
|
|
23
|
+
readonly error?: string;
|
|
24
|
+
readonly model?: string;
|
|
25
|
+
readonly outcome: "completed" | "failed";
|
|
26
|
+
readonly parentSpanId?: string;
|
|
27
|
+
readonly sessionId?: string;
|
|
28
|
+
readonly spanId: string;
|
|
29
|
+
readonly startOffsetMs: number;
|
|
30
|
+
readonly toolName?: string;
|
|
31
|
+
readonly turnId?: string;
|
|
32
|
+
readonly usage?: TraceTokenUsage;
|
|
33
|
+
}
|
|
34
|
+
export interface TraceAnalysis {
|
|
35
|
+
readonly summary: LocalTraceSummary;
|
|
36
|
+
readonly groups: readonly TraceAnalysisGroup[];
|
|
37
|
+
/** Accumulated operation time, not elapsed time; parallel calls can overlap. */
|
|
38
|
+
readonly modelWorkMs: number;
|
|
39
|
+
readonly toolWorkMs: number;
|
|
40
|
+
readonly records: readonly TraceTimelineRecord[];
|
|
41
|
+
}
|
|
42
|
+
export interface TraceAnalysisGroup {
|
|
43
|
+
readonly modelWorkMs: number;
|
|
44
|
+
readonly modelCalls: number;
|
|
45
|
+
readonly sessionId?: string;
|
|
46
|
+
readonly toolWorkMs: number;
|
|
47
|
+
readonly toolCalls: number;
|
|
48
|
+
readonly turnId?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Builds the detailed timeline only when inspection, rather than search, needs it. */
|
|
51
|
+
export declare function analyzeLocalTrace(traceId: string, spans: readonly LocalTraceSpan[], selector?: TraceAnalysisSelector): TraceAnalysis;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{summarizeLocalTrace}from"#tracing/local-trace-summary.js";import{localTraceOperations,traceModelName,traceSessionId,traceStringAttribute,traceToolName,uniqueLocalTraceSpans}from"#tracing/local-trace-operations.js";function analyzeLocalTrace(e,t,n={}){let r=uniqueLocalTraceSpans(t),i=new Map(localTraceOperations(r).map(({span:e})=>[e.spanId,e])),a=r.filter(e=>matches(i.get(e.spanId)??e,n)),o=a.reduce((e,t)=>t.startTimeNs<e?t.startTimeNs:e,a[0]?.startTimeNs??0n),s=localTraceOperations(a).map(e=>recordFor(e,o)).sort((e,t)=>e.startOffsetMs-t.startOffsetMs||e.endOffsetMs-t.endOffsetMs||e.spanId.localeCompare(t.spanId));return{summary:summarizeLocalTrace(e,a),groups:groups(s),modelWorkMs:sum(s,`model`),toolWorkMs:sum(s,`tool`),records:s}}function matches(e,t){let n=traceSessionId(e),r=traceStringAttribute(e,`agent.turn.id`);if(t.excludeSessionId!==void 0&&n===t.excludeSessionId||t.sessionId!==void 0&&n!==t.sessionId||t.turnId!==void 0&&r!==t.turnId)return!1;let i=Number(e.startTimeNs/1000000n);return(t.fromMs===void 0||i>=t.fromMs)&&(t.toMs===void 0||i<=t.toMs)}function recordFor(e,t){let{span:n,category:r}=e,i={category:r,durationMs:Number(n.endTimeNs-n.startTimeNs)/1e6,endOffsetMs:Number(n.endTimeNs-t)/1e6,outcome:n.statusCode===2?`failed`:`completed`,spanId:n.spanId,startOffsetMs:Number(n.startTimeNs-t)/1e6},a=traceStringAttribute(n,`agent.action.call_id`),o=traceModelName(n),s=traceSessionId(n),c=traceToolName(n),l=traceStringAttribute(n,`agent.turn.id`);if(a!==void 0&&(i.callId=a),n.statusMessage!==void 0&&(i.error=n.statusMessage),o!==void 0&&(i.model=o),n.parentSpanId!==void 0&&(i.parentSpanId=n.parentSpanId),s!==void 0&&(i.sessionId=s),c!==void 0&&r===`tool`&&(i.toolName=c),c!==void 0&&r===`other`&&(i.actionName=c),l!==void 0&&(i.turnId=l),e.actionDurationMs!==void 0&&(i.actionDurationMs=e.actionDurationMs),r===`model`){let e={};for(let[t,r]of Object.entries({inputTokens:`agent.usage.input_tokens`,outputTokens:`agent.usage.output_tokens`,cacheReadTokens:`agent.usage.cache_read_tokens`,cacheWriteTokens:`agent.usage.cache_write_tokens`})){let i=n.attributes[r];typeof i==`number`&&Number.isFinite(i)&&i>=0&&(e[t]=i)}Object.keys(e).length>0&&(i.usage=e)}return i}function groups(e){let t=new Map;for(let n of e){let e=JSON.stringify([n.sessionId,n.turnId]),r=t.get(e);r===void 0&&(r={modelCalls:0,modelWorkMs:0,toolCalls:0,toolWorkMs:0},n.sessionId!==void 0&&(r.sessionId=n.sessionId),n.turnId!==void 0&&(r.turnId=n.turnId),t.set(e,r)),n.category===`model`&&(r.modelCalls+=1,r.modelWorkMs+=n.durationMs),n.category===`tool`&&(r.toolCalls+=1,r.toolWorkMs+=n.durationMs)}return[...t.values()]}function sum(e,t){return e.reduce((e,n)=>e+(n.category===t?n.durationMs:0),0)}export{analyzeLocalTrace};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** A path-safe, non-reversible key for one recorded conversation identifier. */
|
|
2
|
+
export declare function localTraceConversationIndexKey(conversationId: string): string;
|
|
3
|
+
/** Marker path relative to one trace directory. */
|
|
4
|
+
export declare function localTraceConversationMarker(conversationId: string): string;
|
|
5
|
+
/** Marker proving that a trace was written by an index-aware writer. */
|
|
6
|
+
export declare function localTraceIndexedMarker(): string;
|
|
7
|
+
/**
|
|
8
|
+
* Records conversation membership without rewriting shared state. Empty marker
|
|
9
|
+
* creation is idempotent, so overlapping dev workers cannot lose each other's
|
|
10
|
+
* conversation entries.
|
|
11
|
+
*/
|
|
12
|
+
export declare function indexLocalTraceConversation(input: {
|
|
13
|
+
readonly conversationId: string;
|
|
14
|
+
readonly traceDirectory: string;
|
|
15
|
+
}): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash}from"node:crypto";import{mkdir,writeFile}from"node:fs/promises";import{join}from"node:path";const INDEX_DIRECTORY=`index/v1`,CONVERSATIONS_DIRECTORY=`${INDEX_DIRECTORY}/conversations`,INDEXED_MARKER=`${INDEX_DIRECTORY}/indexed`;function localTraceConversationIndexKey(e){return createHash(`sha256`).update(e).digest(`hex`)}function localTraceConversationMarker(e){return`${CONVERSATIONS_DIRECTORY}/${localTraceConversationIndexKey(e)}`}function localTraceIndexedMarker(){return INDEXED_MARKER}async function indexLocalTraceConversation(e){let t=join(e.traceDirectory,localTraceConversationMarker(e.conversationId));await mkdir(join(e.traceDirectory,CONVERSATIONS_DIRECTORY),{recursive:!0}),await createMarker(t),await createMarker(join(e.traceDirectory,INDEXED_MARKER))}async function createMarker(e){try{await writeFile(e,``,{flag:`wx`})}catch(e){if(!isAlreadyPresent(e))throw e}}function isAlreadyPresent(e){return e instanceof Error&&`code`in e&&e.code===`EEXIST`}export{indexLocalTraceConversation,localTraceConversationIndexKey,localTraceConversationMarker,localTraceIndexedMarker};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LocalTraceSpan } from "#tracing/local-trace-reader.js";
|
|
2
|
+
export interface LocalTraceOperation {
|
|
3
|
+
readonly span: LocalTraceSpan;
|
|
4
|
+
readonly category: "model" | "other" | "tool";
|
|
5
|
+
readonly actionDurationMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function uniqueLocalTraceSpans(spans: readonly LocalTraceSpan[]): LocalTraceSpan[];
|
|
8
|
+
/** Pairs action wrappers with execution spans without constructing a sorted timeline. */
|
|
9
|
+
export declare function localTraceOperations(spans: readonly LocalTraceSpan[]): LocalTraceOperation[];
|
|
10
|
+
export declare function traceModelName(span: LocalTraceSpan): string | undefined;
|
|
11
|
+
export declare function traceToolName(span: LocalTraceSpan): string | undefined;
|
|
12
|
+
export declare function traceSessionId(span: LocalTraceSpan): string | undefined;
|
|
13
|
+
export declare function traceStringAttribute(span: LocalTraceSpan, key: string): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function uniqueLocalTraceSpans(e){let t=new Map;for(let n of e)t.has(n.spanId)||t.set(n.spanId,n);return[...t.values()]}function localTraceOperations(e){let t=new Map(e.map(e=>[e.spanId,e])),n=new Set,r=[];for(let i of e){let e=categoryFor(i);if(e===void 0)continue;let a=i.parentSpanId===void 0?void 0:t.get(i.parentSpanId);i.attributes[`gen_ai.operation.name`]===`execute_tool`&&a?.name===`agent.action`&&traceToolName(a)===traceToolName(i)?(n.add(a.spanId),r.push({category:e,span:{...i,attributes:{...a.attributes,...i.attributes},parentSpanId:a.parentSpanId,statusCode:a.statusCode===2?a.statusCode:i.statusCode,statusMessage:a.statusCode===2?a.statusMessage:i.statusMessage},...a.attributes[`agent.action.kind`]===`subagent-call`?{actionDurationMs:Number(a.endTimeNs-a.startTimeNs)/1e6}:{}})):r.push({category:e,span:i})}return r.filter(({span:e})=>!n.has(e.spanId))}function categoryFor(e){if(e.attributes[`gen_ai.operation.name`]===`chat`)return`model`;if(e.attributes[`gen_ai.operation.name`]===`execute_tool`)return`tool`;if(e.name===`agent.action`)return e.attributes[`agent.action.kind`]===`tool-call`?`tool`:`other`}function traceModelName(e){return traceStringAttribute(e,`agent.model.id`)??traceStringAttribute(e,`gen_ai.request.model`)}function traceToolName(e){return traceStringAttribute(e,`gen_ai.tool.name`)??traceStringAttribute(e,`agent.action.name`)}function traceSessionId(e){return traceStringAttribute(e,`agent.run.id`)??traceStringAttribute(e,`agent.session.id`)}function traceStringAttribute(e,t){let n=e.attributes[t];return typeof n==`string`&&n.length>0?n:void 0}export{localTraceOperations,traceModelName,traceSessionId,traceStringAttribute,traceToolName,uniqueLocalTraceSpans};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LocalTraceSummary } from "#tracing/local-trace-summary.js";
|
|
2
|
+
export type LocalTraceSortBy = "duration" | "failures" | "inputTokens" | "latest";
|
|
3
|
+
export interface LocalTraceQueryFilter {
|
|
4
|
+
readonly agentName?: string;
|
|
5
|
+
/** Selects traces containing error spans, not necessarily failed activations. */
|
|
6
|
+
readonly failedOnly?: boolean;
|
|
7
|
+
readonly sessionId?: string;
|
|
8
|
+
readonly toolName?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Filters whole traces without restricting their totals to matching spans. */
|
|
11
|
+
export declare function queryLocalTraceSummaries(summaries: readonly LocalTraceSummary[], options: LocalTraceQueryFilter & {
|
|
12
|
+
readonly limit: number;
|
|
13
|
+
readonly sortBy: LocalTraceSortBy;
|
|
14
|
+
}): {
|
|
15
|
+
readonly matches: readonly LocalTraceSummary[];
|
|
16
|
+
readonly truncated: boolean;
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function queryLocalTraceSummaries(e,t){let n=e.filter(e=>matchesFilter(e,t));return n.sort((e,n)=>compareSummaries(e,n,t.sortBy)),{matches:n.slice(0,t.limit),truncated:n.length>t.limit}}function matchesFilter(e,t){return(t.agentName===void 0||e.agentNames.includes(t.agentName))&&(t.sessionId===void 0||e.sessionIds.includes(t.sessionId))&&(t.toolName===void 0||e.toolNames.includes(t.toolName))&&(t.failedOnly!==!0||e.errorSpanCount>0)}function compareSummaries(e,t,n){return(n===`duration`?t.durationMs-e.durationMs:n===`failures`?t.errorSpanCount-e.errorSpanCount:n===`inputTokens`?t.inputTokens-e.inputTokens:Date.parse(t.startedAt)-Date.parse(e.startedAt))||e.traceId.localeCompare(t.traceId)}export{queryLocalTraceSummaries};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdir}from"node:fs/promises";import{createLogger,formatError}from"#internal/logging.js";import{join}from"node:path";import{atomicWriteFile}from"#shared/atomic-write-file.js";import{JsonTraceSerializer}from"#compiled/@opentelemetry/otlp-transformer/index.js";const log=createLogger(`harness.local-trace-span-processor`);function resolveLocalTraceStoreDirectory(e){return join(e,`.eve`,`traces`)}function resolveLocalTraceSchemaDirectory(e){return join(resolveLocalTraceStoreDirectory(e),`v1`)}function
|
|
1
|
+
import{mkdir}from"node:fs/promises";import{createLogger,formatError}from"#internal/logging.js";import{join}from"node:path";import{atomicWriteFile}from"#shared/atomic-write-file.js";import{indexLocalTraceConversation}from"#tracing/local-trace-discovery-index.js";import{JsonTraceSerializer}from"#compiled/@opentelemetry/otlp-transformer/index.js";const log=createLogger(`harness.local-trace-span-processor`);function resolveLocalTraceStoreDirectory(e){return join(e,`.eve`,`traces`)}function resolveLocalTraceSchemaDirectory(e){return join(resolveLocalTraceStoreDirectory(e),`v1`)}function resolveLocalTraceDirectory(e,t){return join(resolveLocalTraceSchemaDirectory(e),t)}function resolveLocalTraceSegmentsDirectory(e,t){return join(resolveLocalTraceDirectory(e,t),`segments`)}var LocalTraceSpanProcessor=class{#e;#t=Promise.resolve();#n=!1;constructor(e){this.#e=e}forceFlush(){return this.#t}onStart(){}onEnd(e){if(!isReadableSpan(e))return;let{spanId:t,traceId:n}=e.spanContext();if(!isHexId(n,32)||!isHexId(t,16))return;let r=JsonTraceSerializer.serializeRequest([e]);if(r===void 0)return;let i=e.attributes[`gen_ai.conversation.id`],a=typeof i==`string`&&i.length>0?i:void 0;this.#t=this.#t.then(async()=>{let e=resolveLocalTraceDirectory(this.#e,n),i=resolveLocalTraceSegmentsDirectory(this.#e,n);await mkdir(i,{recursive:!0}),await atomicWriteFile(join(i,`${t}.otlp.json`),r),a!==void 0&&await indexLocalTraceConversation({conversationId:a,traceDirectory:e})}).catch(e=>{this.#n||(this.#n=!0,log.warn(`local trace persistence failed`,{error:formatError(e)}))})}shutdown(){return this.forceFlush()}};function isReadableSpan(e){return typeof e==`object`&&!!e&&`attributes`in e&&`spanContext`in e&&typeof e.spanContext==`function`}function isHexId(e,t){return e.length===t&&/^[0-9a-f]+$/u.test(e)}export{LocalTraceSpanProcessor,resolveLocalTraceSchemaDirectory,resolveLocalTraceSegmentsDirectory};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LocalTraceSpan } from "#tracing/local-trace-reader.js";
|
|
2
|
+
/** Structural metadata and totals for one retained trace, not its final outcome. */
|
|
3
|
+
export interface LocalTraceSummary {
|
|
4
|
+
readonly traceId: string;
|
|
5
|
+
readonly startedAt: string;
|
|
6
|
+
/** Elapsed time from the earliest span start to the latest span end. */
|
|
7
|
+
readonly durationMs: number;
|
|
8
|
+
readonly spanCount: number;
|
|
9
|
+
readonly agentNames: readonly string[];
|
|
10
|
+
readonly conversationIds: readonly string[];
|
|
11
|
+
readonly sessionIds: readonly string[];
|
|
12
|
+
readonly models: readonly string[];
|
|
13
|
+
readonly toolNames: readonly string[];
|
|
14
|
+
readonly modelCalls: number;
|
|
15
|
+
readonly toolCalls: number;
|
|
16
|
+
/** Error-bearing spans; one failure can be recorded on multiple ancestors. */
|
|
17
|
+
readonly errorSpanCount: number;
|
|
18
|
+
readonly inputTokens: number;
|
|
19
|
+
readonly outputTokens: number;
|
|
20
|
+
readonly cacheReadTokens: number;
|
|
21
|
+
readonly cacheWriteTokens: number;
|
|
22
|
+
/** Total gateway cost in USD; undefined when no step reported cost. */
|
|
23
|
+
readonly costUsd?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Only agent.step spans contribute usage: model spans repeat the same counters.
|
|
27
|
+
* Operation counts collapse action/execution pairs, but error counts retain all
|
|
28
|
+
* error-bearing spans so summaries agree with the raw trace tree.
|
|
29
|
+
*/
|
|
30
|
+
export declare function summarizeLocalTrace(traceId: string, spans: readonly LocalTraceSpan[]): LocalTraceSummary;
|
|
31
|
+
export declare function localTraceSpanCostUsd(span: LocalTraceSpan): number | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AGENT_USAGE_ATTRIBUTES}from"#tracing/agent-span-contract.js";import{localTraceOperations,traceModelName,traceSessionId,traceStringAttribute,traceToolName,uniqueLocalTraceSpans}from"#tracing/local-trace-operations.js";function summarizeLocalTrace(e,t){let n=uniqueLocalTraceSpans(t),r=new Set,i=new Set,a=new Set,o=new Set,s=n[0]?.startTimeNs??0n,c=s,l=0,u=0,d,f=0,p=0,m=0;for(let e of n){if(e.startTimeNs<s&&(s=e.startTimeNs),e.endTimeNs>c&&(c=e.endTimeNs),add(r,traceModelName(e)),add(i,traceStringAttribute(e,`agent.name`)),add(a,traceStringAttribute(e,`gen_ai.conversation.id`)),add(o,traceSessionId(e)),e.statusCode===2&&(f+=1),e.name!==`agent.step`)continue;p+=numberAttribute(e,`agent.usage.input_tokens`)??0,m+=numberAttribute(e,`agent.usage.output_tokens`)??0,l+=numberAttribute(e,AGENT_USAGE_ATTRIBUTES.cacheReadTokens)??numberAttribute(e,`gen_ai.usage.cache_read.input_tokens`)??0,u+=numberAttribute(e,AGENT_USAGE_ATTRIBUTES.cacheWriteTokens)??numberAttribute(e,`gen_ai.usage.cache_creation.input_tokens`)??0;let t=localTraceSpanCostUsd(e);t!==void 0&&(d=(d??0)+t)}let h=new Set,g=0,_=0;for(let e of localTraceOperations(n))e.category===`model`&&(g+=1),e.category===`tool`&&(_+=1,add(h,traceToolName(e.span)));return{traceId:e,startedAt:new Date(Number(s/1000000n)).toISOString(),durationMs:Number(c-s)/1e6,spanCount:n.length,agentNames:[...i].sort(),conversationIds:[...a].sort(),sessionIds:[...o].sort(),models:[...r].sort(),toolNames:[...h].sort(),modelCalls:g,toolCalls:_,errorSpanCount:f,cacheReadTokens:l,cacheWriteTokens:u,costUsd:d,inputTokens:p,outputTokens:m}}function localTraceSpanCostUsd(e){return numberAttribute(e,`gen_ai.usage.gateway_cost`)??numberAttribute(e,`gen_ai.usage.cost`)}function numberAttribute(e,t){let n=e.attributes[t];if(typeof n==`number`)return Number.isFinite(n)&&n>=0?n:void 0;if(typeof n==`string`&&n.trim()!==``){let e=Number(n);return Number.isFinite(e)&&e>=0?e:void 0}}function add(e,t){t!==void 0&&e.add(t)}export{localTraceSpanCostUsd,summarizeLocalTrace};
|
package/dist/src/vue/index.js
CHANGED
|
@@ -74,14 +74,12 @@ Use separate packages or projects when agents need independent dependencies or r
|
|
|
74
74
|
|
|
75
75
|
Choose how the frontend and agents run together independently of how many agents you have:
|
|
76
76
|
|
|
77
|
-
- **Add agents to a Next.js application:** use [`eve/next`](/docs/guides/frontend/nextjs) in `next.config.ts`. Next.js owns the application lifecycle; the integration starts agent processes and proxies requests locally, and contributes separate agent services on Vercel. A root Next.js app can sit beside either `agent/` or `agents/`; workspace members are discovered automatically.
|
|
77
|
+
- **Add agents to a Next.js application:** use [`eve/next`](/docs/guides/frontend/nextjs) in `next.config.ts`. Next.js owns the application lifecycle; the integration starts agent processes and proxies requests locally, and contributes separate agent services on Vercel. A root Next.js app can sit beside either `agent/` or `agents/`; workspace members are discovered automatically. A peer app such as `apps/web/` can select its eve project with `eveRoot: "../.."`.
|
|
78
78
|
- **Add a frontend to an agent workspace:** keep the frontend as a peer application, for example under `apps/web/`. On Vercel, use [`eve/vercel` in root `vercel.ts`](/docs/guides/deployment/vercel#compose-agents-with-other-vercel-services) to contribute the agents alongside the frontend service. For [self-hosting](/docs/guides/deployment/self-hosting#run-workspace-members), run the services with your process manager and configure a reverse proxy. The frontend does not need `eve/next`.
|
|
79
79
|
|
|
80
80
|
`apps/web/` is an organizational convention, not an eve filesystem slot. Deployment configuration owns peer services; eve discovers only the agents. Both Vercel integrations deploy the services together, not as independent releases.
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
For a single `agent/` project, `eve add channel/web` currently generates a root Next.js app using `eve/next`. `eve/vercel` currently requires an `agents/` workspace; it cannot compose a standalone root `agent/`.
|
|
82
|
+
Run `eve add channel/web` from a standalone agent or select a workspace agent with `--agent <name>`. The installer creates a Next.js frontend under `apps/web/`. Choose **Vercel** to configure separate Vercel services and run them with `pnpm dev:services`, or **Other** to let Next.js host the agents and run the application with `pnpm dev:web`. Use `pnpm dev` or `pnpm dev:eve` when you only want one agent and the eve terminal UI.
|
|
85
83
|
|
|
86
84
|
## Add a second root agent
|
|
87
85
|
|
|
@@ -79,7 +79,7 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
|
|
|
79
79
|
| `action.result` | A tool call returned. |
|
|
80
80
|
| `input.requested` | The run paused for human input ([HITL](/docs/human-in-the-loop) approval or a `ctx.ask()` question); carries `requests`. |
|
|
81
81
|
| `input.resolved` | The server accepted terminal human-input outcomes; carries `resolutions` with responses when provided. |
|
|
82
|
-
| `subagent.called` | A subagent was delegated; carries `childSessionId`
|
|
82
|
+
| `subagent.called` | A subagent was delegated; carries `childSessionId` and the `childStreamPath` that `session.streamSubagent()` follows. |
|
|
83
83
|
| `subagent.completed` | The parent recorded a successful subagent invocation result; carries the actual output. |
|
|
84
84
|
| `reasoning.appended` | A reasoning text delta. |
|
|
85
85
|
| `reasoning.completed` | The finalized reasoning block. |
|
|
@@ -119,7 +119,7 @@ Note: consider the privacy, confidentiality, and user-experience implications fo
|
|
|
119
119
|
|
|
120
120
|
When a task explicitly requires conditional delivery and there is nothing new to report, the agent can finish with exactly `<eve-empty-delivery/>`. eve emits `message.completed` with `message: null` for that intentional silence. The marker must be the entire response, apart from surrounding whitespace; the HTML-escaped form `<eve-empty-delivery/>` is also accepted. A response that quotes the marker in prose or code is delivered normally.
|
|
121
121
|
|
|
122
|
-
A delegated subagent publishes progress on its own child-session stream. The parent emits `subagent.called` with a `childSessionId`, which a client
|
|
122
|
+
A delegated subagent publishes progress on its own child-session stream. The parent emits `subagent.called` with a `childSessionId` and a `childStreamPath`, which a client follows with `session.streamSubagent()`. Both blocking and background calls emit `subagent.completed` with the actual output after the parent records a successful outcome. A background working receipt is an `action.result` tool output; it does not emit completion. Older streams can contain receipt-bearing completion events marked by `data.backgroundTask`; those are admission only. Completion does not mean that the reusable child session has ended. Background task terminal outcomes also arrive as task-triggered `message.received` notifications with `data.kind: "execution.background_task"`. The default frontend reducer retains these events in `events` but does not project their runtime-authored text as participant messages.
|
|
123
123
|
|
|
124
124
|
`step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally. Whatever the turn streamed before cancellation stays on the stream. Durable history keeps the accepted user input and previously settled work, but discards incomplete assistant output and unfinished tool state. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`).
|
|
125
125
|
|
package/docs/evals/cases.mdx
CHANGED
|
@@ -111,6 +111,7 @@ Every `t.session()` or `t.send()` creates a new independent conversation. Contin
|
|
|
111
111
|
- `session.start(message, options?)` starts a text turn and returns as soon as the server accepts it. The live turn exposes `.session`, `.sessionId`, `.waitForEvent(...)`, `.cancel()`, and `.result()`.
|
|
112
112
|
- `session.cancel()` requests cooperative cancellation of that session's active turn. Both `accepted` and `no_active_turn` are successful outcomes.
|
|
113
113
|
- `session.sendFile(text, path, mediaType?)` attaches a local file as a data URL.
|
|
114
|
+
- `session.streamSubagent(called, options?)` follows a delegated child's stream through the parent with the eval client's credentials. Pass a `subagent.called` event from that session. It also reaches children on another deployment, which `t.target.watchTurn(...)` cannot address.
|
|
114
115
|
- `session.requireInputRequest(filter?)` records a gate, requires exactly one pending request, and returns it. Filters match tool name, action input, prompt, display, and option ids.
|
|
115
116
|
- `session.respond(responses, options?)` answers specific pending input requests and sends them as the next turn. `session.startRespond(...)` returns a live turn for the same operation.
|
|
116
117
|
- `session.respondAll(optionId)` answers every pending input request with the same option and sends the responses as the next turn.
|
package/docs/extensions.md
CHANGED
|
@@ -273,7 +273,9 @@ The mount is intentionally per agent. Each consumer chooses its own mount namesp
|
|
|
273
273
|
|
|
274
274
|
When `eve dev` starts a consuming agent, it builds mounted, source-backed extensions found inside the same workspace before compiling the agent. It watches the extension source and relevant package and TypeScript configuration, then rebuilds only the affected extension. If an extension edit fails to build, the previous successful development generation keeps running.
|
|
275
275
|
|
|
276
|
-
Production `eve build`
|
|
276
|
+
Production builds build the same extensions from source. `eve build` builds each mounted, source-backed workspace extension before it compiles the agent, and `withEve` does the same for its agents during `next build`. Production builds therefore do not depend on the extension package's `prepare` script, which package managers skip for no-op installs and with `--ignore-scripts`. eve skips an extension whose distribution was built by the same eve version and is newer than the extension's source, `package.json`, and TypeScript configuration.
|
|
277
|
+
|
|
278
|
+
If an extension fails to build, the agent build stops with an error that names the extension package and its directory. Fix the reported error, or run `eve extension build` in that package directory to build it on its own.
|
|
277
279
|
|
|
278
280
|
### Override a contribution
|
|
279
281
|
|
|
@@ -239,9 +239,41 @@ export default eveChannel({
|
|
|
239
239
|
|
|
240
240
|
`trustedForwarders` authorizes the verified forwarder to supply eve delegation context: principal identity, parent session lineage, and, with principal forwarding, trace-content constraints. Match it precisely: `() => true` grants this authority to every caller that passes route auth, including preview deployments accepted by `vercelOidc()`. The framework default channel rejects forwarded principals and ignores the other context.
|
|
241
241
|
|
|
242
|
+
### Limiting what a forwarder may assert
|
|
243
|
+
|
|
244
|
+
A forwarder accepted on its identity alone can assert any principal, including identities your tools trust directly, such as a Slack user or an app principal. When a forwarder should speak only for its own users, check what it asserts with the predicate's second argument:
|
|
245
|
+
|
|
246
|
+
```ts title="agent/channels/eve.ts"
|
|
247
|
+
import { eveChannel } from "eve/channels/eve";
|
|
248
|
+
import { vercelOidc, vercelSubject } from "eve/channels/auth";
|
|
249
|
+
import type { SessionAuthContext } from "eve/context";
|
|
250
|
+
|
|
251
|
+
const router = vercelSubject({ teamSlug: "acme", projectName: "router" });
|
|
252
|
+
|
|
253
|
+
/** The router forwards only users signed in through its own identity provider. */
|
|
254
|
+
function isRouterUser(context: SessionAuthContext): boolean {
|
|
255
|
+
return (
|
|
256
|
+
context.authenticator === "router-sso" &&
|
|
257
|
+
context.issuer === "router" &&
|
|
258
|
+
context.principalType === "user"
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export default eveChannel({
|
|
263
|
+
auth: [vercelOidc()],
|
|
264
|
+
trustedForwarders: (forwarder, assertion) =>
|
|
265
|
+
forwarder.subject === router &&
|
|
266
|
+
assertion.principal !== undefined &&
|
|
267
|
+
isRouterUser(assertion.principal.current) &&
|
|
268
|
+
isRouterUser(assertion.principal.initiator),
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`assertion.principal` holds the `current` and `initiator` contexts the forwarder asserts, already stamped with `eve:forwarded-by`. `initiator` equals `current` when the sender omits it. `initiator` takes effect only on session creation; on continuation the predicate still sees the asserted `initiator`, but the session keeps its original initiator, so checking it does not constrain that pinned value. Attributes are asserted too, so check any attribute your tools trust. `assertion.principal` is absent when the predicate decides parent session lineage for a request that forwards no principal; a predicate that requires it accepts that forwarder's lineage only alongside a principal it accepts. The `ForwardedAssertion` and `TrustedForwarders` types are exported from `eve/channels/eve` for named predicates.
|
|
273
|
+
|
|
242
274
|
When the predicate accepts a create request, `ctx.session.auth.current` and `.initiator` carry the forwarded user exactly as if they had called your deployment directly. On continuation, only `auth.current` is replaced; `auth.initiator` remains the session creator. User-scoped connections, local subagents, and further `forwardPrincipal` hops therefore see the active turn's caller.
|
|
243
275
|
|
|
244
|
-
The forwarder is recorded on accepted contexts as the `eve:forwarded-by` attribute (always overwritten by the receiver, so a forwarder cannot falsify it). Forwarded identity rejections fail loud: a forwarded body without `trustedForwarders` configured or with a forwarder the predicate refuses is a `403`, and a malformed payload is a `400`. Only principal metadata is ever accepted — tokens and credentials never cross the hop.
|
|
276
|
+
The forwarder is recorded on accepted contexts as the `eve:forwarded-by` attribute (always overwritten by the receiver, so a forwarder cannot falsify it). Forwarded identity rejections fail loud: a forwarded body without `trustedForwarders` configured, or with a forwarder or assertion the predicate refuses, is a `403`, and a malformed payload is a `400`. Only principal metadata is ever accepted — tokens and credentials never cross the hop.
|
|
245
277
|
|
|
246
278
|
Trusted parent session lineage populates `ctx.session.parent` and preserves the root session across the delegation chain. Untrusted lineage is ignored, and accepted lineage does not remove the normal root-session token cap.
|
|
247
279
|
|
|
@@ -241,6 +241,32 @@ Unlike `stream()`, `snapshot()` does not advance the originating
|
|
|
241
241
|
`ClientSession`. Its returned cursor contains the fixed session ID and the exact
|
|
242
242
|
stream index after the captured prefix.
|
|
243
243
|
|
|
244
|
+
## Follow a subagent
|
|
245
|
+
|
|
246
|
+
A delegated subagent reports its progress on its own child session. The parent stream announces each dispatch with a `subagent.called` event. Pass that event to `streamSubagent()` on the parent's session handle to follow the child:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
import { isCurrentTurnBoundaryEvent } from "eve/client";
|
|
250
|
+
|
|
251
|
+
const session = client.sessions.attach(parentSessionId);
|
|
252
|
+
const { events } = await session.snapshot();
|
|
253
|
+
const called = events.find((event) => event.type === "subagent.called");
|
|
254
|
+
|
|
255
|
+
if (called?.type === "subagent.called") {
|
|
256
|
+
for await (const event of session.streamSubagent(called)) {
|
|
257
|
+
console.log(called.data.name, event.type);
|
|
258
|
+
if (isCurrentTurnBoundaryEvent(event)) break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`streamSubagent()` reads the event's `childStreamPath` with the parent session's host and credentials, so the same client works for local and [remote](../remote-agents) children:
|
|
264
|
+
|
|
265
|
+
- A local child's path is its own session stream route on the same deployment. The channel's usual session authorization applies.
|
|
266
|
+
- A remote child's path is a proxy route on the parent deployment. The parent checks that the child belongs to this session, then relays the remote child's stream with the remote agent's authored `auth` and `headers`. The client never needs the remote URL or its credentials.
|
|
267
|
+
|
|
268
|
+
The child has its own cursor, starting at `0`, and reading it never advances the parent's `streamIndex`. Pass `startIndex` to resume, `follow: false` for a bounded read, and `signal` to detach. A child parks after answering and can be continued later, so stop at a turn boundary with `isCurrentTurnBoundaryEvent` when you only need the current turn. Passing a `subagent.called` event from a different session throws.
|
|
269
|
+
|
|
244
270
|
## Abort a request
|
|
245
271
|
|
|
246
272
|
Pass an `AbortSignal` to cancel the POST or stream. Aborting is local transport cancellation: turns are resumable across disconnects, so detaching never stops server-side work. Use `session.cancel()` to stop the active turn, or `session.cancel({ tasks: true })` to also stop background tasks owned by the session. Cancellation is asynchronous; watch the stream for `turn.cancelled` followed by `session.waiting`, and inspect task state in a later turn to confirm task cancellation.
|
|
@@ -57,9 +57,7 @@ A Next.js-centered project uses [`withEve` in `next.config.ts`](../frontend/next
|
|
|
57
57
|
|
|
58
58
|
Use `withEve` from `eve/vercel` when the agents and other applications are peer services. The helper contributes workspace agents to a Vercel service graph; it does not manage or require a particular frontend framework. Unlike `eve/next`, this keeps the project lifecycle separate from Next.js. Both integrations deploy the agent services together in one Vercel project.
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
For a workspace with a peer Next.js frontend under `apps/web/`, replace `vercel.json` with a root `vercel.ts`. The frontend uses an ordinary Next.js config without `eve/next`:
|
|
60
|
+
For a standalone agent or workspace with a peer Next.js frontend under `apps/web/`, replace `vercel.json` with a root `vercel.ts`. The frontend uses an ordinary Next.js config without `eve/next`:
|
|
63
61
|
|
|
64
62
|
```typescript title="vercel.ts"
|
|
65
63
|
import { withEve } from "eve/vercel";
|
|
@@ -82,9 +80,9 @@ export default await withEve({
|
|
|
82
80
|
|
|
83
81
|
Vercel evaluates `vercel.ts` before resolving the service graph. `withEve` adds the root agent, or every direct workspace member, as an independently built service and returns a plain Vercel configuration. Named workspace agents mount at `/eve/<name>/v1/*`; a root agent mounts at `/eve/v1/*`. Vercel then builds the frontend and each eve agent separately. The frontend does not need `withEve` in its framework configuration or a build script that builds the agents.
|
|
84
82
|
|
|
85
|
-
The Web Chat installer
|
|
83
|
+
The Web Chat installer can generate this composition for a standalone agent or a selected workspace agent. Configure authentication for every exposed agent. To self-host the same source layout, replace Vercel composition with your own [process and proxy configuration](./self-hosting#run-workspace-members).
|
|
86
84
|
|
|
87
|
-
Run Vercel CLI 59.16.0 or newer with `vercel dev
|
|
85
|
+
Run Vercel CLI 59.16.0 or newer with `vercel dev` to start the complete service graph locally. A generated Vercel Web Chat project exposes this as `pnpm dev:services`; the first run links the directory when needed and linked projects load their development environment and settings. Use `pnpm dev` or `pnpm dev:eve` when you want one agent and the eve terminal UI, or `pnpm dev:web` when you want the frontend without its agent services. Named agents use the same `/eve/<name>/v1/*` routes in development, and default `defineWorkspaceAgent` transports can call peers without deployment credentials.
|
|
88
86
|
|
|
89
87
|
Generated transport routes are inserted before a filesystem handler or, when no filesystem handler exists, before authored routes. `withEve` throws instead of overwriting an authored service key or exact transport route that belongs to a generated agent. Remove the authored route, and remove or rename the authored service; `withEve` adds both automatically. Names in the array form of `services` must also be unique. Other service names, routes, bindings, and Cron Jobs remain authored in `vercel.ts`.
|
|
90
88
|
|
|
@@ -124,6 +122,8 @@ eve deploy
|
|
|
124
122
|
|
|
125
123
|
`eve deploy` installs dependencies, runs `vercel deploy --prod`, and pulls the project environment after deployment. You can also push to a Git-connected Vercel project. Hosted Vercel builds set `VERCEL`, so `eve build` writes the deployment bundle under `.vercel/output`.
|
|
126
124
|
|
|
125
|
+
When `eve deploy` creates a new Vercel project, it configures trace sampling so traces appear in Agent Runs automatically. See [Agent Runs](../../observability/agent-runs) for details. Pass `--no-trace-sampling` to skip this setting.
|
|
126
|
+
|
|
127
127
|
For non-interactive use, confirm the production deploy up front. `--project` links first, so a new project needs no separate `eve link`:
|
|
128
128
|
|
|
129
129
|
```bash
|
|
@@ -80,13 +80,26 @@ Generated agent services build with `EVE_PUBLIC_ROUTE_PREFIX` set to the agent's
|
|
|
80
80
|
|
|
81
81
|
All fields are optional.
|
|
82
82
|
|
|
83
|
-
| Option | Type | Default | Purpose
|
|
84
|
-
| -------------------- | --------------------- | ------------------------ |
|
|
85
|
-
| `eveRoot` | `string` | Next.js app root |
|
|
86
|
-
| `agents` | `Record<string, ...>` | inferred for a workspace | Named eve agents to mount under `/eve/<name>/v1/*`. `withEve()` discovers project-level `agents/<name>/` members when
|
|
87
|
-
| `eveBuildCommand` | `string` | generated | Build command for generated eve Vercel services. In multi-agent mode this is the default for agents without their own `buildCommand`.
|
|
88
|
-
| `servicePrefix` | `string` | `"/_eve_internal/eve"` | Private route namespace for legacy manual Vercel service configs and non-Vercel production proxying. Named agents derive unique defaults from this prefix.
|
|
89
|
-
| `devServerTimeoutMs` | `number` | `180000` | Maximum time to wait for each eve development server to become available.
|
|
83
|
+
| Option | Type | Default | Purpose |
|
|
84
|
+
| -------------------- | --------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `eveRoot` | `string` | Next.js app root | Eve project root, relative to the Next.js app root unless absolute. It may contain either one `agent/` or an `agents/` workspace. Do not combine with `agents`. |
|
|
86
|
+
| `agents` | `Record<string, ...>` | inferred for a workspace | Named eve agents to mount under `/eve/<name>/v1/*`. `withEve()` discovers project-level `agents/<name>/` members when `agents` and `eveRoot` are unset; otherwise each value is a root string or `{ root, buildCommand?, servicePrefix? }`. |
|
|
87
|
+
| `eveBuildCommand` | `string` | generated | Build command for generated eve Vercel services. In multi-agent mode this is the default for agents without their own `buildCommand`. |
|
|
88
|
+
| `servicePrefix` | `string` | `"/_eve_internal/eve"` | Private route namespace for legacy manual Vercel service configs and non-Vercel production proxying. Named agents derive unique defaults from this prefix. |
|
|
89
|
+
| `devServerTimeoutMs` | `number` | `180000` | Maximum time to wait for each eve development server to become available. |
|
|
90
|
+
|
|
91
|
+
When the Next.js app is a peer of an eve project, select its root without repeating every agent path. The root may contain either one `agent/` or an `agents/` workspace:
|
|
92
|
+
|
|
93
|
+
```ts title="apps/web/next.config.ts"
|
|
94
|
+
import type { NextConfig } from "next";
|
|
95
|
+
import { withEve } from "eve/next";
|
|
96
|
+
|
|
97
|
+
const nextConfig: NextConfig = {};
|
|
98
|
+
|
|
99
|
+
export default withEve(nextConfig, {
|
|
100
|
+
eveRoot: "../..",
|
|
101
|
+
});
|
|
102
|
+
```
|
|
90
103
|
|
|
91
104
|
For slow cold starts, increase the development timeout:
|
|
92
105
|
|
|
@@ -172,7 +172,7 @@ supplied `session` remains externally owned and is never replaced by prewarming
|
|
|
172
172
|
|
|
173
173
|
`data.messages` are eve-owned `EveMessage[]`. Common text, reasoning, file, and dynamic-tool parts follow the [AI SDK `UIMessage`](https://ai-sdk.dev/docs/reference/ai-sdk-core/ui-message) rendering convention, but the types are not interchangeable. eve also exposes authorization and HITL metadata, and a file part's URL can be absent. Adapt those parts before passing messages to an API typed as `UIMessage[]`.
|
|
174
174
|
|
|
175
|
-
When the root agent delegates, its stream emits `subagent.called` with the child's `childSessionId`, then `subagent.completed` when the parent records a successful result, for both blocking and background invocations. A background working receipt appears in `action.result`, without a completion event. The child session can remain available for reuse. Task notifications wake the parent with completion, failure, or cancellation. Detailed child progress lives on the child session's stream instead of being flattened into the root `data.messages`.
|
|
175
|
+
When the root agent delegates, its stream emits `subagent.called` with the child's `childSessionId`, then `subagent.completed` when the parent records a successful result, for both blocking and background invocations. A background working receipt appears in `action.result`, without a completion event. The child session can remain available for reuse. Task notifications wake the parent with completion, failure, or cancellation. Detailed child progress lives on the child session's stream instead of being flattened into the root `data.messages`. When your UI needs live subagent activity, attach a [client session](../client/overview#sessions) to the parent and pass the `subagent.called` event from `events` to [`streamSubagent()`](../client/streaming#follow-a-subagent). It follows local and remote children through the parent, so the browser never calls a remote deployment directly. See [What the parent sees](../../subagents#what-the-parent-sees) for the complete contract.
|
|
176
176
|
|
|
177
177
|
## Sending and streaming
|
|
178
178
|
|
|
@@ -28,10 +28,10 @@ Omitting `agent/instrumentation/agent-runs.ts` preserves that default. Export
|
|
|
28
28
|
|
|
29
29
|
## Enable tracing on Vercel
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
traces. To enable tracing for an existing
|
|
34
|
-
project, then open
|
|
31
|
+
When `eve deploy` creates a new Vercel project, it configures 100% trace
|
|
32
|
+
sampling for all environments. Existing Vercel projects need a sampling rule
|
|
33
|
+
configured to collect traces. To enable tracing for an existing project, select
|
|
34
|
+
your team and project, then open
|
|
35
35
|
[**Settings → Tracing**](https://vercel.com/d?to=%2F%5Bteam%5D%2F%5Bproject%5D%2Fsettings%2Ftracing&title=Go+to+Tracing+settings):
|
|
36
36
|
|
|
37
37
|
1. Select **Add Sampling Rule**.
|
|
@@ -138,7 +138,7 @@ This makes caller authority turn-scoped even when the remote child session is pe
|
|
|
138
138
|
|
|
139
139
|
Identity forwarding does not make a persistent session private to one caller. Conversation history, tool outputs, and other child-session state still persist. If those values must not be visible across users, give each user a distinct child session or enforce that ownership at the application boundary.
|
|
140
140
|
|
|
141
|
-
Forwarding identity is explicit on both sides. The receiver names which deployments it trusts with `eveChannel({ trustedForwarders })` (see [Auth & route protection](./auth-and-route-protection#accepting-forwarded-identity-from-another-deployment)); refusing the forwarder rejects a forwarded principal with a 403. The same trust decision covers parent session lineage and, with principal forwarding, trace-content constraints.
|
|
141
|
+
Forwarding identity is explicit on both sides. The receiver names which deployments it trusts with `eveChannel({ trustedForwarders })` and can limit each one to the principals it may assert (see [Auth & route protection](./auth-and-route-protection#accepting-forwarded-identity-from-another-deployment)); refusing the forwarder or what it asserts rejects a forwarded principal with a 403. The same trust decision covers parent session lineage and, with principal forwarding, trace-content constraints.
|
|
142
142
|
|
|
143
143
|
## Trace propagation
|
|
144
144
|
|
|
@@ -192,6 +192,8 @@ A remote subagent runs as a durable background task in its own deployment:
|
|
|
192
192
|
|
|
193
193
|
The parent stream carries the same `subagent.called`, `action.result`, and `subagent.completed` events as local delegation. For a remote call, `subagent.called.data.remote.url` records the target.
|
|
194
194
|
|
|
195
|
+
Clients follow a remote child through the parent. [`session.streamSubagent()`](./client/streaming#follow-a-subagent) reads `subagent.called.data.childStreamPath`, a route on the parent deployment. The parent verifies that the child belongs to that session, resolves the remote agent's `auth` and `headers`, and relays the child's stream. A browser never calls the remote deployment or holds its credentials; it only needs access to the parent session.
|
|
196
|
+
|
|
195
197
|
An admitted task survives cancellation of the turn that started it; background work that has not yet been admitted is rejected with the cancelled step. Use `task_cancel` to stop an admitted task. eve resolves the remote's `headers` and `auth` again for every cancellation attempt, so rotating credentials work the same way as they do for session creation. Cancellation always uses the standard eve cancel path on `url`, even when `path` customizes only the create-session endpoint. The remote child reports `turn.cancelled` → `session.waiting` on its own stream; an older or unreachable remote is logged but cannot turn the parent's cancellation into a failure.
|
|
196
198
|
|
|
197
199
|
You can also steer a running remote background child by calling its subagent tool with the same `agentId` and an updated `message`. eve cancels the old task and requests cancellation of the remote turn before continuing the same remote session under a new task ID. The remote must support the standard eve cancellation and session-message routes. See [Agent messaging](../subagents#agent-messaging) for the shared steering contract.
|
|
@@ -19,7 +19,7 @@ eve add memory/file
|
|
|
19
19
|
|
|
20
20
|
If an item is not found, `eve add` searches the available catalogs and prints close matches without installing anything.
|
|
21
21
|
|
|
22
|
-
Web Chat installs a
|
|
22
|
+
Web Chat installs a shared Next.js application at `apps/web` for either a standalone agent or a selected member of an agent workspace. Choose **Vercel services** (recommended) to deploy Web Chat and agents as separate services, or **Next.js** to serve Web Chat and route agent requests through one Next.js app. Existing authored Next.js or Vercel configuration is preserved, and eve stops with manual composition guidance instead of overwriting it. See [Project Structure](./concepts/project-structure) for browser-app placement and [Next.js](./guides/frontend/nextjs) for Next.js-owned integration.
|
|
23
23
|
|
|
24
24
|
If you do not know an item name yet, run `eve add` without an argument. Its help output shows how to search the registry with `eve registry search <query>`.
|
|
25
25
|
|
|
@@ -64,6 +64,22 @@ Paths below are relative to the agent directory. Root agents can use every path;
|
|
|
64
64
|
| `schedules/` | Recurring jobs | No | `defineSchedule` modules or Markdown prompts with `cron` frontmatter; recursive nesting is supported. |
|
|
65
65
|
| `subagents/` | Specialist child agents | Yes | Local directories or remote-agent definitions; nested subagents are supported. |
|
|
66
66
|
|
|
67
|
+
## Colocated tests
|
|
68
|
+
|
|
69
|
+
eve ignores JavaScript and TypeScript modules named `*.test.*` or `*.spec.*`,
|
|
70
|
+
along with `__tests__/` directories, during automatic discovery and when choosing
|
|
71
|
+
extension runtime entries.
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
agent/tools/
|
|
75
|
+
├── get_weather.ts # registered as get_weather
|
|
76
|
+
├── get_weather.test.ts # excluded from discovery
|
|
77
|
+
└── __tests__/ # excluded from discovery
|
|
78
|
+
└── fixtures.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Explicit imports, sandbox workspace files, and packaged skill resources are unaffected.
|
|
82
|
+
|
|
67
83
|
## Files available in the sandbox
|
|
68
84
|
|
|
69
85
|
Agent source files are not automatically available to shell commands. Put files to copy into the sandbox's `/workspace/` under `agent/sandbox/workspace/`. Skill runtime files are seeded separately under `$HOME/.agents/skills/`, with `/workspace/skills/` as a fallback. See [Sandboxes](/docs/sandbox) and [Skills](/docs/skills).
|
package/docs/reference/cli.md
CHANGED
|
@@ -311,7 +311,7 @@ eve traces --json # dump the full trace as JSON
|
|
|
311
311
|
|
|
312
312
|
Reads the immutable OTLP/JSON segments under `.eve/traces/v1`, so `eve dev` need not be running. Accepts a full trace id, a `gen_ai.conversation.id`, or an unambiguous prefix of either. Malformed segments are skipped without hiding valid spans from the same trace.
|
|
313
313
|
|
|
314
|
-
Span rows carry inline metrics when the span recorded them — `↑input`/`↓output` token counts, gateway cost, and the tool name for `execute_tool` spans
|
|
314
|
+
Span rows carry inline metrics when the span recorded them — `↑input`/`↓output` token counts, gateway cost, and the tool name for `execute_tool` spans. The header lists models across the trace, sums token usage and cost from step spans, and counts all error-bearing spans. `--verbose` expands each span under its tree row: status (with the error message on failures), timing, ids, every attribute (prompts, responses, and tool payloads as transcripts or pretty-printed JSON), and every span event with its offset from span start. `--json` prints the same records as JSON, one object per selected trace.
|
|
315
315
|
|
|
316
316
|
Every subagent activation starts its own trace. The first child's `invoke_agent` root links to the dispatching caller with `eve.link.type=agent.dispatch`; remote agents preserve that caller in W3C `tracestate` even when HTTP `traceparent` advances through platform ingress. Later turns also start fresh traces without repeating the initial caller link. All related sessions retain the same `gen_ai.conversation.id`, and `agent.subagent.name` labels the child invocation.
|
|
317
317
|
|
package/docs/subagents/index.mdx
CHANGED
|
@@ -9,6 +9,12 @@ Use a subagent to run independent work in parallel, narrow the available tools,
|
|
|
9
9
|
- Use a [declared local subagent](#declared-subagents) for a specialist with its own directory and authored capabilities, rather than inheriting the root's.
|
|
10
10
|
- Use a [remote agent](./guides/remote-agents) to delegate to a separately deployed eve agent, with its own configuration and authentication.
|
|
11
11
|
|
|
12
|
+
A subagent can finish a model turn while background tasks started in that turn are still running.
|
|
13
|
+
That turn yields; its interim reply does not complete the caller's delegated task. Background work started by an earlier turn does not hold the reply, and a turn that ends with an error always answers the caller. If the child session expires, resets, or closes before replying, the delegated task fails and reports the usage accumulated since its previous settlement.
|
|
14
|
+
After the nested tasks finish, the subagent resumes and returns its final result to
|
|
15
|
+
the caller. This applies to root-agent copies, declared local subagents, and remote
|
|
16
|
+
subagents. The subagent session remains available for later calls.
|
|
17
|
+
|
|
12
18
|
## Completion batching
|
|
13
19
|
|
|
14
20
|
Overlapping background work owned by a session forms a cohort. Tasks launched in
|
|
@@ -99,7 +105,7 @@ The parent can alternatively export `disableTool()` from a same-named tool path,
|
|
|
99
105
|
|
|
100
106
|
Every declared local or remote subagent runs as a durable background task: the call returns `{ status: "working", taskId, agentId }` immediately, then task notifications wake the parent with completion, failure, or cancellation. Human input requests surface separately on the parent session.
|
|
101
107
|
|
|
102
|
-
`task_cancel` is available to sessions that own background tasks, including a child that starts nested background work.
|
|
108
|
+
`task_cancel` is available to sessions that own background tasks, including a child that starts nested background work. Cancelling a delegated agent task also requests cancellation of its child's nested background tasks, even after that child's model turn has yielded. The child does not start another model turn for notifications from that cancelled work. This applies to self, local, and remote delegation. The calling model receives the cancellation receipt in the `task_cancel` result; a later report of that same outcome does not start another model turn.
|
|
103
109
|
|
|
104
110
|
A mounted extension can also contribute declared subagents from `extension/subagents/`. The mount namespace prefixes the subagent visible to the consuming agent node: mounting an extension as `crm` exposes its `reviewer` subagent as `crm__reviewer`. The contributed subagent keeps its own isolated tools, connections, skills, hooks, instructions, sandbox, and nested subagents, and its modules can read configuration from the extension handle. See [Extensions](./extensions#add-a-subagent) for the authoring and override behavior.
|
|
105
111
|
|
|
@@ -253,7 +259,7 @@ By default, a subagent named `researcher` collides with an authored tool named `
|
|
|
253
259
|
|
|
254
260
|
Do not rely on subagent delegation by itself as an approval boundary. Put sensitive tools behind `approval`, connection approval, route/session authorization, or other controls wherever those tools can be called.
|
|
255
261
|
|
|
256
|
-
Each delegated subagent spins up its own child session and stream. The parent stream carries the control-plane events `subagent.called` and `subagent.completed`, plus interactive `input.requested`, `authorization.required`, and `authorization.completed` events proxied from descendants so the root channel can prompt the user. To follow the child's other progress,
|
|
262
|
+
Each delegated subagent spins up its own child session and stream. The parent stream carries the control-plane events `subagent.called` and `subagent.completed`, plus interactive `input.requested`, `authorization.required`, and `authorization.completed` events proxied from descendants so the root channel can prompt the user. To follow the child's other progress, pass the `subagent.called` event to [`session.streamSubagent()`](./guides/client/streaming#follow-a-subagent) on a client session attached to the parent. It reads `subagent.called.data.childStreamPath`: the child's own session stream for a local child, or a parent-origin proxy for a remote child, which the parent authenticates to the remote deployment.
|
|
257
263
|
|
|
258
264
|
Both blocking and background invocations emit `subagent.called` after dispatch and `subagent.completed` after the parent records successful completion. Completion carries the actual output and identifies the same invocation by `callId`; the child session can remain available for reuse. A background working receipt is returned as an `action.result` tool output and does not emit completion. Background completion events do not wait for the cohort report. Failure and cancellation are not successful completion; task notifications retain those outcomes.
|
|
259
265
|
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type ExtensionBuildConfig } from "#internal/nitro/host/build-extension.js";
|
|
2
|
-
/** Build inputs retained with a prepared dev host for path-scoped extension HMR. */
|
|
3
|
-
export interface DevelopmentWorkspaceExtension {
|
|
4
|
-
readonly config: ExtensionBuildConfig;
|
|
5
|
-
/** Canonical package root, with workspace links resolved. */
|
|
6
|
-
readonly packageRoot: string;
|
|
7
|
-
/** Non-source inputs that affect publisher output, such as tsconfig files. */
|
|
8
|
-
readonly buildConfigPaths: readonly string[];
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Builds mounted source-backed workspace extensions before the consuming agent
|
|
12
|
-
* compiles and returns the inputs needed to scope the next development rebuild.
|
|
13
|
-
*/
|
|
14
|
-
export declare function prepareDevelopmentWorkspaceExtensions(input: {
|
|
15
|
-
readonly appRoot: string;
|
|
16
|
-
readonly changedPaths?: readonly string[];
|
|
17
|
-
readonly previousExtensions?: readonly DevelopmentWorkspaceExtension[];
|
|
18
|
-
}): Promise<readonly DevelopmentWorkspaceExtension[]>;
|