eve 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/src/channel/forwarded-principal.d.ts +4 -4
- package/dist/src/compiler/extension-compatibility.d.ts +7 -5
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.d.ts +3 -0
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/normalize-tool.js +1 -1
- package/dist/src/context/build-dynamic-tools.d.ts +5 -5
- package/dist/src/context/build-dynamic-tools.js +1 -1
- package/dist/src/context/dynamic-subagent-lifecycle.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.d.ts +8 -27
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/keys.d.ts +10 -14
- package/dist/src/context/keys.js +1 -1
- package/dist/src/context/provider.d.ts +5 -1
- package/dist/src/context/run-step.d.ts +3 -2
- package/dist/src/context/run-step.js +1 -1
- package/dist/src/execution/agent-handle-dispatch.d.ts +3 -0
- package/dist/src/execution/agent-handle-dispatch.js +1 -1
- package/dist/src/execution/delegation-tool.d.ts +9 -1
- package/dist/src/execution/delegation-tool.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-shared.d.ts +14 -1
- package/dist/src/execution/dispatch-runtime-actions-shared.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/history-view.d.ts +9 -0
- package/dist/src/execution/history-view.js +1 -0
- package/dist/src/execution/next-driver-action.d.ts +33 -1
- package/dist/src/execution/node-step.d.ts +5 -2
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/remote-agent-dispatch.d.ts +2 -0
- package/dist/src/execution/remote-agent-dispatch.js +1 -1
- package/dist/src/execution/session-callback-step.d.ts +2 -2
- package/dist/src/execution/session-callback-step.js +1 -1
- package/dist/src/execution/tasks/child/steps.js +1 -1
- package/dist/src/execution/tasks/child/update.d.ts +2 -2
- package/dist/src/execution/tasks/child/update.js +1 -1
- package/dist/src/execution/tasks/child/workflow.js +1 -1
- package/dist/src/execution/tasks/parent/agent-views.d.ts +2 -1
- package/dist/src/execution/tasks/parent/agent-views.js +1 -1
- package/dist/src/execution/tasks/parent/continuation-dispatch.d.ts +6 -0
- package/dist/src/execution/tasks/parent/continuation-dispatch.js +1 -1
- package/dist/src/execution/tasks/parent/control-shared.d.ts +1 -1
- package/dist/src/execution/tasks/parent/control-shared.js +1 -1
- package/dist/src/execution/tasks/parent/delegate.d.ts +20 -6
- package/dist/src/execution/tasks/parent/delegate.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch-task-step.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch.d.ts +13 -1
- package/dist/src/execution/tasks/parent/dispatch.js +1 -1
- package/dist/src/execution/tasks/parent/hitl-proxy-steps.js +1 -1
- package/dist/src/execution/tasks/parent/tool-execution.d.ts +46 -0
- package/dist/src/execution/tasks/parent/tool-execution.js +1 -0
- package/dist/src/execution/tool-auth.d.ts +12 -3
- package/dist/src/execution/tool-auth.js +1 -1
- package/dist/src/execution/turn-cancellation-control.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/wire/session-inbox-wire.v1.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +1 -54
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/advertised-tools.js +1 -1
- package/dist/src/harness/background-tools.d.ts +37 -0
- package/dist/src/harness/background-tools.js +1 -0
- package/dist/src/harness/execute-tool.d.ts +10 -1
- package/dist/src/harness/handles/transitions.d.ts +36 -0
- package/dist/src/harness/handles/transitions.js +1 -1
- package/dist/src/harness/messages.d.ts +2 -0
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/harness/tools.d.ts +5 -1
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/harness/types.d.ts +13 -0
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/schema-backed.js +1 -1
- package/dist/src/internal/authored-module-loader.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-capability-transform-plugin.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.d.ts +13 -0
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.d.ts +7 -31
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +4 -4
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/public/channels/eve.d.ts +7 -7
- package/dist/src/public/channels/eve.js +1 -1
- package/dist/src/public/definitions/remote-agent.d.ts +7 -5
- package/dist/src/public/definitions/tool.d.ts +23 -0
- package/dist/src/public/definitions/tool.js +1 -1
- package/dist/src/public/tools/approval/approval-helpers.js +1 -1
- package/dist/src/public/tools/index.d.ts +1 -1
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
- package/dist/src/runtime/framework-tools/subagent/local.d.ts +41 -0
- package/dist/src/runtime/framework-tools/subagent/local.js +1 -0
- package/dist/src/runtime/framework-tools/subagent/remote.d.ts +23 -0
- package/dist/src/runtime/framework-tools/subagent/remote.js +1 -0
- package/dist/src/runtime/framework-tools/tasks.d.ts +11 -2
- package/dist/src/runtime/framework-tools/tasks.js +1 -1
- package/dist/src/runtime/resolve-tool.js +1 -1
- package/dist/src/runtime/session-callback-route.js +1 -1
- package/dist/src/setup/integrations/linq/management.d.ts +5 -0
- package/dist/src/setup/integrations/linq/management.js +1 -0
- package/dist/src/setup/integrations/linq/setup.d.ts +5 -1
- package/dist/src/setup/integrations/linq/setup.js +3 -3
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +4 -10
- package/dist/src/setup/scaffold/create/web-template.d.ts +0 -1
- package/dist/src/setup/scaffold/create/web-template.js +1 -1
- package/dist/src/setup/scaffold/update/channels.d.ts +1 -1
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/scaffold/update/package-json.d.ts +0 -2
- package/dist/src/setup/scaffold/update/package-json.js +1 -1
- package/dist/src/setup/scaffold/workspace-root.d.ts +0 -1
- package/dist/src/setup/scaffold/workspace-root.js +1 -1
- package/dist/src/shared/durable-dynamic-tool-callbacks.d.ts +34 -0
- package/dist/src/shared/durable-dynamic-tool-callbacks.js +1 -0
- package/dist/src/shared/dynamic-tool-definition.d.ts +2 -4
- package/dist/src/shared/empty-delivery.js +1 -1
- package/dist/src/shared/history-view.d.ts +22 -0
- package/dist/src/shared/history-view.js +1 -0
- package/dist/src/shared/json.d.ts +2 -0
- package/dist/src/shared/json.js +1 -1
- package/dist/src/shared/tool-definition.d.ts +4 -1
- package/dist/src/shared/tool-task.d.ts +107 -0
- package/dist/src/shared/tool-task.js +1 -0
- package/dist/src/tasks/delivery-context.d.ts +12 -0
- package/dist/src/tasks/delivery-context.js +17 -0
- package/dist/src/tasks/json.d.ts +25 -10
- package/dist/src/tasks/json.js +1 -1
- package/dist/src/tasks/session-index.d.ts +5 -3
- package/dist/src/tasks/session-index.js +1 -1
- package/dist/src/tasks/transitions.d.ts +40 -5
- package/dist/src/tasks/transitions.js +1 -1
- package/dist/src/tasks/types.d.ts +46 -4
- package/dist/src/tasks/types.js +1 -1
- package/docs/channels/linq.mdx +1 -1
- package/docs/getting-started.mdx +36 -36
- package/docs/guides/auth-and-route-protection.md +6 -2
- package/docs/guides/dynamic-capabilities.md +12 -10
- package/docs/guides/remote-agents.md +10 -2
- package/docs/tools/overview.mdx +19 -0
- package/package.json +1 -1
package/dist/src/tasks/json.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { JsonValue } from "#shared/json.js";
|
|
|
3
3
|
import type { TaskView } from "#tasks/types.js";
|
|
4
4
|
/** Model-visible task shape. Unlisted private fields are stripped by zod. */
|
|
5
5
|
declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
6
|
-
metadata: z.ZodObject<{
|
|
6
|
+
metadata: z.ZodUnion<readonly [z.ZodObject<{
|
|
7
7
|
agentId: z.ZodString;
|
|
8
8
|
kind: z.ZodLiteral<"subagent">;
|
|
9
9
|
mode: z.ZodEnum<{
|
|
@@ -11,11 +11,14 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
11
11
|
remote: "remote";
|
|
12
12
|
}>;
|
|
13
13
|
name: z.ZodString;
|
|
14
|
-
}, z.core.$strip
|
|
14
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
15
|
+
kind: z.ZodString;
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
}, z.core.$strip>]>;
|
|
15
18
|
taskId: z.ZodString;
|
|
16
19
|
status: z.ZodLiteral<"working">;
|
|
17
20
|
}, z.core.$strip>, z.ZodObject<{
|
|
18
|
-
metadata: z.ZodObject<{
|
|
21
|
+
metadata: z.ZodUnion<readonly [z.ZodObject<{
|
|
19
22
|
agentId: z.ZodString;
|
|
20
23
|
kind: z.ZodLiteral<"subagent">;
|
|
21
24
|
mode: z.ZodEnum<{
|
|
@@ -23,12 +26,15 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
23
26
|
remote: "remote";
|
|
24
27
|
}>;
|
|
25
28
|
name: z.ZodString;
|
|
26
|
-
}, z.core.$strip
|
|
29
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
30
|
+
kind: z.ZodString;
|
|
31
|
+
name: z.ZodString;
|
|
32
|
+
}, z.core.$strip>]>;
|
|
27
33
|
taskId: z.ZodString;
|
|
28
34
|
inputRequests: z.ZodReadonly<z.ZodArray<z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>>>;
|
|
29
35
|
status: z.ZodLiteral<"input_required">;
|
|
30
36
|
}, z.core.$strip>, z.ZodObject<{
|
|
31
|
-
metadata: z.ZodObject<{
|
|
37
|
+
metadata: z.ZodUnion<readonly [z.ZodObject<{
|
|
32
38
|
agentId: z.ZodString;
|
|
33
39
|
kind: z.ZodLiteral<"subagent">;
|
|
34
40
|
mode: z.ZodEnum<{
|
|
@@ -36,7 +42,10 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
36
42
|
remote: "remote";
|
|
37
43
|
}>;
|
|
38
44
|
name: z.ZodString;
|
|
39
|
-
}, z.core.$strip
|
|
45
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
46
|
+
kind: z.ZodString;
|
|
47
|
+
name: z.ZodString;
|
|
48
|
+
}, z.core.$strip>]>;
|
|
40
49
|
taskId: z.ZodString;
|
|
41
50
|
lastOutput: z.ZodObject<{
|
|
42
51
|
data: z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>;
|
|
@@ -44,7 +53,7 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
44
53
|
}, z.core.$strip>;
|
|
45
54
|
status: z.ZodLiteral<"completed">;
|
|
46
55
|
}, z.core.$strip>, z.ZodObject<{
|
|
47
|
-
metadata: z.ZodObject<{
|
|
56
|
+
metadata: z.ZodUnion<readonly [z.ZodObject<{
|
|
48
57
|
agentId: z.ZodString;
|
|
49
58
|
kind: z.ZodLiteral<"subagent">;
|
|
50
59
|
mode: z.ZodEnum<{
|
|
@@ -52,7 +61,10 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
52
61
|
remote: "remote";
|
|
53
62
|
}>;
|
|
54
63
|
name: z.ZodString;
|
|
55
|
-
}, z.core.$strip
|
|
64
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
65
|
+
kind: z.ZodString;
|
|
66
|
+
name: z.ZodString;
|
|
67
|
+
}, z.core.$strip>]>;
|
|
56
68
|
taskId: z.ZodString;
|
|
57
69
|
lastOutput: z.ZodObject<{
|
|
58
70
|
data: z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>;
|
|
@@ -60,7 +72,7 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
60
72
|
}, z.core.$strip>;
|
|
61
73
|
status: z.ZodLiteral<"failed">;
|
|
62
74
|
}, z.core.$strip>, z.ZodObject<{
|
|
63
|
-
metadata: z.ZodObject<{
|
|
75
|
+
metadata: z.ZodUnion<readonly [z.ZodObject<{
|
|
64
76
|
agentId: z.ZodString;
|
|
65
77
|
kind: z.ZodLiteral<"subagent">;
|
|
66
78
|
mode: z.ZodEnum<{
|
|
@@ -68,7 +80,10 @@ declare const taskViewJsonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
68
80
|
remote: "remote";
|
|
69
81
|
}>;
|
|
70
82
|
name: z.ZodString;
|
|
71
|
-
}, z.core.$strip
|
|
83
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
84
|
+
kind: z.ZodString;
|
|
85
|
+
name: z.ZodString;
|
|
86
|
+
}, z.core.$strip>]>;
|
|
72
87
|
taskId: z.ZodString;
|
|
73
88
|
status: z.ZodLiteral<"cancelled">;
|
|
74
89
|
}, z.core.$strip>], "status">;
|
package/dist/src/tasks/json.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{jsonValueSchema}from"#shared/json-schemas.js";const taskMetadataJsonSchema=z.object({agentId:z.string(),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string()}),taskOutputJsonSchema=z.object({data:jsonValueSchema,type:z.enum([`result`,`error`])}),taskViewJsonBaseShape={metadata:taskMetadataJsonSchema,taskId:z.string()},taskViewJsonSchema=z.discriminatedUnion(`status`,[z.object({...taskViewJsonBaseShape,status:z.literal(`working`)}),z.object({...taskViewJsonBaseShape,inputRequests:z.array(jsonValueSchema).readonly(),status:z.literal(`input_required`)}),z.object({...taskViewJsonBaseShape,lastOutput:taskOutputJsonSchema.extend({type:z.literal(`result`)}),status:z.literal(`completed`)}),z.object({...taskViewJsonBaseShape,lastOutput:taskOutputJsonSchema.extend({type:z.literal(`error`)}),status:z.literal(`failed`)}),z.object({...taskViewJsonBaseShape,status:z.literal(`cancelled`)})]);function taskViewToJson(e){return taskViewJsonSchema.parse(e)}function taskViewsToJson(e){return{tasks:e.map(e=>taskViewToJson(e))}}export{taskViewToJson,taskViewsToJson};
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{jsonValueSchema}from"#shared/json-schemas.js";import{readSubagentTaskMetadata}from"#tasks/types.js";const taskMetadataJsonSchema=z.union([z.object({agentId:z.string(),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string()}),z.object({kind:z.string(),name:z.string()})]),taskOutputJsonSchema=z.object({data:jsonValueSchema,type:z.enum([`result`,`error`])}),taskViewJsonBaseShape={metadata:taskMetadataJsonSchema,taskId:z.string()},taskViewJsonSchema=z.discriminatedUnion(`status`,[z.object({...taskViewJsonBaseShape,status:z.literal(`working`)}),z.object({...taskViewJsonBaseShape,inputRequests:z.array(jsonValueSchema).readonly(),status:z.literal(`input_required`)}),z.object({...taskViewJsonBaseShape,lastOutput:taskOutputJsonSchema.extend({type:z.literal(`result`)}),status:z.literal(`completed`)}),z.object({...taskViewJsonBaseShape,lastOutput:taskOutputJsonSchema.extend({type:z.literal(`error`)}),status:z.literal(`failed`)}),z.object({...taskViewJsonBaseShape,status:z.literal(`cancelled`)})]);function taskViewToJson(e){let t=readSubagentTaskMetadata(e),n=t===void 0?e.metadata:{agentId:t.agentId,kind:t.kind,mode:t.mode,name:t.name};return taskViewJsonSchema.parse({...e,metadata:n})}function taskViewsToJson(e){return{tasks:e.map(e=>taskViewToJson(e))}}export{taskViewToJson,taskViewsToJson};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HarnessSession, SessionStateMap } from "#harness/types.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { TaskExecutorBinding } from "#shared/tool-task.js";
|
|
3
|
+
import { type DurableTaskMetadata, type TaskView } from "#tasks/types.js";
|
|
3
4
|
/**
|
|
4
5
|
* Session-state key for the parent's live-task index.
|
|
5
6
|
*
|
|
@@ -27,8 +28,9 @@ export interface SessionTaskIndexEntry {
|
|
|
27
28
|
readonly taskInboxToken: string;
|
|
28
29
|
readonly createdByStepIndex?: number;
|
|
29
30
|
readonly createdByTurnId: string;
|
|
30
|
-
readonly
|
|
31
|
-
readonly
|
|
31
|
+
readonly executor?: TaskExecutorBinding;
|
|
32
|
+
readonly metadata: DurableTaskMetadata;
|
|
33
|
+
readonly operationId?: string;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* Reads and validates the task index from session state.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";const SESSION_TASKS_STATE_KEY=`eve.tasks`,taskMetadataSchema=z.strictObject({agentId:z.string().min(1),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string().min(1)}),taskViewBaseShape={executor:z.strictObject({childSessionId:z.string().min(1).optional(),childTurnId:z.string().min(1).optional(),lifecycle:z.enum([`parked`,`terminal`]).optional()}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),usage:z.strictObject({cacheReadTokens:z.number().nonnegative(),cacheWriteTokens:z.number().nonnegative(),inputTokens:z.number().nonnegative(),outputTokens:z.number().nonnegative()}).optional()},taskViewSchema=z.discriminatedUnion(`status`,[z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`result`)}),status:z.literal(`completed`)}),z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`error`)}),status:z.literal(`failed`)}),z.strictObject({...taskViewBaseShape,status:z.literal(`cancelled`)})]),sessionTaskIndexEntrySchema=z.strictObject({taskInboxToken:z.string().min(1),createdByStepIndex:z.number().int().nonnegative().optional(),createdByTurnId:z.string().min(1),metadata:taskMetadataSchema,operationId:z.string().min(1),taskId:z.string().min(1),taskRunId:z.string().min(1),terminalView:taskViewSchema.optional()}),sessionTaskIndexSchema=z.strictObject({tasks:z.array(sessionTaskIndexEntrySchema)}).refine(e=>new Set(e.tasks.map(e=>e.taskId)).size===e.tasks.length,{message:`Task ids must be unique.`}).refine(e=>e.tasks.every(e=>e.terminalView===void 0||e.terminalView.taskId===e.taskId&&sameTaskMetadata(e.terminalView.metadata,e.metadata)),{message:`Cached terminal views must match their task index entry.`});function getSessionTaskIndex(e){let
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{sameTaskMetadata}from"#tasks/types.js";const SESSION_TASKS_STATE_KEY=`eve.tasks`,taskMetadataSchema=z.union([z.strictObject({agentId:z.string().min(1),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string().min(1)}),z.strictObject({kind:z.string().min(1),name:z.string().min(1)})]),taskViewBaseShape={executor:z.strictObject({binding:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional(),childSessionId:z.string().min(1).optional(),childTurnId:z.string().min(1).optional(),lifecycle:z.enum([`parked`,`terminal`]).optional()}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),usage:z.strictObject({cacheReadTokens:z.number().nonnegative(),cacheWriteTokens:z.number().nonnegative(),inputTokens:z.number().nonnegative(),outputTokens:z.number().nonnegative()}).optional()},taskViewSchema=z.discriminatedUnion(`status`,[z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`result`)}),status:z.literal(`completed`)}),z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`error`)}),status:z.literal(`failed`)}),z.strictObject({...taskViewBaseShape,status:z.literal(`cancelled`)})]),sessionTaskIndexEntrySchema=z.strictObject({taskInboxToken:z.string().min(1),createdByStepIndex:z.number().int().nonnegative().optional(),createdByTurnId:z.string().min(1),executor:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional(),metadata:taskMetadataSchema,operationId:z.string().min(1).optional(),taskId:z.string().min(1),taskRunId:z.string().min(1),terminalView:taskViewSchema.optional()}),sessionTaskIndexSchema=z.strictObject({tasks:z.array(sessionTaskIndexEntrySchema)}).refine(e=>new Set(e.tasks.map(e=>e.taskId)).size===e.tasks.length,{message:`Task ids must be unique.`}).refine(e=>e.tasks.every(e=>e.terminalView===void 0||e.terminalView.taskId===e.taskId&&sameTaskMetadata(e.terminalView.metadata,e.metadata)),{message:`Cached terminal views must match their task index entry.`});function getSessionTaskIndex(e){let t=e?.[SESSION_TASKS_STATE_KEY];if(t===void 0)return[];let n=sessionTaskIndexSchema.safeParse(t);if(!n.success)throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": ${n.error.message}`);return n.data.tasks}function cacheTerminalTaskView(e,n){if(!isValidTerminalView(n))throw Error(`Cannot cache invalid terminal task "${n.taskId}".`);let r=getSessionTaskIndex(e),i=r.findIndex(e=>e.taskId===n.taskId);if(i<0)return e;if(!sameTaskMetadata(r[i].metadata,n.metadata))throw Error(`Task view metadata does not match index entry "${n.taskId}".`);let a=[...r];return a[i]={...a[i],terminalView:n},{...e,[SESSION_TASKS_STATE_KEY]:{tasks:a}}}function isValidTerminalView(e){if(e.inputRequests!==void 0)return!1;switch(e.status){case`completed`:return e.lastOutput?.type===`result`;case`failed`:return e.lastOutput?.type===`error`;case`cancelled`:return e.lastOutput===void 0;case`working`:return!1}}function findSessionTaskEntry(e,t){return getSessionTaskIndex(e).find(e=>e.taskId===t)}function recordSessionTask(e,t){let n=[...getSessionTaskIndex(e.state).filter(e=>e.taskId!==t.taskId),t];return{...e,state:{...e.state,[SESSION_TASKS_STATE_KEY]:{tasks:n}}}}export{SESSION_TASKS_STATE_KEY,cacheTerminalTaskView,findSessionTaskEntry,getSessionTaskIndex,recordSessionTask};
|
|
@@ -1,23 +1,58 @@
|
|
|
1
1
|
import type { TaskCommand, TaskView } from "#tasks/types.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Action taken on one command applied to a task view.
|
|
4
4
|
*
|
|
5
|
-
* - `accepted`: the
|
|
5
|
+
* - `accepted`: the view changed; the new view must be appended.
|
|
6
6
|
* - `noop`: the command is recognized and benign (idempotent cancel,
|
|
7
7
|
* stale answer); nothing changed and nothing is appended.
|
|
8
8
|
* - `rejected`: the command is invalid for the current status; the
|
|
9
9
|
* reason is diagnostic only.
|
|
10
10
|
*/
|
|
11
11
|
type TaskTransitionResult = {
|
|
12
|
-
readonly
|
|
12
|
+
readonly action: "accepted";
|
|
13
13
|
readonly view: TaskView;
|
|
14
14
|
} | {
|
|
15
|
-
readonly
|
|
15
|
+
readonly action: "noop";
|
|
16
16
|
readonly view: TaskView;
|
|
17
17
|
} | {
|
|
18
|
-
readonly
|
|
18
|
+
readonly action: "rejected";
|
|
19
19
|
readonly view: TaskView;
|
|
20
20
|
readonly reason: string;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Pure transition function for the task lifecycle:
|
|
24
|
+
*
|
|
25
|
+
* ```text
|
|
26
|
+
* working <-> input_required
|
|
27
|
+
* | |
|
|
28
|
+
* +-----> completed
|
|
29
|
+
* +-----> failed
|
|
30
|
+
* +-----> cancelled
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* Terminal states are final: a late child result can never revive a
|
|
34
|
+
* cancelled task, and repeated cancellation is idempotent. The durable
|
|
35
|
+
* task run is the only caller that persists accepted views, which is
|
|
36
|
+
* what serializes competing completion, cancellation, and input
|
|
37
|
+
* transitions.
|
|
38
|
+
*
|
|
39
|
+
* Orthogonal to the status, the view carries private executor state
|
|
40
|
+
* (`TaskExecutorState`) with its own lifecycle. These commands move
|
|
41
|
+
* executor fields, never the status above:
|
|
42
|
+
*
|
|
43
|
+
* ```text
|
|
44
|
+
* binding: unset --bind-------> bound (replay noop, conflict rejected)
|
|
45
|
+
* address: unset --start-turn-> session pinned (turn id updated per delivery)
|
|
46
|
+
* verdict: unset --complete/fail/cancel/settle-executor-> parked | terminal
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* - `bind` writes the executor binding exactly once: replaying the
|
|
50
|
+
* same binding is a noop, a different one is rejected.
|
|
51
|
+
* - `start-turn` records the child session/turn ids used to address
|
|
52
|
+
* the executor, rejecting a child-session mismatch.
|
|
53
|
+
* - Terminal commands and a late `settle-executor` record the child's
|
|
54
|
+
* lifecycle verdict: `parked` means the child session survived and
|
|
55
|
+
* can take another delivery, `terminal` means it ended with the turn.
|
|
56
|
+
*/
|
|
22
57
|
export declare function applyTaskTransition(view: TaskView, command: TaskCommand): TaskTransitionResult;
|
|
23
58
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isTerminalTaskStatus,readTaskInputRequestId}from"#tasks/types.js";function terminalView(e,t,n){let r={executor:t.lifecycle===void 0?e.executor:{...e.executor,lifecycle:t.lifecycle},metadata:e.metadata,taskId:e.taskId};switch(t.usage!==void 0&&(r.usage=t.usage),n.status){case`completed`:return{...r,lastOutput:n.lastOutput,status:`completed`};case`failed`:return{...r,lastOutput:n.lastOutput,status:`failed`};case`cancelled`:return{...r,status:`cancelled`}}}function applyTaskTransition(
|
|
1
|
+
import{jsonValuesEqual}from"#shared/json.js";import{isTerminalTaskStatus,readTaskInputRequestId}from"#tasks/types.js";function terminalView(e,t,n){let r={executor:t.lifecycle===void 0?e.executor:{...e.executor,lifecycle:t.lifecycle},metadata:e.metadata,taskId:e.taskId};switch(t.usage!==void 0&&(r.usage=t.usage),n.status){case`completed`:return{...r,lastOutput:n.lastOutput,status:`completed`};case`failed`:return{...r,lastOutput:n.lastOutput,status:`failed`};case`cancelled`:return{...r,status:`cancelled`}}}function applyTaskTransition(r,i){if(i.kind===`bind`){let t=r.executor?.binding;return t!==void 0&&t.kind===i.executor.kind&&jsonValuesEqual(t.data,i.executor.data)?{action:`noop`,view:r}:t===void 0?{action:`accepted`,view:{...r,executor:{...r.executor,binding:i.executor}}}:{action:`rejected`,reason:`Task "${r.taskId}" already has an executor binding.`,view:r}}if(isTerminalTaskStatus(r.status)){if(i.kind===`settle-executor`){let e={...r.executor,lifecycle:`terminal`};if(sameUsage(r.usage,i.usage)&&r.executor?.lifecycle===`terminal`)return{action:`noop`,view:r};let t={...r,executor:e};return{action:`accepted`,view:i.usage===void 0?t:{...t,usage:i.usage}}}return i.kind===`cancel`&&r.status===`cancelled`?{action:`noop`,view:r}:{action:`rejected`,reason:`Task "${r.taskId}" is already ${r.status}; "${i.kind}" cannot change a terminal task.`,view:r}}switch(i.kind){case`complete`:return{action:`accepted`,view:terminalView(r,i,{lastOutput:{data:i.data,type:`result`},status:`completed`})};case`fail`:case`reject-dispatch`:return{action:`accepted`,view:terminalView(r,i,{lastOutput:{data:i.data,type:`error`},status:`failed`})};case`cancel`:return{action:`accepted`,view:terminalView(r,i,{status:`cancelled`})};case`settle-executor`:return{action:`rejected`,reason:`Task "${r.taskId}" is not terminal; usage settles with its terminal command.`,view:r};case`require-authorization`:{let e={blockedOn:`authorization`,requestId:i.requestId};return r.status===`input_required`?r.inputRequests.some(e=>readTaskInputRequestId(e)===i.requestId)?{action:`noop`,view:r}:{action:`accepted`,view:{...r,inputRequests:[...r.inputRequests,e]}}:{action:`accepted`,view:{inputRequests:[e],executor:r.executor,metadata:r.metadata,status:`input_required`,taskId:r.taskId}}}case`require-input`:return isValidInputRequestBatch(i.inputRequests)?{action:`accepted`,view:{inputRequests:i.inputRequests,executor:r.executor,metadata:r.metadata,status:`input_required`,taskId:r.taskId}}:{action:`rejected`,reason:`Task "${r.taskId}" received an invalid input request batch.`,view:r};case`ready`:return{action:`accepted`,view:r};case`answered`:{if(r.status!==`input_required`)return{action:`noop`,view:r};let e=new Set(i.requestIds),t=r.inputRequests,a=t.filter(t=>{let r=readTaskInputRequestId(t);return r===void 0||!e.has(r)});return a.length===t.length?{action:`noop`,view:r}:a.length>0?{action:`accepted`,view:{inputRequests:a,executor:r.executor,metadata:r.metadata,status:`input_required`,taskId:r.taskId}}:{action:`accepted`,view:{executor:r.executor,metadata:r.metadata,status:`working`,taskId:r.taskId}}}case`start-turn`:return i.taskId===r.taskId?r.executor?.childSessionId!==void 0&&r.executor.childSessionId!==i.childSessionId?{action:`rejected`,reason:`Task child session "${i.childSessionId}" does not match "${r.executor.childSessionId}".`,view:r}:r.executor?.childSessionId===i.childSessionId&&r.executor.childTurnId===i.childTurnId?{action:`noop`,view:r}:{action:`accepted`,view:{...r,executor:{...r.executor,childSessionId:i.childSessionId,childTurnId:i.childTurnId}}}:{action:`rejected`,reason:`Task turn identity "${i.taskId}" does not match "${r.taskId}".`,view:r}}}function isValidInputRequestBatch(e){if(e.length===0)return!1;let t=e.map(readTaskInputRequestId);return t.every(e=>e!==void 0&&e.length>0)&&new Set(t).size===t.length}function sameUsage(e,t){return e===void 0||t===void 0?e===t:e?.cacheReadTokens===t.cacheReadTokens&&e.cacheWriteTokens===t.cacheWriteTokens&&e.inputTokens===t.inputTokens&&e.outputTokens===t.outputTokens}export{applyTaskTransition};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentAddress, AgentIdentity } from "#harness/handles/store.js";
|
|
2
|
+
import { type JsonValue } from "#shared/json.js";
|
|
3
|
+
import type { TaskExecutorBinding } from "#shared/tool-task.js";
|
|
2
4
|
import type { SubagentAuthorizationEvent } from "#channel/types.js";
|
|
3
5
|
/**
|
|
4
6
|
* Task lifecycle contract for `experimental.tasks`.
|
|
@@ -33,10 +35,45 @@ export interface TaskMetadata {
|
|
|
33
35
|
/** Authored subagent name the parent dispatched. */
|
|
34
36
|
readonly name: string;
|
|
35
37
|
}
|
|
38
|
+
export type SubagentTaskMetadata = TaskMetadata;
|
|
39
|
+
/** Executor-neutral metadata retained by a non-subagent durable task. */
|
|
40
|
+
export interface BackgroundTaskMetadata {
|
|
41
|
+
readonly kind: string;
|
|
42
|
+
readonly name: string;
|
|
43
|
+
}
|
|
44
|
+
export type DurableTaskMetadata = BackgroundTaskMetadata | TaskMetadata;
|
|
45
|
+
export declare function createSubagentTaskMetadata(metadata: Omit<SubagentTaskMetadata, "kind" | "name"> & {
|
|
46
|
+
readonly name: string;
|
|
47
|
+
}): SubagentTaskMetadata;
|
|
48
|
+
export declare function readSubagentTaskMetadata(task: {
|
|
49
|
+
readonly executor?: TaskExecutorBinding | TaskExecutorState;
|
|
50
|
+
readonly metadata: DurableTaskMetadata;
|
|
51
|
+
}): SubagentTaskMetadata | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Durable subagent executor binding payload: the child's stable identity and
|
|
54
|
+
* private delivery address, copied from the parent's agent handle store at
|
|
55
|
+
* delegation time. Every field derives deterministically from the
|
|
56
|
+
* originating call (operation-hashed id, dispatch-chosen continuation
|
|
57
|
+
* token), so a replayed delegation produces a deep-equal binding — the
|
|
58
|
+
* equality the task run's `bind` replay check compares.
|
|
59
|
+
*/
|
|
60
|
+
export interface SubagentExecutorData {
|
|
61
|
+
readonly address: AgentAddress;
|
|
62
|
+
readonly identity: AgentIdentity;
|
|
63
|
+
}
|
|
64
|
+
export declare function createSubagentExecutorBinding(executor: SubagentExecutorData): TaskExecutorBinding;
|
|
65
|
+
export declare function readSubagentExecutor(executor: TaskExecutorBinding | TaskExecutorState | undefined): SubagentExecutorData | undefined;
|
|
66
|
+
export declare function sameTaskMetadata(left: DurableTaskMetadata, right: DurableTaskMetadata): boolean;
|
|
36
67
|
/** Private executor state retained for cancellation and address reconciliation. */
|
|
37
68
|
export interface TaskExecutorState {
|
|
69
|
+
/** Write-once executor address recorded by the `bind` command. */
|
|
70
|
+
readonly binding?: TaskExecutorBinding;
|
|
38
71
|
readonly childSessionId?: string;
|
|
39
72
|
readonly childTurnId?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Child-session verdict from the last settled turn: `parked` survived
|
|
75
|
+
* and can take another delivery, `terminal` ended with the turn.
|
|
76
|
+
*/
|
|
40
77
|
readonly lifecycle?: "parked" | "terminal";
|
|
41
78
|
}
|
|
42
79
|
/**
|
|
@@ -92,7 +129,7 @@ export declare function readTaskInputRequestId(request: TaskInputRequest): strin
|
|
|
92
129
|
/** Fields shared by every durable task view. */
|
|
93
130
|
interface TaskViewBase {
|
|
94
131
|
readonly taskId: string;
|
|
95
|
-
readonly metadata:
|
|
132
|
+
readonly metadata: DurableTaskMetadata;
|
|
96
133
|
/** Private executor state; deliberately excluded from model-visible JSON. */
|
|
97
134
|
readonly executor?: TaskExecutorState;
|
|
98
135
|
/**
|
|
@@ -140,6 +177,9 @@ export type TaskView = TaskViewBase & ({
|
|
|
140
177
|
});
|
|
141
178
|
/** Commands accepted by the durable task run's transition function. */
|
|
142
179
|
export type TaskCommand = {
|
|
180
|
+
readonly executor: TaskExecutorBinding;
|
|
181
|
+
readonly kind: "bind";
|
|
182
|
+
} | {
|
|
143
183
|
readonly kind: "complete";
|
|
144
184
|
readonly data: JsonValue;
|
|
145
185
|
readonly lifecycle?: "parked" | "terminal";
|
|
@@ -260,8 +300,10 @@ export interface TaskInboundTurnStarted {
|
|
|
260
300
|
/** Intermediate progress sent by a running child to its parent agent. */
|
|
261
301
|
export interface TaskInboundUpdate {
|
|
262
302
|
readonly callId: string;
|
|
263
|
-
|
|
264
|
-
readonly
|
|
303
|
+
/** Executor-neutral monotonic index within {@link updateEpoch}. */
|
|
304
|
+
readonly updateIndex: number;
|
|
305
|
+
/** Executor-neutral epoch id used with {@link updateIndex} for update dedupe. */
|
|
306
|
+
readonly updateEpoch: string;
|
|
265
307
|
readonly kind: "task-update";
|
|
266
308
|
readonly message: string;
|
|
267
309
|
}
|
package/dist/src/tasks/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function readTaskUsage(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=readUsageAxis(e,`cacheReadTokens`),n=readUsageAxis(e,`cacheWriteTokens`),r=readUsageAxis(e,`inputTokens`),i=readUsageAxis(e,`outputTokens`);if(!(t===void 0||n===void 0||r===void 0||i===void 0))return{cacheReadTokens:t,cacheWriteTokens:n,inputTokens:r,outputTokens:i}}function readUsageAxis(e,t){let n=Reflect.get(e,t);return typeof n==`number`&&Number.isFinite(n)&&n>=0?n:void 0}const TASK_AUTHORIZATION_REQUEST_ID_PREFIX=`task:authorization`;function taskAuthorizationRequestId(
|
|
1
|
+
import{isJsonObjectValue}from"#shared/json.js";function createSubagentTaskMetadata(e){return{...e,kind:`subagent`}}function readSubagentTaskMetadata(e){if(e.metadata.kind===`subagent`&&`agentId`in e.metadata)return e.metadata;let t=readSubagentExecutor(e.executor);if(t!==void 0)return{agentId:t.identity.id,kind:`subagent`,mode:t.address.kind===`agent/remote`?`remote`:`local`,name:t.identity.name}}function createSubagentExecutorBinding(e){let{address:t,identity:n}=e;return{data:{address:{...t},identity:{id:n.id,name:n.name,nodeId:n.nodeId}},kind:`subagent`}}function readSubagentExecutor(e){let t=e!==void 0&&`kind`in e?e:e?.binding;if(t?.kind!==`subagent`)return;let n=readAgentIdentity(t.data.identity),r=readAgentAddress(t.data.address);return n===void 0||r===void 0?void 0:{address:r,identity:n}}function readAgentIdentity(t){if(t===void 0||!isJsonObjectValue(t))return;let{id:n,name:r,nodeId:i}=t;return typeof n==`string`&&typeof r==`string`&&typeof i==`string`?{id:n,name:r,nodeId:i}:void 0}function readAgentAddress(t){if(t===void 0||!isJsonObjectValue(t))return;let{callbackBaseUrl:n,continuationToken:r,kind:i,sessionId:a,url:o}=t;if(typeof a==`string`){if(i===`agent/local`||i===`agent/self`)return typeof r==`string`?{continuationToken:r,kind:i,sessionId:a}:void 0;if(i===`agent/remote`)return typeof o==`string`&&typeof n==`string`?{callbackBaseUrl:n,kind:i,sessionId:a,url:o}:void 0}}function sameTaskMetadata(e,t){if(e.kind!==t.kind||e.name!==t.name)return!1;let n=`agentId`in e,r=`agentId`in t;return n===r&&(!n||!r||e.agentId===t.agentId&&e.mode===t.mode)}function readTaskUsage(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=readUsageAxis(e,`cacheReadTokens`),n=readUsageAxis(e,`cacheWriteTokens`),r=readUsageAxis(e,`inputTokens`),i=readUsageAxis(e,`outputTokens`);if(!(t===void 0||n===void 0||r===void 0||i===void 0))return{cacheReadTokens:t,cacheWriteTokens:n,inputTokens:r,outputTokens:i}}function readUsageAxis(e,t){let n=Reflect.get(e,t);return typeof n==`number`&&Number.isFinite(n)&&n>=0?n:void 0}const TASK_AUTHORIZATION_REQUEST_ID_PREFIX=`task:authorization`;function taskAuthorizationRequestId(e){return e.type===`approval.candidate`||e.type===`approval.settled`?`${TASK_AUTHORIZATION_REQUEST_ID_PREFIX}:${e.data.requestId}`:`${TASK_AUTHORIZATION_REQUEST_ID_PREFIX}:${e.data.attemptId??e.data.name}`}function readTaskInputRequestId(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=Reflect.get(e,`requestId`);return typeof t==`string`?t:void 0}const TASK_VIEW_STREAM_NAMESPACE=`eve.task`;function isTerminalTaskStatus(e){return e===`completed`||e===`failed`||e===`cancelled`}function isReadyTaskStatus(e){return e===`input_required`||isTerminalTaskStatus(e)}export{TASK_VIEW_STREAM_NAMESPACE,createSubagentExecutorBinding,createSubagentTaskMetadata,isReadyTaskStatus,isTerminalTaskStatus,readSubagentExecutor,readSubagentTaskMetadata,readTaskInputRequestId,readTaskUsage,sameTaskMetadata,taskAuthorizationRequestId};
|
package/docs/channels/linq.mdx
CHANGED
|
@@ -5,7 +5,7 @@ description: Connect an eve agent to iMessage and SMS through Linq.
|
|
|
5
5
|
|
|
6
6
|
Use `linqChannel` to receive and reply to iMessage and SMS conversations through Linq.
|
|
7
7
|
|
|
8
|
-
Run `eve add channel/linq` to choose Vercel Connect or portable credentials. With Vercel Connect, eve signs you in and creates or links a Vercel project when needed. Then choose whether to create a managed Linq account and line or connect an existing
|
|
8
|
+
Run `eve add channel/linq` to choose Vercel Connect or portable credentials. With Vercel Connect, eve signs you in and creates or links a Vercel project when needed. Then choose whether to create a managed Linq account and line or connect an existing account with its partner API token. eve fetches the phone numbers assigned to that account, and you select the numbers for the agent. eve configures the connector and webhook through Connect:
|
|
9
9
|
|
|
10
10
|
```ts title="agent/channels/linq.ts"
|
|
11
11
|
import { connectLinqCredentials } from "@vercel/connect/eve";
|
package/docs/getting-started.mdx
CHANGED
|
@@ -24,13 +24,7 @@ Run `eve init` with a project name:
|
|
|
24
24
|
npx eve@latest init my-agent
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
The command creates the project, installs dependencies, and initializes Git.
|
|
28
|
-
|
|
29
|
-
Pass an AI Gateway model ID or reasoning effort when you do not want the defaults:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx eve@latest init my-agent --model openai/gpt-5.6-terra --reasoning high
|
|
33
|
-
```
|
|
27
|
+
The command creates the project, installs dependencies, and initializes Git. After scaffolding, eve offers to start the development server or, if a supported coding agent is installed, to open the project in the coding agent.
|
|
34
28
|
|
|
35
29
|
To add eve to a project that already has a `package.json`, run this command from its root before you create any `agent/` files:
|
|
36
30
|
|
|
@@ -40,15 +34,23 @@ npx eve@latest init .
|
|
|
40
34
|
|
|
41
35
|
eve adds the missing `eve`, `ai`, and `zod` dependencies without changing files the project already owns.
|
|
42
36
|
|
|
37
|
+
### Customize initialization
|
|
38
|
+
|
|
39
|
+
To initialize the agent with a different AI Gateway model or reasoning effort, pass `--model` or `--reasoning`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx eve@latest init my-agent --model openai/gpt-5.6-terra --reasoning high
|
|
43
|
+
```
|
|
44
|
+
|
|
43
45
|
## Run the agent
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
Choose **Start eve dev** after scaffolding, or run this from the project root:
|
|
46
48
|
|
|
47
49
|
```bash
|
|
48
50
|
npm run dev
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
This starts an interactive session where you can send messages to your agent.
|
|
52
54
|
|
|
53
55
|
## Project layout
|
|
54
56
|
|
|
@@ -56,7 +58,7 @@ eve builds an agent by walking the filesystem under `agent/`. Each directory is
|
|
|
56
58
|
|
|
57
59
|
### Naming from paths
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
eve derives names from file paths, so you do not configure them separately.
|
|
60
62
|
|
|
61
63
|
| Path | Resolves to |
|
|
62
64
|
| ------------------------------------- | --------------------- |
|
|
@@ -65,7 +67,7 @@ Identity comes from the path. You never write a `name` or `id` field on a `defin
|
|
|
65
67
|
| `agent/skills/summarize.md` | skill `summarize` |
|
|
66
68
|
| `agent/subagents/researcher/agent.ts` | subagent `researcher` |
|
|
67
69
|
|
|
68
|
-
The root agent
|
|
70
|
+
The root agent uses its `package.json` `name`, or its app directory name if none is set. A subagent uses its directory name.
|
|
69
71
|
|
|
70
72
|
### Recommended layout
|
|
71
73
|
|
|
@@ -93,31 +95,29 @@ my-agent/
|
|
|
93
95
|
|
|
94
96
|
Evals live beside `agent/`, not inside it.
|
|
95
97
|
|
|
96
|
-
###
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| Path |
|
|
101
|
-
| ------------------------------------------------------- | ----------------------------------------- |
|
|
102
|
-
| `agent.ts` | Runtime config | Yes
|
|
103
|
-
| `instructions.md` / `instructions.ts` / `instructions/` | Base system prompt | Optional
|
|
104
|
-
| `instrumentation.ts` | Telemetry config | No
|
|
105
|
-
| `channels/` | HTTP and messaging entry points | No
|
|
106
|
-
| `connections/` | External MCP and OpenAPI services | Yes
|
|
107
|
-
| `hooks/` | Lifecycle and stream-event subscribers | Yes
|
|
108
|
-
| `skills/` | On-demand procedures and capability packs | Yes
|
|
109
|
-
| `lib/` | Shared authored helper code | Yes
|
|
110
|
-
| `sandbox.ts` or `sandbox/sandbox.ts` | The agent's single sandbox | Yes
|
|
111
|
-
| `sandbox/workspace/**` | Files seeded into the sandbox | Yes
|
|
112
|
-
| `tools/` | Typed executable integrations | Yes
|
|
113
|
-
| `schedules/` | Recurring jobs | No
|
|
114
|
-
| `subagents/` | Specialist child agents | Yes
|
|
115
|
-
|
|
116
|
-
###
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Skill package files land outside the workspace under `$HOME/.agents/skills/`, with `/workspace/skills/` as a fallback when `$HOME` is unavailable. Everything in `lib/` remains import-only source code.
|
|
98
|
+
### Agent files and directories
|
|
99
|
+
|
|
100
|
+
Each path under `agent/` has a specific purpose. Root agents can use every path below. A subagent has its own files and can use only the paths marked **Yes**.
|
|
101
|
+
|
|
102
|
+
| Path | Use | Available to subagents | Notes |
|
|
103
|
+
| ------------------------------------------------------- | ----------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
104
|
+
| `agent.ts` | Runtime config | Yes | Model, model options, compaction, build, and experimental settings. See [Agents](./agent-config). |
|
|
105
|
+
| `instructions.md` / `instructions.ts` / `instructions/` | Base system prompt | Optional | A flat file or directory of `.md` and `.ts` files. Static sources compose at build time. Dynamic sources resolve at runtime. Required on the root, optional on subagents. |
|
|
106
|
+
| `instrumentation.ts` | Telemetry config | No | OTel exporter and AI SDK span settings, auto-discovered and run before agent code. Root-only. |
|
|
107
|
+
| `channels/` | HTTP and messaging entry points | No | Root-only. |
|
|
108
|
+
| `connections/` | External MCP and OpenAPI services | Yes | One connection per file; its name comes from the filename. |
|
|
109
|
+
| `hooks/` | Lifecycle and stream-event subscribers | Yes | Module-backed only. Recursive directories are supported. |
|
|
110
|
+
| `skills/` | On-demand procedures and capability packs | Yes | Flat markdown, module-backed skills, or packaged skills. Runtime files are seeded under `$HOME/.agents/skills/`, with `/workspace/skills/` as a fallback. |
|
|
111
|
+
| `lib/` | Shared authored helper code | Yes | Import-only; not mounted into the workspace. |
|
|
112
|
+
| `sandbox.ts` or `sandbox/sandbox.ts` | The agent's single sandbox | Yes | Use `sandbox.ts` for a definition-only override; use `sandbox/sandbox.ts` with `sandbox/workspace/**` to also seed files. The framework default applies when neither is authored. |
|
|
113
|
+
| `sandbox/workspace/**` | Files seeded into the sandbox | Yes | Mirrored into `/workspace/` when a session starts. |
|
|
114
|
+
| `tools/` | Typed executable integrations | Yes | Module-backed only. |
|
|
115
|
+
| `schedules/` | Recurring jobs | No | Each schedule is a default-exported `defineSchedule` module or a markdown prompt with `cron` frontmatter. Recursive nesting is supported. Root-only. |
|
|
116
|
+
| `subagents/` | Specialist child agents | Yes | Each child is a local package under `subagents/<id>/`. Nested subagents are supported. |
|
|
117
|
+
|
|
118
|
+
### Files available in the sandbox
|
|
119
|
+
|
|
120
|
+
Files under `agent/` define your agent; only files in `agent/sandbox/workspace/` are copied to `/workspace/` when a session starts.
|
|
121
121
|
|
|
122
122
|
### Local subagents
|
|
123
123
|
|
|
@@ -223,7 +223,7 @@ Keep secret values (`ROUTE_AUTH_BASIC_PASSWORD`, signing keys) in environment va
|
|
|
223
223
|
|
|
224
224
|
## Accepting forwarded identity from another deployment
|
|
225
225
|
|
|
226
|
-
A `defineRemoteAgent({ forwardPrincipal: true })` caller (see [Remote agents](./remote-agents#forwarding-the-caller-identity)) asserts its end user's principal on
|
|
226
|
+
A `defineRemoteAgent({ forwardPrincipal: true })` caller (see [Remote agents](./remote-agents#forwarding-the-caller-identity)) asserts its end user's principal on create and continuation requests as a `forwardedPrincipal` body field. By default every such assertion is rejected with `403` — accepting someone else's word for who the user is requires naming exactly which forwarders you trust. Do that with `trustedForwarders` on `eveChannel`:
|
|
227
227
|
|
|
228
228
|
```ts title="agent/channels/eve.ts"
|
|
229
229
|
import { eveChannel } from "eve/channels/eve";
|
|
@@ -239,7 +239,11 @@ export default eveChannel({
|
|
|
239
239
|
|
|
240
240
|
The predicate authorizes the _forwarder_ (the verified route-auth principal — who is asserting), not the forwarded principal (what is asserted). Match it precisely: a permissive predicate like `() => true` lets any caller that passes route auth assert any principal, including preview deployments of your own project when `vercelOidc()` is in the walk. `trustedForwarders` exists only on your authored channel — the framework default channel never accepts a forwarded principal, so a receiving deployment must author `agent/channels/eve.ts`.
|
|
241
241
|
|
|
242
|
-
When the predicate accepts
|
|
242
|
+
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. The forwarder is recorded on accepted contexts as the `eve:forwarded-by` attribute (always overwritten by the receiver, so a forwarder cannot falsify it). 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.
|
|
243
|
+
|
|
244
|
+
> ⚠️ Both deployments must support continuation forwarding before you resume persistent remote sessions. A create-only receiver rejects a forwarded continuation with HTTP 400; the sender does not fall back to service authority. See [Forwarding the caller identity](./remote-agents#forwarding-the-caller-identity) for the upgrade behavior.
|
|
245
|
+
|
|
246
|
+
Persistent sessions do not preserve caller authority between turns. Every accepted follow-up replaces `auth.current`, including replacing it with no authenticated caller on internal local delivery; per-user connection lookup is then keyed from that current principal. This prevents a later caller from resolving a prior caller's OAuth grant. It does not hide the persistent session's conversation history or artifacts from a caller who is otherwise allowed to continue that session; session ownership remains an application policy.
|
|
243
247
|
|
|
244
248
|
## What reaches `ctx.session.auth`
|
|
245
249
|
|
|
@@ -132,7 +132,7 @@ approval checks.
|
|
|
132
132
|
|
|
133
133
|
## Dynamic tools
|
|
134
134
|
|
|
135
|
-
Pass `defineDynamic` an `events` object whose handlers return either a single `defineTool(...)`, a `Record<string, defineTool(...)>`, or `null` for no tools. Wrap every entry in `defineTool()`.
|
|
135
|
+
Pass `defineDynamic` an `events` object whose handlers return either a single `defineTool(...)`, a `Record<string, defineTool(...)>`, or `null` for no tools. Wrap every entry in `defineTool()`. eve records durable descriptors for `execute`, approval request and response policies, and `toModelOutput`, so a parked call can reconstruct the same callbacks in a fresh process.
|
|
136
136
|
|
|
137
137
|
Dynamic tool executors receive the same `ToolContext` as static authored tools, including inline provider auth through `ctx.getToken(provider)` and `ctx.requireAuth(provider)`.
|
|
138
138
|
|
|
@@ -160,11 +160,13 @@ export default defineDynamic({
|
|
|
160
160
|
});
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
###
|
|
163
|
+
### Author replayable callbacks
|
|
164
164
|
|
|
165
|
-
Write
|
|
165
|
+
Write callback properties as inline function expressions, arrows, method shorthand, or module-level function references. eve transforms authored modules that import `defineTool`, including helper modules outside `agent/tools/`, and stores each callback's referenced closure values independently.
|
|
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
|
+
|
|
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, and replay never reruns the current resolver to recover one.
|
|
168
170
|
|
|
169
171
|
### Naming
|
|
170
172
|
|
|
@@ -181,13 +183,13 @@ A dynamic tool or skill whose name matches an **authored** one **overrides** it
|
|
|
181
183
|
|
|
182
184
|
### Events
|
|
183
185
|
|
|
184
|
-
| Event | Resolver runs
|
|
185
|
-
| ----------------- |
|
|
186
|
-
| `session.started` | At session start;
|
|
187
|
-
| `turn.started` | Once per turn
|
|
188
|
-
| `step.started` | Before each model call
|
|
186
|
+
| Event | Resolver runs | Tools available for |
|
|
187
|
+
| ----------------- | ----------------------------------------------------- | ------------------------------- |
|
|
188
|
+
| `session.started` | At session start; may be redelivered during recovery¹ | Every model call in the session |
|
|
189
|
+
| `turn.started` | Once per turn | Every model call in the turn |
|
|
190
|
+
| `step.started` | Before each model call | That model call |
|
|
189
191
|
|
|
190
|
-
¹
|
|
192
|
+
¹ Workflow recovery can redeliver a resolver event, so keep resolvers idempotent. Replaying a parked callback does not depend on running the resolver again.
|
|
191
193
|
|
|
192
194
|
### Execution order
|
|
193
195
|
|
|
@@ -114,9 +114,17 @@ export default defineRemoteAgent({
|
|
|
114
114
|
});
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
The create-session request
|
|
117
|
+
The create-session request carries the parent turn's `session.auth.current` and `session.auth.initiator` as a `forwardedPrincipal` body field (`initiator` is optional on the wire; when absent, the receiver seeds both from `current`). Every continuation carries only that turn's `session.auth.current`; the remote session keeps its original `auth.initiator`. Only principal metadata crosses the wire — never tokens or credentials. The receiving deployment resolves its own per-user credentials through its own connections.
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
This makes caller authority turn-scoped even when the remote child session is persistent. If Alice starts the child and Bob later continues it, the follow-up runs with Bob as `auth.current`, not Alice. If the parent turn's auth is `null`, a local child clears `auth.current`, while a remote child uses the freshly verified transport principal; neither inherits Alice. eve's in-step bearer cache is also keyed by the resolved principal and is not serialized across steps. The external authorization provider may preserve each user's server-side OAuth grant, but a later turn can resolve only the grant belonging to its own `auth.current` principal.
|
|
120
|
+
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
Forwarding is explicit on both sides. The receiver names which forwarders it trusts with `eveChannel({ trustedForwarders })` (see [Auth & route protection](./auth-and-route-protection#accepting-forwarded-identity-from-another-deployment)); a receiver that refuses the forwarder — or has no `trustedForwarders` at all — rejects with a 403 and the dispatch fails.
|
|
124
|
+
|
|
125
|
+
> ⚠️ **Upgrade both deployments before resuming persistent remote sessions.** A sender with continuation forwarding includes `forwardedPrincipal` on each authenticated follow-up. A receiver that supports forwarding only on session creation rejects that continuation with HTTP 400. eve does not retry without the field because that would run the follow-up as the transport service principal and silently change caller authority. The parent retains the child handle after this failure, so you can retry the same session after upgrading the receiver.
|
|
126
|
+
|
|
127
|
+
A receiver on an eve version that predates all principal forwarding may instead drop the unknown field and run the session as your app's service identity; per-user connections there fail with `principal_required`. On remote requests where the dispatching turn has no auth, the field is omitted and the call proceeds on transport trust alone.
|
|
120
128
|
|
|
121
129
|
## How remote dispatch and callbacks work
|
|
122
130
|
|
package/docs/tools/overview.mdx
CHANGED
|
@@ -56,6 +56,25 @@ history or `toModelOutput`; only the final yield does. Treat snapshots as
|
|
|
56
56
|
last-write-wins by tool call id, not append-only progress. The durable runtime
|
|
57
57
|
can retry a step and replay overlapping snapshots.
|
|
58
58
|
|
|
59
|
+
### Experimental background execution
|
|
60
|
+
|
|
61
|
+
`defineTool({ execution: "background" })` receives a third `task` argument. Returning a normal
|
|
62
|
+
value completes the durable task with that value. Returning `task.delegated({ executor, receipt })`
|
|
63
|
+
returns a `working` receipt immediately while an external executor continues the task.
|
|
64
|
+
The root agent must enable `experimental.tasks`; eve rejects background tools at build time otherwise.
|
|
65
|
+
|
|
66
|
+
This contract currently supports framework-owned task executors, including local and remote
|
|
67
|
+
subagents when `experimental.tasks` is enabled. After delegating, an in-process executor reports
|
|
68
|
+
progress with `task.send({ kind: "update", message })` and the terminal result with
|
|
69
|
+
`task.send({ kind: "complete", data })` (or `fail` / `cancel`). `send` is not restart-safe — an
|
|
70
|
+
in-memory callback dies with the process — so the cross-process executor wire remains
|
|
71
|
+
framework-owned and is not yet a stable authored-tool API.
|
|
72
|
+
|
|
73
|
+
Each task-triggered parent turn includes runtime-authored state for tasks started by the same
|
|
74
|
+
parent turn. The model is instructed to keep related intermediate results silent while that state
|
|
75
|
+
contains pending tasks. Once every related task is terminal, the state includes their outputs so
|
|
76
|
+
the model can combine the useful results.
|
|
77
|
+
|
|
59
78
|
### The `ctx` parameter
|
|
60
79
|
|
|
61
80
|
`execute` gets a `ctx` carrying the runtime accessors:
|