eve 0.13.3 → 0.13.5
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 +21 -0
- package/dist/src/channel/schedule-auth.d.ts +7 -0
- package/dist/src/channel/schedule-auth.js +1 -0
- package/dist/src/channel/schedule.d.ts +2 -6
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/chunks/use-eve-agent-BjAM8_a3.js +1499 -0
- package/dist/src/chunks/use-eve-agent-_dbX0ASK.js +1529 -0
- package/dist/src/client/agent-info-schema.d.ts +1 -1
- package/dist/src/client/agent-info-schema.js +1 -1
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +3 -3
- package/dist/src/compiled/@ai-sdk/anthropic/index.js +2 -2
- package/dist/src/compiled/@ai-sdk/google/index.js +6 -6
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/openai/index.js +2 -2
- package/dist/src/compiled/@workflow/core/create-hook.d.ts +3 -1
- package/dist/src/compiled/@workflow/core/events-consumer.d.ts +9 -0
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/logger.d.ts +1 -0
- package/dist/src/compiled/@workflow/core/private.d.ts +35 -2
- package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +73 -0
- package/dist/src/compiled/@workflow/core/runtime/get-port-lazy.d.ts +15 -0
- package/dist/src/compiled/@workflow/core/runtime/run-id-time.d.ts +10 -0
- package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +61 -1
- package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +38 -2
- package/dist/src/compiled/@workflow/core/runtime.d.ts +1 -0
- package/dist/src/compiled/@workflow/core/runtime.js +28 -28
- package/dist/src/compiled/@workflow/core/source-map.d.ts +5 -0
- package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +27 -0
- package/dist/src/compiled/@workflow/core/step-hydration-cache.d.ts +148 -0
- package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +28 -0
- package/dist/src/compiled/@workflow/core/telemetry.d.ts +9 -6
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/vm/script-cache.d.ts +28 -0
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/world/events.d.ts +78 -3
- package/dist/src/compiled/@workflow/world/index.d.ts +1 -1
- package/dist/src/compiled/@workflow/world/spec-version.d.ts +11 -1
- package/dist/src/compiled/_chunks/{workflow/core-CXJbIkCL.js → client/core-Bm8azZA6.js} +5 -5
- package/dist/src/compiled/_chunks/workflow/{attribute-changes-Bi5DLT8S.js → attribute-changes-DUxG-Gic.js} +3 -3
- package/dist/src/compiled/_chunks/workflow/dist-C9PV_vnE.js +77 -0
- package/dist/src/compiled/_chunks/workflow/resume-hook-CUCPW67D.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{run-XM8dTRAo.js → run-CVlF84yI.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/sleep-Dxuzj5to.js +1 -0
- package/dist/src/compiled/zod/index.js +1 -1
- package/dist/src/compiled/zod-validation-error/index.js +1 -1
- package/dist/src/execution/hook-ownership.d.ts +7 -0
- package/dist/src/execution/hook-ownership.js +1 -0
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/action-result-helpers.d.ts +2 -3
- package/dist/src/harness/action-result-helpers.js +1 -1
- package/dist/src/harness/authorization.d.ts +1 -0
- package/dist/src/harness/authorization.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/provider-tools.d.ts +4 -27
- package/dist/src/harness/provider-tools.js +1 -1
- package/dist/src/harness/step-hooks.d.ts +0 -13
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tool-output-serialization.d.ts +17 -0
- package/dist/src/harness/tool-output-serialization.js +1 -0
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/optional-package-install.js +15 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-core-shim.d.ts +10 -8
- package/dist/src/public/channels/slack/defaults.js +1 -1
- package/dist/src/runtime/framework-tools/web-search.d.ts +2 -2
- package/dist/src/runtime/framework-tools/web-search.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/shared/empty-delivery.d.ts +3 -0
- package/dist/src/shared/empty-delivery.js +1 -0
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/custom.mdx +1 -1
- package/docs/channels/eve.mdx +1 -1
- package/docs/concepts/execution-model-and-durability.md +2 -0
- package/docs/guides/client/continuations.mdx +4 -0
- package/docs/guides/client/streaming.mdx +6 -0
- package/docs/guides/frontend/overview.mdx +28 -8
- package/docs/schedules.mdx +5 -3
- package/docs/tools/overview.mdx +2 -0
- package/package.json +4 -4
- package/dist/src/chunks/use-eve-agent-B18LYpfZ.js +0 -5765
- package/dist/src/chunks/use-eve-agent-BPI1nbo5.js +0 -5795
- package/dist/src/compiled/_chunks/workflow/coerce-B-Ro4Nfe.js +0 -1
- package/dist/src/compiled/_chunks/workflow/compat-DLpWymPP.js +0 -1
- package/dist/src/compiled/_chunks/workflow/dist-DTchiX0N.js +0 -14
- package/dist/src/compiled/_chunks/workflow/resume-hook-CKTw-lb5.js +0 -1
- package/dist/src/compiled/_chunks/workflow/schemas-iG9Z4s4o.js +0 -1
- package/dist/src/compiled/_chunks/workflow/sleep-DPjVkRY-.js +0 -1
|
@@ -0,0 +1,1499 @@
|
|
|
1
|
+
import { computed, onScopeDispose, shallowRef } from "vue";
|
|
2
|
+
import { z } from "#compiled/zod/index.js";
|
|
3
|
+
|
|
4
|
+
//#region src/protocol/routes.ts
|
|
5
|
+
const EVE_ROUTE_PREFIX = "/eve/v1";
|
|
6
|
+
const EVE_HEALTH_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/health`;
|
|
7
|
+
const EVE_INFO_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/info`;
|
|
8
|
+
const EVE_CREATE_SESSION_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/session`;
|
|
9
|
+
const EVE_CONTINUE_SESSION_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId`;
|
|
10
|
+
const EVE_MESSAGE_STREAM_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId/stream`;
|
|
11
|
+
const EVE_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/dev/schedules/:scheduleId`;
|
|
12
|
+
const EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/dev/runtime-artifacts`;
|
|
13
|
+
const EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH = `${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/rebuild`;
|
|
14
|
+
const EVE_CONNECTION_CALLBACK_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/connections/:name/callback/:token`;
|
|
15
|
+
const EVE_CALLBACK_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/callback/:token`;
|
|
16
|
+
function createEveMessageStreamRoutePath(sessionId) {
|
|
17
|
+
return `${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(sessionId)}/stream`;
|
|
18
|
+
}
|
|
19
|
+
function createEveContinueSessionRoutePath(sessionId) {
|
|
20
|
+
return `${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(sessionId)}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/client/agent-info-schema.ts
|
|
25
|
+
const source = z.object({
|
|
26
|
+
exportName: z.string().optional(),
|
|
27
|
+
logicalPath: z.string(),
|
|
28
|
+
sourceId: z.string().optional(),
|
|
29
|
+
sourceKind: z.string()
|
|
30
|
+
});
|
|
31
|
+
const entry = source.extend({ name: z.string() });
|
|
32
|
+
const modelRouting = z.discriminatedUnion("kind", [z.object({
|
|
33
|
+
kind: z.literal("gateway"),
|
|
34
|
+
target: z.string(),
|
|
35
|
+
byok: z.string().optional()
|
|
36
|
+
}), z.object({
|
|
37
|
+
kind: z.literal("external"),
|
|
38
|
+
provider: z.string()
|
|
39
|
+
})]);
|
|
40
|
+
const modelEndpoint = z.union([
|
|
41
|
+
z.object({
|
|
42
|
+
kind: z.literal("external"),
|
|
43
|
+
provider: z.string()
|
|
44
|
+
}),
|
|
45
|
+
z.object({
|
|
46
|
+
kind: z.literal("gateway"),
|
|
47
|
+
connected: z.literal(true),
|
|
48
|
+
credential: z.enum(["api-key", "oidc"])
|
|
49
|
+
}),
|
|
50
|
+
z.object({
|
|
51
|
+
kind: z.literal("gateway"),
|
|
52
|
+
connected: z.literal(false)
|
|
53
|
+
})
|
|
54
|
+
]);
|
|
55
|
+
const tool = entry.extend({
|
|
56
|
+
description: z.string(),
|
|
57
|
+
hasAuth: z.boolean(),
|
|
58
|
+
hasExecute: z.boolean(),
|
|
59
|
+
hasModelOutputProjection: z.boolean(),
|
|
60
|
+
hasOutputSchema: z.boolean(),
|
|
61
|
+
inputSchema: z.unknown(),
|
|
62
|
+
origin: z.enum(["authored", "framework"]),
|
|
63
|
+
outputSchema: z.unknown().optional(),
|
|
64
|
+
replacesFrameworkTool: z.boolean(),
|
|
65
|
+
requiresApproval: z.boolean()
|
|
66
|
+
});
|
|
67
|
+
const frameworkTool = tool.extend({
|
|
68
|
+
disabledByAuthor: z.boolean(),
|
|
69
|
+
replacedByAuthoredTool: z.boolean(),
|
|
70
|
+
status: z.enum([
|
|
71
|
+
"active",
|
|
72
|
+
"disabled",
|
|
73
|
+
"replaced"
|
|
74
|
+
])
|
|
75
|
+
});
|
|
76
|
+
const dynamicResolver = source.extend({
|
|
77
|
+
eventNames: z.array(z.string()),
|
|
78
|
+
origin: z.enum(["authored", "framework"]),
|
|
79
|
+
slug: z.string()
|
|
80
|
+
});
|
|
81
|
+
const skill = entry.extend({
|
|
82
|
+
description: z.string(),
|
|
83
|
+
license: z.string().optional(),
|
|
84
|
+
markdown: z.string(),
|
|
85
|
+
metadata: z.record(z.string(), z.string()).optional()
|
|
86
|
+
});
|
|
87
|
+
const instructions = entry.extend({ markdown: z.string() });
|
|
88
|
+
const schedule = entry.extend({
|
|
89
|
+
cron: z.string(),
|
|
90
|
+
hasRun: z.boolean(),
|
|
91
|
+
markdown: z.string().optional()
|
|
92
|
+
});
|
|
93
|
+
const subagent = entry.extend({
|
|
94
|
+
description: z.string(),
|
|
95
|
+
entryPath: z.string(),
|
|
96
|
+
nodeId: z.string(),
|
|
97
|
+
rootPath: z.string(),
|
|
98
|
+
summary: z.object({
|
|
99
|
+
channels: z.number(),
|
|
100
|
+
connections: z.number(),
|
|
101
|
+
hooks: z.number(),
|
|
102
|
+
instructions: z.boolean(),
|
|
103
|
+
schedules: z.number(),
|
|
104
|
+
skills: z.number(),
|
|
105
|
+
tools: z.number()
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
const channel = entry.extend({
|
|
109
|
+
adapterKind: z.string().optional(),
|
|
110
|
+
method: z.string(),
|
|
111
|
+
origin: z.enum(["authored", "framework"]),
|
|
112
|
+
urlPath: z.string()
|
|
113
|
+
});
|
|
114
|
+
const frameworkChannel = channel.extend({
|
|
115
|
+
disabledByAuthor: z.boolean(),
|
|
116
|
+
replacedByAuthoredChannel: z.boolean(),
|
|
117
|
+
status: z.enum([
|
|
118
|
+
"active",
|
|
119
|
+
"disabled",
|
|
120
|
+
"replaced"
|
|
121
|
+
])
|
|
122
|
+
});
|
|
123
|
+
const connection = source.extend({
|
|
124
|
+
connectionName: z.string(),
|
|
125
|
+
description: z.string(),
|
|
126
|
+
hasApproval: z.boolean(),
|
|
127
|
+
hasAuthorization: z.boolean(),
|
|
128
|
+
hasHeaders: z.boolean(),
|
|
129
|
+
protocol: z.string(),
|
|
130
|
+
toolFilter: z.unknown().optional(),
|
|
131
|
+
url: z.string()
|
|
132
|
+
});
|
|
133
|
+
const hook = source.extend({
|
|
134
|
+
eventNames: z.array(z.string()),
|
|
135
|
+
slug: z.string()
|
|
136
|
+
});
|
|
137
|
+
const sandbox = source.extend({
|
|
138
|
+
backendKind: z.string().optional(),
|
|
139
|
+
description: z.string().optional(),
|
|
140
|
+
hasBootstrap: z.boolean(),
|
|
141
|
+
hasOnSession: z.boolean(),
|
|
142
|
+
revalidationKey: z.string().optional(),
|
|
143
|
+
sourceHash: z.string().optional()
|
|
144
|
+
});
|
|
145
|
+
const AgentInfoResultSchema = z.object({
|
|
146
|
+
agent: z.object({
|
|
147
|
+
agentRoot: z.string(),
|
|
148
|
+
appRoot: z.string(),
|
|
149
|
+
configSource: source.optional(),
|
|
150
|
+
description: z.string().optional(),
|
|
151
|
+
model: z.object({
|
|
152
|
+
contextWindowTokens: z.number().optional(),
|
|
153
|
+
id: z.string(),
|
|
154
|
+
providerOptions: z.unknown().optional(),
|
|
155
|
+
source: source.optional(),
|
|
156
|
+
routing: modelRouting.optional(),
|
|
157
|
+
endpoint: modelEndpoint.optional()
|
|
158
|
+
}),
|
|
159
|
+
name: z.string(),
|
|
160
|
+
outputSchema: z.unknown().optional()
|
|
161
|
+
}),
|
|
162
|
+
capabilities: z.object({ devRoutes: z.boolean() }),
|
|
163
|
+
channels: z.object({
|
|
164
|
+
authored: z.array(channel),
|
|
165
|
+
available: z.array(channel),
|
|
166
|
+
disabledFramework: z.array(z.string()),
|
|
167
|
+
framework: z.array(frameworkChannel)
|
|
168
|
+
}),
|
|
169
|
+
connections: z.array(connection),
|
|
170
|
+
diagnostics: z.object({
|
|
171
|
+
discoveryErrors: z.number(),
|
|
172
|
+
discoveryWarnings: z.number()
|
|
173
|
+
}),
|
|
174
|
+
hooks: z.array(hook),
|
|
175
|
+
instructions: z.object({
|
|
176
|
+
dynamic: z.array(dynamicResolver),
|
|
177
|
+
static: instructions.nullable()
|
|
178
|
+
}),
|
|
179
|
+
kind: z.literal("eve-agent-info"),
|
|
180
|
+
mode: z.enum(["development", "production"]),
|
|
181
|
+
sandbox: sandbox.nullable(),
|
|
182
|
+
schedules: z.array(schedule),
|
|
183
|
+
skills: z.object({
|
|
184
|
+
dynamic: z.array(dynamicResolver),
|
|
185
|
+
static: z.array(skill)
|
|
186
|
+
}),
|
|
187
|
+
subagents: z.object({
|
|
188
|
+
local: z.array(subagent),
|
|
189
|
+
total: z.number()
|
|
190
|
+
}),
|
|
191
|
+
tools: z.object({
|
|
192
|
+
authored: z.array(tool),
|
|
193
|
+
available: z.array(tool),
|
|
194
|
+
disabledFramework: z.array(z.string()),
|
|
195
|
+
dynamic: z.array(dynamicResolver),
|
|
196
|
+
framework: z.array(frameworkTool),
|
|
197
|
+
reserved: z.array(z.string())
|
|
198
|
+
}),
|
|
199
|
+
version: z.literal(1),
|
|
200
|
+
workflow: z.object({
|
|
201
|
+
enabled: z.boolean(),
|
|
202
|
+
toolName: z.string()
|
|
203
|
+
}),
|
|
204
|
+
workspace: z.object({
|
|
205
|
+
resourceRoot: z.unknown(),
|
|
206
|
+
rootEntries: z.array(z.string())
|
|
207
|
+
})
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/shared/guards.ts
|
|
212
|
+
function isObject(value) {
|
|
213
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/client/client-error.ts
|
|
218
|
+
var ClientError = class extends Error {
|
|
219
|
+
status;
|
|
220
|
+
body;
|
|
221
|
+
constructor(status, body) {
|
|
222
|
+
let message = body || `Server returned ${status}.`;
|
|
223
|
+
try {
|
|
224
|
+
const parsed = JSON.parse(body);
|
|
225
|
+
if (isObject(parsed) && typeof parsed.error === "string") message = parsed.error;
|
|
226
|
+
} catch {}
|
|
227
|
+
super(message);
|
|
228
|
+
this.name = "ClientError";
|
|
229
|
+
this.status = status;
|
|
230
|
+
this.body = body;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/protocol/message.ts
|
|
236
|
+
const EVE_SESSION_ID_HEADER = "x-eve-session-id";
|
|
237
|
+
const textEncoder = new TextEncoder();
|
|
238
|
+
function isCurrentTurnBoundaryEvent(event) {
|
|
239
|
+
return event.type === "session.completed" || event.type === "session.failed" || event.type === "session.waiting";
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/shared/json.ts
|
|
244
|
+
const INVALID_JSON_VALUE_CANDIDATE = Symbol("invalid-json-value-candidate");
|
|
245
|
+
const JSON_VALUE_ERROR_MESSAGE = "Expected a JSON-serializable value.";
|
|
246
|
+
const JSON_OBJECT_ERROR_MESSAGE = "Expected a JSON-serializable object.";
|
|
247
|
+
function parseJsonValue(value) {
|
|
248
|
+
const normalized = normalizeJsonValueCandidate(value);
|
|
249
|
+
if (normalized === INVALID_JSON_VALUE_CANDIDATE) throw new TypeError(JSON_VALUE_ERROR_MESSAGE);
|
|
250
|
+
return normalized;
|
|
251
|
+
}
|
|
252
|
+
function parseJsonObject(value) {
|
|
253
|
+
const normalized = parseJsonValue(value);
|
|
254
|
+
if (!isJsonObjectValue(normalized)) throw new TypeError(JSON_OBJECT_ERROR_MESSAGE);
|
|
255
|
+
return normalized;
|
|
256
|
+
}
|
|
257
|
+
function normalizeJsonValueCandidate(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
258
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") return value;
|
|
259
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : INVALID_JSON_VALUE_CANDIDATE;
|
|
260
|
+
if (Array.isArray(value)) {
|
|
261
|
+
const normalizedItems = [];
|
|
262
|
+
for (const item of value) {
|
|
263
|
+
const normalizedItem = normalizeJsonValueCandidate(item, seen);
|
|
264
|
+
if (normalizedItem === INVALID_JSON_VALUE_CANDIDATE) return INVALID_JSON_VALUE_CANDIDATE;
|
|
265
|
+
normalizedItems.push(normalizedItem);
|
|
266
|
+
}
|
|
267
|
+
return normalizedItems;
|
|
268
|
+
}
|
|
269
|
+
if (typeof value !== "object" || value === void 0) return INVALID_JSON_VALUE_CANDIDATE;
|
|
270
|
+
if (!isPlainObject(value)) return INVALID_JSON_VALUE_CANDIDATE;
|
|
271
|
+
if (seen.has(value)) return INVALID_JSON_VALUE_CANDIDATE;
|
|
272
|
+
seen.add(value);
|
|
273
|
+
const normalized = {};
|
|
274
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
275
|
+
if (entry === void 0) continue;
|
|
276
|
+
const normalizedEntry = normalizeJsonValueCandidate(entry, seen);
|
|
277
|
+
if (normalizedEntry === INVALID_JSON_VALUE_CANDIDATE) return INVALID_JSON_VALUE_CANDIDATE;
|
|
278
|
+
normalized[key] = normalizedEntry;
|
|
279
|
+
}
|
|
280
|
+
seen.delete(value);
|
|
281
|
+
return normalized;
|
|
282
|
+
}
|
|
283
|
+
function isJsonObjectValue(value) {
|
|
284
|
+
return value !== null && !Array.isArray(value) && typeof value === "object";
|
|
285
|
+
}
|
|
286
|
+
function isPlainObject(value) {
|
|
287
|
+
const prototype = Object.getPrototypeOf(value);
|
|
288
|
+
return prototype === null || prototype === Object.prototype;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region src/shared/json-schema.ts
|
|
293
|
+
const STANDARD_JSON_SCHEMA_TARGET = "draft-07";
|
|
294
|
+
function normalizeJsonSchemaDefinition(value, direction = "input") {
|
|
295
|
+
if (isStandardSchema(value)) return parseJsonObject(value["~standard"].jsonSchema[direction]({ target: STANDARD_JSON_SCHEMA_TARGET }));
|
|
296
|
+
return parseJsonObject(value);
|
|
297
|
+
}
|
|
298
|
+
function isStandardSchema(value) {
|
|
299
|
+
return value !== null && typeof value === "object" && "~standard" in value;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/client/output-schema.ts
|
|
304
|
+
function normalizeOutputSchemaForRequest(schema) {
|
|
305
|
+
return schema === void 0 ? void 0 : normalizeJsonSchemaDefinition(schema, "output");
|
|
306
|
+
}
|
|
307
|
+
function extractCompletedResult(events) {
|
|
308
|
+
let result;
|
|
309
|
+
for (const event of events) if (isResultCompletedEvent(event)) result = event.data.result;
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
function isResultCompletedEvent(event) {
|
|
313
|
+
return event.type === "result.completed";
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/client/session-utils.ts
|
|
318
|
+
function createInitialSessionState() {
|
|
319
|
+
return { streamIndex: 0 };
|
|
320
|
+
}
|
|
321
|
+
function advanceSession(input) {
|
|
322
|
+
const boundaryEvent = findBoundaryEvent(input.events);
|
|
323
|
+
const streamIndex = input.session.streamIndex + input.events.length;
|
|
324
|
+
if (boundaryEvent?.type === "session.waiting" || input.preserveCompletedSessions === true && boundaryEvent?.type === "session.completed") return {
|
|
325
|
+
continuationToken: input.continuationToken ?? input.session.continuationToken,
|
|
326
|
+
sessionId: input.sessionId,
|
|
327
|
+
streamIndex
|
|
328
|
+
};
|
|
329
|
+
return createInitialSessionState();
|
|
330
|
+
}
|
|
331
|
+
function extractCompletedMessage(events) {
|
|
332
|
+
let lastMessage;
|
|
333
|
+
for (const event of events) if (isFinalMessageCompleted(event)) lastMessage = event.data.message ?? void 0;
|
|
334
|
+
return lastMessage;
|
|
335
|
+
}
|
|
336
|
+
function deriveResultStatus(events) {
|
|
337
|
+
const boundary = findBoundaryEvent(events);
|
|
338
|
+
if (boundary?.type === "session.waiting") return "waiting";
|
|
339
|
+
if (boundary?.type === "session.failed") return "failed";
|
|
340
|
+
return "completed";
|
|
341
|
+
}
|
|
342
|
+
function extractInputRequests(events) {
|
|
343
|
+
const requests = [];
|
|
344
|
+
for (const event of events) if (event.type === "input.requested") requests.push(...event.data.requests);
|
|
345
|
+
return requests;
|
|
346
|
+
}
|
|
347
|
+
function findBoundaryEvent(events) {
|
|
348
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
349
|
+
const event = events[i];
|
|
350
|
+
if (event !== void 0 && isCurrentTurnBoundaryEvent(event)) return event;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function isFinalMessageCompleted(event) {
|
|
354
|
+
return event.type === "message.completed" && event.data.finishReason !== "tool-calls";
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/client/message-response.ts
|
|
359
|
+
var MessageResponse = class {
|
|
360
|
+
continuationToken;
|
|
361
|
+
sessionId;
|
|
362
|
+
#consumed = false;
|
|
363
|
+
#createStream;
|
|
364
|
+
constructor(input) {
|
|
365
|
+
this.continuationToken = input.continuationToken;
|
|
366
|
+
this.sessionId = input.sessionId;
|
|
367
|
+
this.#createStream = input.createStream;
|
|
368
|
+
}
|
|
369
|
+
async result() {
|
|
370
|
+
const events = [];
|
|
371
|
+
for await (const event of this) events.push(event);
|
|
372
|
+
return {
|
|
373
|
+
data: extractCompletedResult(events),
|
|
374
|
+
events,
|
|
375
|
+
inputRequests: extractInputRequests(events),
|
|
376
|
+
message: extractCompletedMessage(events),
|
|
377
|
+
sessionId: this.sessionId,
|
|
378
|
+
status: deriveResultStatus(events)
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
[Symbol.asyncIterator]() {
|
|
382
|
+
if (this.#consumed) throw new Error("MessageResponse has already been consumed.");
|
|
383
|
+
this.#consumed = true;
|
|
384
|
+
return this.#createStream();
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region src/client/ndjson.ts
|
|
390
|
+
function isStreamDisconnectError(error) {
|
|
391
|
+
if (error instanceof DOMException) return error.name === "AbortError";
|
|
392
|
+
if (!(error instanceof Error)) return false;
|
|
393
|
+
const errorCode = "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
394
|
+
return error.name === "AbortError" || error.message === "terminated" || errorCode === "UND_ERR_SOCKET" || /abort|cancel|disconnect|premature close|socket|terminated/i.test(error.message);
|
|
395
|
+
}
|
|
396
|
+
async function* readNdjsonStream(body) {
|
|
397
|
+
const reader = body.getReader();
|
|
398
|
+
const decoder = new TextDecoder();
|
|
399
|
+
let buffer = "";
|
|
400
|
+
try {
|
|
401
|
+
while (true) {
|
|
402
|
+
const result = await reader.read();
|
|
403
|
+
if (result.done) {
|
|
404
|
+
buffer += decoder.decode();
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
if (result.value) buffer += decoder.decode(result.value, { stream: true });
|
|
408
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
409
|
+
while (newlineIndex !== -1) {
|
|
410
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
411
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
412
|
+
if (line.length > 0) yield JSON.parse(line);
|
|
413
|
+
newlineIndex = buffer.indexOf("\n");
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const trailing = buffer.trim();
|
|
417
|
+
if (trailing.length > 0) yield JSON.parse(trailing);
|
|
418
|
+
} finally {
|
|
419
|
+
reader.releaseLock();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/client/url.ts
|
|
425
|
+
function createClientUrl(host, routePath, searchParams) {
|
|
426
|
+
const normalizedRoute = routePath.startsWith("/") ? routePath : `/${routePath}`;
|
|
427
|
+
const search = formatSearch(searchParams);
|
|
428
|
+
if (isAbsoluteUrl(host)) {
|
|
429
|
+
const url = new URL(host);
|
|
430
|
+
url.pathname = `${trimTrailingSlash(url.pathname)}${normalizedRoute}`;
|
|
431
|
+
url.search = search;
|
|
432
|
+
url.hash = "";
|
|
433
|
+
return url.toString();
|
|
434
|
+
}
|
|
435
|
+
return `${trimTrailingSlash(host)}${normalizedRoute}${search}`;
|
|
436
|
+
}
|
|
437
|
+
function isAbsoluteUrl(value) {
|
|
438
|
+
return /^[a-z][a-z\d+\-.]*:/i.test(value);
|
|
439
|
+
}
|
|
440
|
+
function trimTrailingSlash(value) {
|
|
441
|
+
if (value === "/") return "";
|
|
442
|
+
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
443
|
+
}
|
|
444
|
+
function formatSearch(searchParams) {
|
|
445
|
+
if (!searchParams || Object.keys(searchParams).length === 0) return "";
|
|
446
|
+
return `?${new URLSearchParams(searchParams).toString()}`;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
//#endregion
|
|
450
|
+
//#region src/client/open-stream.ts
|
|
451
|
+
const STREAM_OPEN_RETRY_ATTEMPTS = 12;
|
|
452
|
+
const STREAM_OPEN_RETRY_DELAY_MS = 250;
|
|
453
|
+
const STREAM_OPEN_RETRYABLE_STATUS = new Set([
|
|
454
|
+
404,
|
|
455
|
+
409,
|
|
456
|
+
425,
|
|
457
|
+
500,
|
|
458
|
+
502,
|
|
459
|
+
503,
|
|
460
|
+
504
|
|
461
|
+
]);
|
|
462
|
+
async function* openStreamIterable(input) {
|
|
463
|
+
let startIndex = input.startIndex;
|
|
464
|
+
let remainingReconnectAttempts = input.maxReconnectAttempts;
|
|
465
|
+
while (true) {
|
|
466
|
+
const body = await openStreamBody({
|
|
467
|
+
...input,
|
|
468
|
+
startIndex
|
|
469
|
+
});
|
|
470
|
+
let disconnected = false;
|
|
471
|
+
try {
|
|
472
|
+
for await (const event of readNdjsonStream(body)) {
|
|
473
|
+
startIndex += 1;
|
|
474
|
+
yield event;
|
|
475
|
+
}
|
|
476
|
+
} catch (error) {
|
|
477
|
+
if (!isStreamDisconnectError(error)) throw error;
|
|
478
|
+
disconnected = true;
|
|
479
|
+
}
|
|
480
|
+
if (!disconnected || input.signal?.aborted || remainingReconnectAttempts <= 0) return;
|
|
481
|
+
remainingReconnectAttempts -= 1;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async function openStreamBody(input) {
|
|
485
|
+
let lastStatus;
|
|
486
|
+
let lastBody;
|
|
487
|
+
for (let attempt = 0; attempt < STREAM_OPEN_RETRY_ATTEMPTS; attempt += 1) {
|
|
488
|
+
const url = createClientUrl(input.host, createEveMessageStreamRoutePath(input.sessionId), input.startIndex > 0 ? { startIndex: String(input.startIndex) } : void 0);
|
|
489
|
+
const headers = await input.resolveHeaders();
|
|
490
|
+
const response = await fetch(url, {
|
|
491
|
+
headers,
|
|
492
|
+
redirect: input.redirect,
|
|
493
|
+
signal: input.signal ?? null
|
|
494
|
+
});
|
|
495
|
+
if (response.ok) {
|
|
496
|
+
if (!response.body) throw new ClientError(response.status, "Response body is null.");
|
|
497
|
+
return response.body;
|
|
498
|
+
}
|
|
499
|
+
lastStatus = response.status;
|
|
500
|
+
lastBody = await response.text();
|
|
501
|
+
if (!STREAM_OPEN_RETRYABLE_STATUS.has(response.status)) throw new ClientError(response.status, lastBody);
|
|
502
|
+
if (attempt < STREAM_OPEN_RETRY_ATTEMPTS - 1) await sleep$1(STREAM_OPEN_RETRY_DELAY_MS);
|
|
503
|
+
}
|
|
504
|
+
throw new ClientError(lastStatus ?? 0, lastBody ?? "Failed to open message stream.");
|
|
505
|
+
}
|
|
506
|
+
async function sleep$1(ms) {
|
|
507
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/client/session.ts
|
|
512
|
+
const DELIVER_RETRY_ATTEMPTS = 10;
|
|
513
|
+
const DELIVER_RETRY_DELAY_MS = 200;
|
|
514
|
+
var ClientSession = class {
|
|
515
|
+
#context;
|
|
516
|
+
#state;
|
|
517
|
+
constructor(context, state) {
|
|
518
|
+
this.#context = context;
|
|
519
|
+
this.#state = state;
|
|
520
|
+
}
|
|
521
|
+
get state() {
|
|
522
|
+
return this.#state;
|
|
523
|
+
}
|
|
524
|
+
async send(input) {
|
|
525
|
+
const payload = normalizeSendTurnInput(input);
|
|
526
|
+
const state = this.#state;
|
|
527
|
+
const { continuationToken, sessionId } = await this.#postTurn(payload, state);
|
|
528
|
+
return new MessageResponse({
|
|
529
|
+
continuationToken,
|
|
530
|
+
createStream: () => this.#createEventStream(sessionId, continuationToken, state, payload),
|
|
531
|
+
sessionId
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
stream(options) {
|
|
535
|
+
const sessionId = this.#state.sessionId;
|
|
536
|
+
if (!sessionId) throw new Error("Session has no session ID. Send a message first.");
|
|
537
|
+
return this.#streamAndAdvance(sessionId, options);
|
|
538
|
+
}
|
|
539
|
+
async #postTurn(input, session) {
|
|
540
|
+
const routePath = session.sessionId ? createEveContinueSessionRoutePath(session.sessionId) : EVE_CREATE_SESSION_ROUTE_PATH;
|
|
541
|
+
const url = createClientUrl(this.#context.host, routePath);
|
|
542
|
+
const headers = await this.#context.resolveHeaders(input.headers);
|
|
543
|
+
headers.set("content-type", "application/json");
|
|
544
|
+
const body = createHandleMessageBody({
|
|
545
|
+
input,
|
|
546
|
+
outputSchema: normalizeOutputSchemaForRequest(input.outputSchema),
|
|
547
|
+
session
|
|
548
|
+
});
|
|
549
|
+
if (body === null) throw new Error("Session.send requires a non-empty message, inputResponses, or both.");
|
|
550
|
+
const response = await postTurnWithRetry({
|
|
551
|
+
body: JSON.stringify(body),
|
|
552
|
+
headers,
|
|
553
|
+
mustDeliver: (input.inputResponses?.length ?? 0) > 0,
|
|
554
|
+
redirect: this.#context.redirect,
|
|
555
|
+
signal: input.signal,
|
|
556
|
+
url
|
|
557
|
+
});
|
|
558
|
+
const payload = await response.json();
|
|
559
|
+
const sessionId = (typeof payload.sessionId === "string" ? payload.sessionId : void 0) ?? response.headers.get("x-eve-session-id")?.trim() ?? session.sessionId;
|
|
560
|
+
if (!sessionId) throw new Error("Message route did not return a session id.");
|
|
561
|
+
return {
|
|
562
|
+
continuationToken: typeof payload.continuationToken === "string" ? payload.continuationToken : void 0,
|
|
563
|
+
sessionId
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
async *#createEventStream(sessionId, continuationToken, initialState, input) {
|
|
567
|
+
const events = [];
|
|
568
|
+
try {
|
|
569
|
+
let currentStreamIndex = initialState.sessionId === sessionId ? initialState.streamIndex : 0;
|
|
570
|
+
let remainingReconnectAttempts = this.#context.maxReconnectAttempts;
|
|
571
|
+
while (true) {
|
|
572
|
+
const body = await this.#openStreamBody(sessionId, currentStreamIndex, input.signal, input.headers);
|
|
573
|
+
let foundBoundary = false;
|
|
574
|
+
try {
|
|
575
|
+
for await (const event of readNdjsonStream(body)) {
|
|
576
|
+
events.push(event);
|
|
577
|
+
currentStreamIndex += 1;
|
|
578
|
+
yield event;
|
|
579
|
+
if (isCurrentTurnBoundaryEvent(event)) {
|
|
580
|
+
foundBoundary = true;
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
} catch (error) {
|
|
585
|
+
if (!isStreamDisconnectError(error)) throw error;
|
|
586
|
+
}
|
|
587
|
+
if (foundBoundary) break;
|
|
588
|
+
if (input.signal?.aborted) break;
|
|
589
|
+
if (remainingReconnectAttempts <= 0) break;
|
|
590
|
+
remainingReconnectAttempts -= 1;
|
|
591
|
+
}
|
|
592
|
+
} finally {
|
|
593
|
+
this.#state = advanceSession({
|
|
594
|
+
continuationToken,
|
|
595
|
+
events,
|
|
596
|
+
preserveCompletedSessions: this.#context.preserveCompletedSessions,
|
|
597
|
+
sessionId,
|
|
598
|
+
session: initialState
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
async #openStreamBody(sessionId, startIndex, signal, headers) {
|
|
603
|
+
return await openStreamBody({
|
|
604
|
+
host: this.#context.host,
|
|
605
|
+
resolveHeaders: () => this.#context.resolveHeaders(headers),
|
|
606
|
+
redirect: this.#context.redirect,
|
|
607
|
+
sessionId,
|
|
608
|
+
signal,
|
|
609
|
+
startIndex
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
async *#streamAndAdvance(sessionId, options) {
|
|
613
|
+
const initialState = this.#state;
|
|
614
|
+
const streamIndex = options?.startIndex ?? initialState.streamIndex;
|
|
615
|
+
const events = [];
|
|
616
|
+
try {
|
|
617
|
+
for await (const event of openStreamIterable({
|
|
618
|
+
host: this.#context.host,
|
|
619
|
+
maxReconnectAttempts: this.#context.maxReconnectAttempts,
|
|
620
|
+
resolveHeaders: () => this.#context.resolveHeaders(),
|
|
621
|
+
redirect: this.#context.redirect,
|
|
622
|
+
sessionId,
|
|
623
|
+
signal: options?.signal,
|
|
624
|
+
startIndex: streamIndex
|
|
625
|
+
})) {
|
|
626
|
+
events.push(event);
|
|
627
|
+
yield event;
|
|
628
|
+
}
|
|
629
|
+
} finally {
|
|
630
|
+
this.#state = advanceSession({
|
|
631
|
+
continuationToken: initialState.continuationToken,
|
|
632
|
+
events,
|
|
633
|
+
preserveCompletedSessions: this.#context.preserveCompletedSessions,
|
|
634
|
+
session: {
|
|
635
|
+
...initialState,
|
|
636
|
+
sessionId,
|
|
637
|
+
streamIndex
|
|
638
|
+
},
|
|
639
|
+
sessionId
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
async function postTurnWithRetry(input) {
|
|
645
|
+
const attempts = input.mustDeliver ? DELIVER_RETRY_ATTEMPTS : 1;
|
|
646
|
+
let lastStatus;
|
|
647
|
+
let lastBody;
|
|
648
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
649
|
+
const response = await fetch(input.url, {
|
|
650
|
+
body: input.body,
|
|
651
|
+
headers: input.headers,
|
|
652
|
+
method: "POST",
|
|
653
|
+
redirect: input.redirect,
|
|
654
|
+
signal: input.signal ?? null
|
|
655
|
+
});
|
|
656
|
+
if (response.ok) return response;
|
|
657
|
+
lastStatus = response.status;
|
|
658
|
+
lastBody = await response.text();
|
|
659
|
+
if (!isRetryableDeliveryFailure(response.status, lastBody)) throw new ClientError(response.status, lastBody);
|
|
660
|
+
if (attempt < attempts - 1) await sleep(DELIVER_RETRY_DELAY_MS);
|
|
661
|
+
}
|
|
662
|
+
throw new ClientError(lastStatus ?? 0, lastBody ?? "Failed to deliver session turn.");
|
|
663
|
+
}
|
|
664
|
+
function isRetryableDeliveryFailure(status, body) {
|
|
665
|
+
return status === 500 && /target session was not found/i.test(body);
|
|
666
|
+
}
|
|
667
|
+
async function sleep(ms) {
|
|
668
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
669
|
+
}
|
|
670
|
+
function normalizeSendTurnInput(input) {
|
|
671
|
+
return typeof input === "string" ? { message: input } : input;
|
|
672
|
+
}
|
|
673
|
+
function createHandleMessageBody(input) {
|
|
674
|
+
const body = {};
|
|
675
|
+
if (input.input.message !== void 0) body.message = input.input.message;
|
|
676
|
+
if (input.input.inputResponses !== void 0 && input.input.inputResponses.length > 0) body.inputResponses = input.input.inputResponses;
|
|
677
|
+
if (input.input.clientContext !== void 0) body.clientContext = input.input.clientContext;
|
|
678
|
+
if (input.outputSchema !== void 0) body.outputSchema = input.outputSchema;
|
|
679
|
+
if (input.session.continuationToken !== void 0) body.continuationToken = input.session.continuationToken;
|
|
680
|
+
if (Object.keys(body).length === 0) return null;
|
|
681
|
+
if (input.session.continuationToken === void 0 && body.message === void 0) return null;
|
|
682
|
+
if (input.session.continuationToken !== void 0 && body.message === void 0 && body.inputResponses === void 0) return null;
|
|
683
|
+
return body;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/client/types.ts
|
|
688
|
+
const VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER = "x-vercel-trusted-oidc-idp-token";
|
|
689
|
+
|
|
690
|
+
//#endregion
|
|
691
|
+
//#region src/client/client.ts
|
|
692
|
+
var Client = class {
|
|
693
|
+
#auth;
|
|
694
|
+
#headers;
|
|
695
|
+
#host;
|
|
696
|
+
#maxReconnectAttempts;
|
|
697
|
+
#preserveCompletedSessions;
|
|
698
|
+
#redirect;
|
|
699
|
+
constructor(options) {
|
|
700
|
+
this.#host = options.host;
|
|
701
|
+
this.#auth = options.auth;
|
|
702
|
+
this.#headers = options.headers;
|
|
703
|
+
this.#maxReconnectAttempts = options.maxReconnectAttempts ?? 3;
|
|
704
|
+
this.#preserveCompletedSessions = options.preserveCompletedSessions ?? false;
|
|
705
|
+
this.#redirect = options.redirect;
|
|
706
|
+
}
|
|
707
|
+
async health() {
|
|
708
|
+
const url = createClientUrl(this.#host, EVE_HEALTH_ROUTE_PATH);
|
|
709
|
+
const headers = await this.#resolveHeaders();
|
|
710
|
+
const response = await fetch(url, withRedirectPolicy({ headers }, this.#redirect));
|
|
711
|
+
if (!response.ok) {
|
|
712
|
+
const body = await response.text();
|
|
713
|
+
throw new ClientError(response.status, body);
|
|
714
|
+
}
|
|
715
|
+
return await response.json();
|
|
716
|
+
}
|
|
717
|
+
async info() {
|
|
718
|
+
const response = await this.fetch(EVE_INFO_ROUTE_PATH);
|
|
719
|
+
if (!response.ok) {
|
|
720
|
+
const body = await response.text();
|
|
721
|
+
throw new ClientError(response.status, body);
|
|
722
|
+
}
|
|
723
|
+
const result = AgentInfoResultSchema.safeParse(await response.json());
|
|
724
|
+
if (!result.success) throw new SyntaxError("The server returned an unrecognized response from the Eve agent info route.");
|
|
725
|
+
return result.data;
|
|
726
|
+
}
|
|
727
|
+
async fetch(path, init = {}) {
|
|
728
|
+
const url = createClientUrl(this.#host, path);
|
|
729
|
+
const headers = await this.#resolveHeaders(headersInitToRecord(init.headers));
|
|
730
|
+
return await fetch(url, withRedirectPolicy({
|
|
731
|
+
...init,
|
|
732
|
+
headers
|
|
733
|
+
}, this.#redirect));
|
|
734
|
+
}
|
|
735
|
+
session(state) {
|
|
736
|
+
let resolved;
|
|
737
|
+
if (typeof state === "string") resolved = {
|
|
738
|
+
continuationToken: state,
|
|
739
|
+
streamIndex: 0
|
|
740
|
+
};
|
|
741
|
+
else if (state) resolved = state;
|
|
742
|
+
else resolved = createInitialSessionState();
|
|
743
|
+
return new ClientSession({
|
|
744
|
+
host: this.#host,
|
|
745
|
+
maxReconnectAttempts: this.#maxReconnectAttempts,
|
|
746
|
+
preserveCompletedSessions: this.#preserveCompletedSessions,
|
|
747
|
+
redirect: this.#redirect,
|
|
748
|
+
resolveHeaders: (perRequest) => this.#resolveHeaders(perRequest)
|
|
749
|
+
}, resolved);
|
|
750
|
+
}
|
|
751
|
+
async #resolveHeaders(perRequest) {
|
|
752
|
+
const headers = new Headers();
|
|
753
|
+
const [baseHeaders, authHeaders] = await Promise.all([resolveHeadersValue(this.#headers), this.#resolveAuthHeaders()]);
|
|
754
|
+
for (const [key, value] of Object.entries(baseHeaders)) headers.set(key, value);
|
|
755
|
+
if (perRequest) for (const [key, value] of Object.entries(perRequest)) headers.set(key, value);
|
|
756
|
+
for (const [key, value] of Object.entries(authHeaders)) headers.set(key, value);
|
|
757
|
+
return headers;
|
|
758
|
+
}
|
|
759
|
+
async #resolveAuthHeaders() {
|
|
760
|
+
const auth = this.#auth;
|
|
761
|
+
if (!auth) return {};
|
|
762
|
+
if ("vercelOidc" in auth) {
|
|
763
|
+
const token = (await resolveTokenValue(auth.vercelOidc.token)).trim();
|
|
764
|
+
if (token.length === 0) return {};
|
|
765
|
+
return {
|
|
766
|
+
authorization: `Bearer ${token}`,
|
|
767
|
+
[VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER]: token
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
if ("bearer" in auth) {
|
|
771
|
+
const token = (await resolveTokenValue(auth.bearer)).trim();
|
|
772
|
+
return token.length === 0 ? {} : { authorization: `Bearer ${token}` };
|
|
773
|
+
}
|
|
774
|
+
if ("basic" in auth) {
|
|
775
|
+
const password = await resolveTokenValue(auth.basic.password);
|
|
776
|
+
return { authorization: `Basic ${encodeBasicCredentials(auth.basic.username, password)}` };
|
|
777
|
+
}
|
|
778
|
+
return {};
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
async function resolveTokenValue(value) {
|
|
782
|
+
return typeof value === "function" ? value() : value;
|
|
783
|
+
}
|
|
784
|
+
async function resolveHeadersValue(value) {
|
|
785
|
+
if (value === void 0) return {};
|
|
786
|
+
return typeof value === "function" ? await value() : value;
|
|
787
|
+
}
|
|
788
|
+
function headersInitToRecord(headers) {
|
|
789
|
+
if (headers === void 0) return {};
|
|
790
|
+
return Object.fromEntries(new Headers(headers).entries());
|
|
791
|
+
}
|
|
792
|
+
function withRedirectPolicy(init, redirect) {
|
|
793
|
+
return redirect === void 0 ? init : {
|
|
794
|
+
...init,
|
|
795
|
+
redirect
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function encodeBasicCredentials(username, password) {
|
|
799
|
+
const bytes = new TextEncoder().encode(`${username}:${password}`);
|
|
800
|
+
const binaryString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
|
|
801
|
+
return btoa(binaryString);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
//#endregion
|
|
805
|
+
//#region src/shared/errors.ts
|
|
806
|
+
function toErrorMessage(error) {
|
|
807
|
+
if (error instanceof Error) return error.message;
|
|
808
|
+
if (typeof error === "string") return error;
|
|
809
|
+
if (error === null || error === void 0) return String(error);
|
|
810
|
+
if (isObject(error)) {
|
|
811
|
+
if (typeof error.message === "string" && error.message.length > 0) return error.message;
|
|
812
|
+
return safeJsonStringify(error);
|
|
813
|
+
}
|
|
814
|
+
return String(error);
|
|
815
|
+
}
|
|
816
|
+
function toError(raw) {
|
|
817
|
+
if (raw instanceof Error) return raw;
|
|
818
|
+
const error = new Error(toErrorMessage(raw));
|
|
819
|
+
if (!isObject(raw)) return error;
|
|
820
|
+
if (typeof raw.name === "string" && raw.name.length > 0) error.name = raw.name;
|
|
821
|
+
if (typeof raw.stack === "string" && raw.stack.length > 0) error.stack = raw.stack;
|
|
822
|
+
if ("cause" in raw && raw.cause !== void 0 && raw.cause !== raw) error.cause = raw.cause;
|
|
823
|
+
return error;
|
|
824
|
+
}
|
|
825
|
+
function safeJsonStringify(value) {
|
|
826
|
+
try {
|
|
827
|
+
return JSON.stringify(value) ?? String(value);
|
|
828
|
+
} catch {
|
|
829
|
+
return String(value);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
//#endregion
|
|
834
|
+
//#region src/client/eve-agent-store.ts
|
|
835
|
+
var EveAgentStore = class {
|
|
836
|
+
#createSession;
|
|
837
|
+
#optimistic;
|
|
838
|
+
#reducer;
|
|
839
|
+
#subscribers = /* @__PURE__ */ new Set();
|
|
840
|
+
#abortController;
|
|
841
|
+
#callbacks = {};
|
|
842
|
+
#data;
|
|
843
|
+
#error;
|
|
844
|
+
#events;
|
|
845
|
+
#operationId = 0;
|
|
846
|
+
#pendingMessageSubmission;
|
|
847
|
+
#projectionEvents;
|
|
848
|
+
#session;
|
|
849
|
+
#snapshot;
|
|
850
|
+
#status = "ready";
|
|
851
|
+
constructor(init) {
|
|
852
|
+
this.#createSession = init.session ? void 0 : () => new Client({
|
|
853
|
+
auth: init.auth,
|
|
854
|
+
headers: init.headers,
|
|
855
|
+
host: init.host ?? "",
|
|
856
|
+
maxReconnectAttempts: init.maxReconnectAttempts
|
|
857
|
+
}).session(init.initialSession);
|
|
858
|
+
this.#events = [...init.initialEvents ?? []];
|
|
859
|
+
this.#projectionEvents = [...this.#events];
|
|
860
|
+
this.#optimistic = init.optimistic ?? true;
|
|
861
|
+
this.#reducer = init.reducer;
|
|
862
|
+
this.#session = init.session ?? this.#createOwnedSession();
|
|
863
|
+
this.#data = this.#reduceProjectionEvents(this.#projectionEvents);
|
|
864
|
+
this.#snapshot = this.#createSnapshot();
|
|
865
|
+
}
|
|
866
|
+
get snapshot() {
|
|
867
|
+
return this.#snapshot;
|
|
868
|
+
}
|
|
869
|
+
setCallbacks(callbacks) {
|
|
870
|
+
this.#callbacks = callbacks;
|
|
871
|
+
}
|
|
872
|
+
subscribe(callback) {
|
|
873
|
+
this.#subscribers.add(callback);
|
|
874
|
+
return () => {
|
|
875
|
+
this.#subscribers.delete(callback);
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
async send(input) {
|
|
879
|
+
if (this.#status === "streaming" || this.#status === "submitted") throw new Error("eve session is already processing a turn.");
|
|
880
|
+
const operationId = this.#startOperation();
|
|
881
|
+
const abortController = new AbortController();
|
|
882
|
+
this.#abortController = abortController;
|
|
883
|
+
this.#error = void 0;
|
|
884
|
+
this.#status = "submitted";
|
|
885
|
+
this.#publish();
|
|
886
|
+
try {
|
|
887
|
+
const preparedInput = await this.#callbacks.prepareSend?.(input) ?? input;
|
|
888
|
+
if (!this.#isCurrentOperation(operationId)) return;
|
|
889
|
+
this.#projectOptimisticMessage(preparedInput);
|
|
890
|
+
this.#projectInputResponses(preparedInput);
|
|
891
|
+
this.#publish();
|
|
892
|
+
const response = await this.#session.send({
|
|
893
|
+
...preparedInput,
|
|
894
|
+
signal: createAbortSignal(preparedInput.signal, abortController.signal)
|
|
895
|
+
});
|
|
896
|
+
let sawEvent = false;
|
|
897
|
+
for await (const event of response) {
|
|
898
|
+
if (!this.#isCurrentOperation(operationId)) return;
|
|
899
|
+
if (!sawEvent) {
|
|
900
|
+
sawEvent = true;
|
|
901
|
+
this.#status = "streaming";
|
|
902
|
+
}
|
|
903
|
+
this.#events = [...this.#events, event];
|
|
904
|
+
this.#applyServerEvent(event);
|
|
905
|
+
this.#callbacks.onEvent?.(event);
|
|
906
|
+
this.#applyTerminalStreamFailure(event);
|
|
907
|
+
this.#publish();
|
|
908
|
+
}
|
|
909
|
+
if (!this.#isCurrentOperation(operationId)) return;
|
|
910
|
+
this.#status = this.#error === void 0 ? "ready" : "error";
|
|
911
|
+
} catch (error) {
|
|
912
|
+
if (!this.#isCurrentOperation(operationId)) return;
|
|
913
|
+
if (isAbortError(error)) {
|
|
914
|
+
this.#status = "ready";
|
|
915
|
+
this.#failPendingMessageSubmission(toError(error));
|
|
916
|
+
} else {
|
|
917
|
+
this.#error = toError(error);
|
|
918
|
+
this.#status = "error";
|
|
919
|
+
this.#failPendingMessageSubmission(this.#error);
|
|
920
|
+
this.#callbacks.onError?.(this.#error);
|
|
921
|
+
}
|
|
922
|
+
} finally {
|
|
923
|
+
if (this.#isCurrentOperation(operationId)) {
|
|
924
|
+
this.#abortController = void 0;
|
|
925
|
+
this.#callbacks.onSessionChange?.(this.#session.state);
|
|
926
|
+
this.#publish();
|
|
927
|
+
this.#callbacks.onFinish?.(this.#snapshot);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
stop() {
|
|
932
|
+
this.#abortController?.abort();
|
|
933
|
+
}
|
|
934
|
+
reset() {
|
|
935
|
+
this.#invalidateOperation();
|
|
936
|
+
this.stop();
|
|
937
|
+
this.#abortController = void 0;
|
|
938
|
+
this.#session = this.#createSession?.() ?? this.#session;
|
|
939
|
+
this.#events = [];
|
|
940
|
+
this.#pendingMessageSubmission = void 0;
|
|
941
|
+
this.#projectionEvents = [];
|
|
942
|
+
this.#data = this.#reducer.initial();
|
|
943
|
+
this.#error = void 0;
|
|
944
|
+
this.#status = "ready";
|
|
945
|
+
this.#callbacks.onSessionChange?.(this.#session.state);
|
|
946
|
+
this.#publish();
|
|
947
|
+
}
|
|
948
|
+
#createOwnedSession() {
|
|
949
|
+
if (!this.#createSession) throw new Error("Cannot create an owned eve session from an external session.");
|
|
950
|
+
return this.#createSession();
|
|
951
|
+
}
|
|
952
|
+
#startOperation() {
|
|
953
|
+
this.#operationId += 1;
|
|
954
|
+
return this.#operationId;
|
|
955
|
+
}
|
|
956
|
+
#invalidateOperation() {
|
|
957
|
+
this.#operationId += 1;
|
|
958
|
+
}
|
|
959
|
+
#isCurrentOperation(operationId) {
|
|
960
|
+
return this.#operationId === operationId;
|
|
961
|
+
}
|
|
962
|
+
#projectOptimisticMessage(input) {
|
|
963
|
+
if (!this.#optimistic || input.message === void 0) return;
|
|
964
|
+
const id = createSubmissionId();
|
|
965
|
+
const pending = {
|
|
966
|
+
createdAt: Date.now(),
|
|
967
|
+
id,
|
|
968
|
+
message: summarizeUserContent(input.message)
|
|
969
|
+
};
|
|
970
|
+
this.#pendingMessageSubmission = pending;
|
|
971
|
+
this.#appendProjectionEvent({
|
|
972
|
+
data: {
|
|
973
|
+
createdAt: pending.createdAt,
|
|
974
|
+
message: pending.message,
|
|
975
|
+
submissionId: pending.id
|
|
976
|
+
},
|
|
977
|
+
type: "client.message.submitted"
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
#projectInputResponses(input) {
|
|
981
|
+
if (input.inputResponses === void 0 || input.inputResponses.length === 0) return;
|
|
982
|
+
this.#appendProjectionEvent({
|
|
983
|
+
data: {
|
|
984
|
+
createdAt: Date.now(),
|
|
985
|
+
responses: input.inputResponses
|
|
986
|
+
},
|
|
987
|
+
type: "client.input.responded"
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
#applyServerEvent(event) {
|
|
991
|
+
if (event.type === "message.received" && this.#pendingMessageSubmission !== void 0) {
|
|
992
|
+
const submissionId = this.#pendingMessageSubmission.id;
|
|
993
|
+
this.#pendingMessageSubmission = void 0;
|
|
994
|
+
this.#replaceProjectionEvent((candidate) => candidate.type === "client.message.submitted" && candidate.data.submissionId === submissionId, event);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
this.#appendProjectionEvent(event);
|
|
998
|
+
}
|
|
999
|
+
#applyTerminalStreamFailure(event) {
|
|
1000
|
+
const error = toTerminalStreamFailureError(event);
|
|
1001
|
+
if (error === void 0) return;
|
|
1002
|
+
this.#status = "error";
|
|
1003
|
+
this.#failPendingMessageSubmission(error);
|
|
1004
|
+
if (this.#error === void 0) {
|
|
1005
|
+
this.#error = error;
|
|
1006
|
+
this.#callbacks.onError?.(error);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
#failPendingMessageSubmission(error) {
|
|
1010
|
+
const pending = this.#pendingMessageSubmission;
|
|
1011
|
+
if (pending === void 0) return;
|
|
1012
|
+
this.#pendingMessageSubmission = void 0;
|
|
1013
|
+
this.#replaceProjectionEvent((event) => event.type === "client.message.submitted" && event.data.submissionId === pending.id, {
|
|
1014
|
+
data: {
|
|
1015
|
+
createdAt: pending.createdAt,
|
|
1016
|
+
error: { message: error.message },
|
|
1017
|
+
message: pending.message,
|
|
1018
|
+
submissionId: pending.id
|
|
1019
|
+
},
|
|
1020
|
+
type: "client.message.failed"
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
#appendProjectionEvent(event) {
|
|
1024
|
+
this.#projectionEvents = [...this.#projectionEvents, event];
|
|
1025
|
+
this.#data = this.#reducer.reduce(this.#data, event);
|
|
1026
|
+
}
|
|
1027
|
+
#replaceProjectionEvent(predicate, replacement) {
|
|
1028
|
+
let replaced = false;
|
|
1029
|
+
this.#projectionEvents = this.#projectionEvents.map((event) => {
|
|
1030
|
+
if (!replaced && predicate(event)) {
|
|
1031
|
+
replaced = true;
|
|
1032
|
+
return replacement;
|
|
1033
|
+
}
|
|
1034
|
+
return event;
|
|
1035
|
+
});
|
|
1036
|
+
if (!replaced) this.#projectionEvents = [...this.#projectionEvents, replacement];
|
|
1037
|
+
this.#data = this.#reduceProjectionEvents(this.#projectionEvents);
|
|
1038
|
+
}
|
|
1039
|
+
#reduceProjectionEvents(events) {
|
|
1040
|
+
let data = this.#reducer.initial();
|
|
1041
|
+
for (const event of events) data = this.#reducer.reduce(data, event);
|
|
1042
|
+
return data;
|
|
1043
|
+
}
|
|
1044
|
+
#createSnapshot() {
|
|
1045
|
+
return {
|
|
1046
|
+
data: this.#data,
|
|
1047
|
+
error: this.#error,
|
|
1048
|
+
events: this.#events,
|
|
1049
|
+
session: this.#session.state,
|
|
1050
|
+
status: this.#status
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
#publish() {
|
|
1054
|
+
this.#snapshot = this.#createSnapshot();
|
|
1055
|
+
for (const subscriber of this.#subscribers) subscriber();
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
let submissionSequence = 0;
|
|
1059
|
+
function createSubmissionId() {
|
|
1060
|
+
const randomUUID = globalThis.crypto?.randomUUID;
|
|
1061
|
+
if (randomUUID !== void 0) return randomUUID.call(globalThis.crypto);
|
|
1062
|
+
submissionSequence += 1;
|
|
1063
|
+
return `submission_${submissionSequence.toString()}`;
|
|
1064
|
+
}
|
|
1065
|
+
function createAbortSignal(first, second) {
|
|
1066
|
+
return first ? AbortSignal.any([first, second]) : second;
|
|
1067
|
+
}
|
|
1068
|
+
function summarizeUserContent(message) {
|
|
1069
|
+
if (typeof message === "string") return message;
|
|
1070
|
+
const parts = [];
|
|
1071
|
+
for (const part of message) {
|
|
1072
|
+
if (part.type === "text") {
|
|
1073
|
+
parts.push(part.text);
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
if (part.type === "file") parts.push(part.filename ? `[file: ${part.filename}]` : "[file]");
|
|
1077
|
+
}
|
|
1078
|
+
return parts.join("\n");
|
|
1079
|
+
}
|
|
1080
|
+
function isAbortError(error) {
|
|
1081
|
+
return error instanceof Error && error.name === "AbortError";
|
|
1082
|
+
}
|
|
1083
|
+
function toTerminalStreamFailureError(event) {
|
|
1084
|
+
if (event.type !== "session.failed") return;
|
|
1085
|
+
const error = new Error(event.data.message);
|
|
1086
|
+
error.name = event.data.code;
|
|
1087
|
+
return error;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
//#endregion
|
|
1091
|
+
//#region src/client/message-reducer.ts
|
|
1092
|
+
function defaultMessageReducer() {
|
|
1093
|
+
return {
|
|
1094
|
+
initial() {
|
|
1095
|
+
return { messages: [] };
|
|
1096
|
+
},
|
|
1097
|
+
reduce(data, event) {
|
|
1098
|
+
return reduceMessageData(data, event);
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
function reduceMessageData(data, event) {
|
|
1103
|
+
switch (event.type) {
|
|
1104
|
+
case "client.message.submitted": return upsertMessage(data, {
|
|
1105
|
+
id: optimisticUserMessageId(event.data.submissionId),
|
|
1106
|
+
metadata: {
|
|
1107
|
+
optimistic: true,
|
|
1108
|
+
status: "submitted"
|
|
1109
|
+
},
|
|
1110
|
+
parts: [{
|
|
1111
|
+
type: "text",
|
|
1112
|
+
text: event.data.message
|
|
1113
|
+
}],
|
|
1114
|
+
role: "user"
|
|
1115
|
+
});
|
|
1116
|
+
case "client.message.failed": return upsertMessage(data, {
|
|
1117
|
+
id: optimisticUserMessageId(event.data.submissionId),
|
|
1118
|
+
metadata: {
|
|
1119
|
+
optimistic: true,
|
|
1120
|
+
status: "failed"
|
|
1121
|
+
},
|
|
1122
|
+
parts: [{
|
|
1123
|
+
type: "text",
|
|
1124
|
+
text: event.data.message
|
|
1125
|
+
}],
|
|
1126
|
+
role: "user"
|
|
1127
|
+
});
|
|
1128
|
+
case "client.input.responded": {
|
|
1129
|
+
let next = data;
|
|
1130
|
+
for (const response of event.data.responses) next = respondToInputRequest(next, response);
|
|
1131
|
+
return next;
|
|
1132
|
+
}
|
|
1133
|
+
case "message.received": return upsertMessage(data, {
|
|
1134
|
+
id: `${event.data.turnId}:user`,
|
|
1135
|
+
metadata: {
|
|
1136
|
+
status: "complete",
|
|
1137
|
+
turnId: event.data.turnId
|
|
1138
|
+
},
|
|
1139
|
+
parts: [{
|
|
1140
|
+
type: "text",
|
|
1141
|
+
text: event.data.message,
|
|
1142
|
+
state: "done"
|
|
1143
|
+
}],
|
|
1144
|
+
role: "user"
|
|
1145
|
+
});
|
|
1146
|
+
case "step.started": return updateAssistantMessage(data, event.data.turnId, (message) => ensureStepStartPart(message, event.data.stepIndex));
|
|
1147
|
+
case "reasoning.appended": return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1148
|
+
state: "streaming",
|
|
1149
|
+
stepIndex: event.data.stepIndex,
|
|
1150
|
+
text: event.data.reasoningSoFar,
|
|
1151
|
+
type: "reasoning"
|
|
1152
|
+
}));
|
|
1153
|
+
case "reasoning.completed": return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1154
|
+
state: "done",
|
|
1155
|
+
stepIndex: event.data.stepIndex,
|
|
1156
|
+
text: event.data.reasoning,
|
|
1157
|
+
type: "reasoning"
|
|
1158
|
+
}));
|
|
1159
|
+
case "actions.requested": {
|
|
1160
|
+
let next = data;
|
|
1161
|
+
for (const action of event.data.actions) {
|
|
1162
|
+
const descriptor = normalizeActionRequest(action);
|
|
1163
|
+
next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1164
|
+
input: "input" in action ? action.input : void 0,
|
|
1165
|
+
state: "input-available",
|
|
1166
|
+
stepIndex: event.data.stepIndex,
|
|
1167
|
+
toolCallId: action.callId,
|
|
1168
|
+
toolMetadata: createToolMetadata(descriptor),
|
|
1169
|
+
toolName: descriptor.toolName,
|
|
1170
|
+
type: "dynamic-tool"
|
|
1171
|
+
}));
|
|
1172
|
+
}
|
|
1173
|
+
return next;
|
|
1174
|
+
}
|
|
1175
|
+
case "input.requested": {
|
|
1176
|
+
let next = data;
|
|
1177
|
+
for (const request of event.data.requests) {
|
|
1178
|
+
const descriptor = normalizeActionRequest(request.action);
|
|
1179
|
+
next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1180
|
+
approval: { id: request.requestId },
|
|
1181
|
+
input: request.action.input,
|
|
1182
|
+
state: "approval-requested",
|
|
1183
|
+
stepIndex: event.data.stepIndex,
|
|
1184
|
+
toolCallId: request.action.callId,
|
|
1185
|
+
toolMetadata: createToolMetadata(descriptor, { inputRequest: toMessageInputRequest(request) }),
|
|
1186
|
+
toolName: descriptor.toolName,
|
|
1187
|
+
type: "dynamic-tool"
|
|
1188
|
+
}));
|
|
1189
|
+
}
|
|
1190
|
+
return next;
|
|
1191
|
+
}
|
|
1192
|
+
case "action.result": {
|
|
1193
|
+
const descriptor = normalizeActionResult(event.data.result);
|
|
1194
|
+
const existing = findToolPart(data, event.data.result.callId);
|
|
1195
|
+
const denied = event.data.error?.code === "TOOL_EXECUTION_DENIED";
|
|
1196
|
+
const failed = event.data.status === "failed" && !denied;
|
|
1197
|
+
const approvalId = existing?.approval?.id ?? event.data.result.callId;
|
|
1198
|
+
const toolMetadata = mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor));
|
|
1199
|
+
const resultPartBase = {
|
|
1200
|
+
input: existing?.input,
|
|
1201
|
+
stepIndex: event.data.stepIndex,
|
|
1202
|
+
toolCallId: event.data.result.callId,
|
|
1203
|
+
toolMetadata,
|
|
1204
|
+
toolName: existing?.toolName ?? descriptor.toolName,
|
|
1205
|
+
type: "dynamic-tool"
|
|
1206
|
+
};
|
|
1207
|
+
let nextPart;
|
|
1208
|
+
if (denied) nextPart = {
|
|
1209
|
+
...resultPartBase,
|
|
1210
|
+
approval: {
|
|
1211
|
+
approved: false,
|
|
1212
|
+
id: approvalId,
|
|
1213
|
+
reason: event.data.error?.message
|
|
1214
|
+
},
|
|
1215
|
+
state: "output-denied"
|
|
1216
|
+
};
|
|
1217
|
+
else if (failed) nextPart = {
|
|
1218
|
+
...resultPartBase,
|
|
1219
|
+
approval: approvedApproval(existing),
|
|
1220
|
+
errorText: event.data.error?.message ?? stringifyUnknown(event.data.result.output),
|
|
1221
|
+
state: "output-error"
|
|
1222
|
+
};
|
|
1223
|
+
else nextPart = {
|
|
1224
|
+
...resultPartBase,
|
|
1225
|
+
approval: approvedApproval(existing),
|
|
1226
|
+
output: event.data.result.output,
|
|
1227
|
+
state: "output-available"
|
|
1228
|
+
};
|
|
1229
|
+
if (existing !== void 0) return updateToolPart(data, event.data.result.callId, nextPart);
|
|
1230
|
+
return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
|
|
1231
|
+
}
|
|
1232
|
+
case "message.appended": return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1233
|
+
state: "streaming",
|
|
1234
|
+
stepIndex: event.data.stepIndex,
|
|
1235
|
+
text: event.data.messageSoFar,
|
|
1236
|
+
type: "text"
|
|
1237
|
+
}));
|
|
1238
|
+
case "message.completed": return updateAssistantMessage(data, event.data.turnId, (message) => {
|
|
1239
|
+
if (event.data.message === null) return removeTextPart(message, event.data.stepIndex);
|
|
1240
|
+
return upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1241
|
+
state: "done",
|
|
1242
|
+
stepIndex: event.data.stepIndex,
|
|
1243
|
+
text: event.data.message,
|
|
1244
|
+
type: "text"
|
|
1245
|
+
});
|
|
1246
|
+
});
|
|
1247
|
+
case "result.completed": return updateAssistantMetadata(data, event.data.turnId, { result: event.data.result });
|
|
1248
|
+
case "turn.completed": return updateAssistantMetadata(data, event.data.turnId, { status: "complete" });
|
|
1249
|
+
case "turn.failed":
|
|
1250
|
+
case "session.failed": return data;
|
|
1251
|
+
default: return data;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
function respondToInputRequest(data, response) {
|
|
1255
|
+
const existing = findToolPartByApprovalId(data, response.requestId);
|
|
1256
|
+
if (!existing) return data;
|
|
1257
|
+
const approval = { id: response.requestId };
|
|
1258
|
+
if (response.text !== void 0) approval.reason = response.text;
|
|
1259
|
+
return updateToolPart(data, existing.toolCallId, {
|
|
1260
|
+
approval,
|
|
1261
|
+
input: existing.input,
|
|
1262
|
+
state: "approval-responded",
|
|
1263
|
+
stepIndex: existing.stepIndex,
|
|
1264
|
+
toolCallId: existing.toolCallId,
|
|
1265
|
+
toolMetadata: mergeToolMetadata(existing.toolMetadata, { eve: {
|
|
1266
|
+
inputResponse: response,
|
|
1267
|
+
kind: existing.toolMetadata?.eve?.kind ?? "unknown",
|
|
1268
|
+
name: existing.toolMetadata?.eve?.name ?? existing.toolName
|
|
1269
|
+
} }),
|
|
1270
|
+
toolName: existing.toolName,
|
|
1271
|
+
type: "dynamic-tool"
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
function updateAssistantMessage(data, turnId, update) {
|
|
1275
|
+
return upsertMessage(data, update(data.messages.find((message) => message.role === "assistant" && message.metadata?.turnId === turnId) ?? createAssistantMessage(turnId)));
|
|
1276
|
+
}
|
|
1277
|
+
function updateAssistantMetadata(data, turnId, metadata) {
|
|
1278
|
+
return updateAssistantMessage(data, turnId, (message) => ({
|
|
1279
|
+
...message,
|
|
1280
|
+
metadata: {
|
|
1281
|
+
...message.metadata,
|
|
1282
|
+
...metadata
|
|
1283
|
+
}
|
|
1284
|
+
}));
|
|
1285
|
+
}
|
|
1286
|
+
function createAssistantMessage(turnId) {
|
|
1287
|
+
return {
|
|
1288
|
+
id: `${turnId}:assistant`,
|
|
1289
|
+
metadata: {
|
|
1290
|
+
status: "streaming",
|
|
1291
|
+
turnId
|
|
1292
|
+
},
|
|
1293
|
+
parts: [],
|
|
1294
|
+
role: "assistant"
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
function ensureStepStartPart(message, stepIndex) {
|
|
1298
|
+
const stepStartCount = message.parts.filter((part) => part.type === "step-start").length;
|
|
1299
|
+
if (stepStartCount > stepIndex) return message;
|
|
1300
|
+
const missingCount = stepIndex - stepStartCount + 1;
|
|
1301
|
+
return {
|
|
1302
|
+
...message,
|
|
1303
|
+
parts: [...message.parts, ...Array.from({ length: missingCount }, () => ({ type: "step-start" }))]
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
function upsertPart(message, next) {
|
|
1307
|
+
const index = message.parts.findIndex((part) => partKey(part) === partKey(next));
|
|
1308
|
+
const parts = index === -1 ? [...message.parts, next] : [
|
|
1309
|
+
...message.parts.slice(0, index),
|
|
1310
|
+
next,
|
|
1311
|
+
...message.parts.slice(index + 1)
|
|
1312
|
+
];
|
|
1313
|
+
return {
|
|
1314
|
+
...message,
|
|
1315
|
+
metadata: {
|
|
1316
|
+
...message.metadata,
|
|
1317
|
+
status: next.type === "text" && next.state === "done" ? "complete" : "streaming"
|
|
1318
|
+
},
|
|
1319
|
+
parts
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
function removeTextPart(message, stepIndex) {
|
|
1323
|
+
const parts = message.parts.filter((part) => part.type !== "text" || part.stepIndex !== stepIndex);
|
|
1324
|
+
if (parts.length === message.parts.length) return message;
|
|
1325
|
+
return {
|
|
1326
|
+
...message,
|
|
1327
|
+
metadata: {
|
|
1328
|
+
...message.metadata,
|
|
1329
|
+
status: "complete"
|
|
1330
|
+
},
|
|
1331
|
+
parts
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
function updateToolPart(data, toolCallId, next) {
|
|
1335
|
+
const message = data.messages.find((candidate) => candidate.role === "assistant" && candidate.parts.some((part) => part.type === "dynamic-tool" && part.toolCallId === toolCallId));
|
|
1336
|
+
if (!message) return data;
|
|
1337
|
+
return upsertMessage(data, upsertPart(message, next));
|
|
1338
|
+
}
|
|
1339
|
+
function findToolPart(data, toolCallId) {
|
|
1340
|
+
for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) return part;
|
|
1341
|
+
}
|
|
1342
|
+
function findToolPartByApprovalId(data, approvalId) {
|
|
1343
|
+
for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.approval?.id === approvalId) return part;
|
|
1344
|
+
}
|
|
1345
|
+
function partKey(part) {
|
|
1346
|
+
switch (part.type) {
|
|
1347
|
+
case "text": return `text:${part.stepIndex ?? 0}`;
|
|
1348
|
+
case "reasoning": return `reasoning:${part.stepIndex ?? 0}`;
|
|
1349
|
+
case "step-start": return "step-start";
|
|
1350
|
+
case "dynamic-tool": return `dynamic-tool:${part.toolCallId}`;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
function upsertMessage(data, next) {
|
|
1354
|
+
const index = data.messages.findIndex((message) => message.id === next.id);
|
|
1355
|
+
if (index === -1) return { messages: [...data.messages, next] };
|
|
1356
|
+
return { messages: [
|
|
1357
|
+
...data.messages.slice(0, index),
|
|
1358
|
+
next,
|
|
1359
|
+
...data.messages.slice(index + 1)
|
|
1360
|
+
] };
|
|
1361
|
+
}
|
|
1362
|
+
function toMessageInputRequest(request) {
|
|
1363
|
+
return {
|
|
1364
|
+
allowFreeform: request.allowFreeform,
|
|
1365
|
+
display: request.display,
|
|
1366
|
+
options: request.options,
|
|
1367
|
+
prompt: request.prompt,
|
|
1368
|
+
requestId: request.requestId
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
function createToolMetadata(descriptor, extra) {
|
|
1372
|
+
return { eve: {
|
|
1373
|
+
inputRequest: extra?.inputRequest,
|
|
1374
|
+
kind: descriptor.kind,
|
|
1375
|
+
name: descriptor.name
|
|
1376
|
+
} };
|
|
1377
|
+
}
|
|
1378
|
+
function mergeToolMetadata(current, next) {
|
|
1379
|
+
const kind = next.eve?.kind ?? current?.eve?.kind ?? "unknown";
|
|
1380
|
+
const name = next.eve?.name ?? current?.eve?.name ?? "unknown";
|
|
1381
|
+
return { eve: {
|
|
1382
|
+
...current?.eve,
|
|
1383
|
+
...next.eve,
|
|
1384
|
+
inputRequest: next.eve?.inputRequest ?? current?.eve?.inputRequest,
|
|
1385
|
+
inputResponse: next.eve?.inputResponse ?? current?.eve?.inputResponse,
|
|
1386
|
+
kind,
|
|
1387
|
+
name
|
|
1388
|
+
} };
|
|
1389
|
+
}
|
|
1390
|
+
function approvedApproval(part) {
|
|
1391
|
+
if (!part?.approval?.id) return;
|
|
1392
|
+
return {
|
|
1393
|
+
approved: true,
|
|
1394
|
+
id: part.approval.id,
|
|
1395
|
+
isAutomatic: part.approval.isAutomatic,
|
|
1396
|
+
reason: part.approval.reason
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
function normalizeActionRequest(action) {
|
|
1400
|
+
switch (action.kind) {
|
|
1401
|
+
case "load-skill": return {
|
|
1402
|
+
kind: "load-skill",
|
|
1403
|
+
name: "load_skill",
|
|
1404
|
+
toolName: "eve:load-skill"
|
|
1405
|
+
};
|
|
1406
|
+
case "tool-call": return {
|
|
1407
|
+
kind: "tool-call",
|
|
1408
|
+
name: action.toolName,
|
|
1409
|
+
toolName: action.toolName
|
|
1410
|
+
};
|
|
1411
|
+
case "subagent-call": return {
|
|
1412
|
+
kind: "subagent-call",
|
|
1413
|
+
name: action.subagentName,
|
|
1414
|
+
toolName: `eve:subagent:${action.subagentName}`
|
|
1415
|
+
};
|
|
1416
|
+
case "remote-agent-call": return {
|
|
1417
|
+
kind: "subagent-call",
|
|
1418
|
+
name: action.remoteAgentName,
|
|
1419
|
+
toolName: `eve:subagent:${action.remoteAgentName}`
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
function normalizeActionResult(result) {
|
|
1424
|
+
switch (result.kind) {
|
|
1425
|
+
case "load-skill-result": return {
|
|
1426
|
+
kind: "load-skill",
|
|
1427
|
+
name: result.name ?? "load_skill",
|
|
1428
|
+
toolName: "eve:load-skill"
|
|
1429
|
+
};
|
|
1430
|
+
case "tool-result": return {
|
|
1431
|
+
kind: "tool-call",
|
|
1432
|
+
name: result.toolName,
|
|
1433
|
+
toolName: result.toolName
|
|
1434
|
+
};
|
|
1435
|
+
case "subagent-result": return {
|
|
1436
|
+
kind: "subagent-call",
|
|
1437
|
+
name: result.subagentName,
|
|
1438
|
+
toolName: `eve:subagent:${result.subagentName}`
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
function optimisticUserMessageId(submissionId) {
|
|
1443
|
+
return `optimistic:${submissionId}:user`;
|
|
1444
|
+
}
|
|
1445
|
+
function stringifyUnknown(value) {
|
|
1446
|
+
if (typeof value === "string") return value;
|
|
1447
|
+
try {
|
|
1448
|
+
return JSON.stringify(value);
|
|
1449
|
+
} catch {
|
|
1450
|
+
return "Action failed.";
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
//#endregion
|
|
1455
|
+
//#region src/vue/use-eve-agent.ts
|
|
1456
|
+
function useEveAgent(options = {}) {
|
|
1457
|
+
const reducer = options.reducer ?? defaultMessageReducer();
|
|
1458
|
+
const store = new EveAgentStore({
|
|
1459
|
+
auth: options.auth,
|
|
1460
|
+
headers: options.headers,
|
|
1461
|
+
host: options.host,
|
|
1462
|
+
initialEvents: options.initialEvents,
|
|
1463
|
+
initialSession: options.initialSession,
|
|
1464
|
+
maxReconnectAttempts: options.maxReconnectAttempts,
|
|
1465
|
+
optimistic: options.optimistic,
|
|
1466
|
+
reducer,
|
|
1467
|
+
session: options.session
|
|
1468
|
+
});
|
|
1469
|
+
store.setCallbacks({
|
|
1470
|
+
onError: options.onError,
|
|
1471
|
+
onEvent: options.onEvent,
|
|
1472
|
+
onFinish: options.onFinish,
|
|
1473
|
+
onSessionChange: options.onSessionChange,
|
|
1474
|
+
prepareSend: options.prepareSend
|
|
1475
|
+
});
|
|
1476
|
+
const snapshot = shallowRef(store.snapshot);
|
|
1477
|
+
if ("window" in globalThis) {
|
|
1478
|
+
const unsubscribe = store.subscribe(() => {
|
|
1479
|
+
snapshot.value = store.snapshot;
|
|
1480
|
+
});
|
|
1481
|
+
onScopeDispose(() => {
|
|
1482
|
+
unsubscribe();
|
|
1483
|
+
store.stop();
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
return {
|
|
1487
|
+
data: computed(() => snapshot.value.data),
|
|
1488
|
+
error: computed(() => snapshot.value.error),
|
|
1489
|
+
events: computed(() => snapshot.value.events),
|
|
1490
|
+
reset: () => store.reset(),
|
|
1491
|
+
send: (input) => store.send(input),
|
|
1492
|
+
session: computed(() => snapshot.value.session),
|
|
1493
|
+
status: computed(() => snapshot.value.status),
|
|
1494
|
+
stop: () => store.stop()
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
//#endregion
|
|
1499
|
+
export { defaultMessageReducer as n, useEveAgent as t };
|