@fevex/core 0.1.0-alpha.1 → 0.1.0-alpha.3
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/README.md +424 -6
- package/dist/agents/index.d.mts +1 -1
- package/dist/agents/index.mjs +1 -1
- package/dist/channels/index.d.mts +2 -0
- package/dist/channels/index.mjs +150 -0
- package/dist/evals/index.d.mts +19 -11
- package/dist/evals/index.mjs +125 -122
- package/dist/fevex-Ddyi6z6L.d.mts +60 -0
- package/dist/http/index.d.mts +90 -0
- package/dist/http/index.mjs +470 -0
- package/dist/{index-ojCY3lwm.d.mts → index-B4PIkqOU.d.mts} +5 -4
- package/dist/index-Bg9rr8Qe.d.mts +50 -0
- package/dist/index-Bgcxgy66.d.mts +82 -0
- package/dist/index-CTIwrVf9.d.mts +51 -0
- package/dist/index-CqOjvtQ9.d.mts +132 -0
- package/dist/index-CrOId2px.d.mts +66 -0
- package/dist/index-DeXUtyd9.d.mts +70 -0
- package/dist/index-DviHtsLo.d.mts +58 -0
- package/dist/index-Dx_LotWZ.d.mts +425 -0
- package/dist/{index-QTkd6a7C.d.mts → index-dkFyTNh4.d.mts} +4 -3
- package/dist/index.d.mts +22 -10
- package/dist/index.mjs +2784 -720
- package/dist/knowledge/index.d.mts +2 -0
- package/dist/knowledge/index.mjs +89 -0
- package/dist/models/index.d.mts +2 -46
- package/dist/observability/index.d.mts +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/policies/index.mjs +1 -1
- package/dist/run-error-Cr17wPGH.mjs +23 -0
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.mjs +58 -9
- package/dist/sandbox/index.d.mts +2 -0
- package/dist/sandbox/index.mjs +122 -0
- package/dist/teams/index.d.mts +2 -0
- package/dist/teams/index.mjs +2 -0
- package/dist/teams-Ctz676G4.mjs +82 -0
- package/dist/testing/index.d.mts +33 -9
- package/dist/testing/index.mjs +415 -27
- package/dist/tools/index.d.mts +3 -3
- package/dist/tools/index.mjs +222 -2
- package/dist/types-CuoRx12Q.d.mts +333 -0
- package/dist/workflows/index.d.mts +2 -0
- package/dist/workflows/index.mjs +6 -0
- package/package.json +27 -3
- package/dist/fevex-Dz6GBz9o.d.mts +0 -32
- package/dist/index-BzxHfyYV.d.mts +0 -23
- package/dist/index-CZGyhNIQ.d.mts +0 -47
- package/dist/index-C_Zpr13f.d.mts +0 -124
- package/dist/index-DGWOGXzc.d.mts +0 -181
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { t as FevexRunError } from "../run-error-Cr17wPGH.mjs";
|
|
2
|
+
//#region src/http/protocol.ts
|
|
3
|
+
const FEVEX_HTTP_PROTOCOL_VERSION = "3";
|
|
4
|
+
const FEVEX_HTTP_PROTOCOL_VERSION_HEADER = "Fevex-Protocol-Version";
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/http/transport.ts
|
|
7
|
+
const JSON_TYPE = "application/json";
|
|
8
|
+
const PROBLEM_TYPE = "application/problem+json";
|
|
9
|
+
const SSE_TYPE = "text/event-stream";
|
|
10
|
+
const FEVEX_RUN_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
11
|
+
"INVALID_CURSOR",
|
|
12
|
+
"AGENT_NOT_FOUND",
|
|
13
|
+
"WORKFLOW_NOT_FOUND",
|
|
14
|
+
"TEAM_NOT_FOUND",
|
|
15
|
+
"MODEL_NOT_FOUND",
|
|
16
|
+
"SESSION_NOT_FOUND",
|
|
17
|
+
"DURABLE_STORE_REQUIRED",
|
|
18
|
+
"RUN_CONFLICT",
|
|
19
|
+
"RUN_NOT_RESUMABLE",
|
|
20
|
+
"RUN_NOT_RECOVERABLE",
|
|
21
|
+
"CHECKPOINT_UNSUPPORTED",
|
|
22
|
+
"RUN_DEFINITION_CHANGED",
|
|
23
|
+
"POLICY_DENIED",
|
|
24
|
+
"CREDENTIAL_NOT_FOUND",
|
|
25
|
+
"SANDBOX_REQUIRED",
|
|
26
|
+
"ELICITATION_INVALID",
|
|
27
|
+
"APPROVAL_INVALID",
|
|
28
|
+
"RUN_PAUSED",
|
|
29
|
+
"TOOL_EXECUTION_UNKNOWN"
|
|
30
|
+
]);
|
|
31
|
+
/** Exposes a Fevex instance through the versioned HTTP protocol. */
|
|
32
|
+
function createFevexHttpHandler(options) {
|
|
33
|
+
const pollIntervalMs = options.pollIntervalMs ?? 100;
|
|
34
|
+
const eventPageSize = options.eventPageSize ?? 100;
|
|
35
|
+
if (!Number.isSafeInteger(eventPageSize) || eventPageSize < 1 || eventPageSize > 1e3) throw new TypeError("eventPageSize must be an integer between 1 and 1000");
|
|
36
|
+
if (!Number.isFinite(pollIntervalMs) || pollIntervalMs < 1) throw new TypeError("pollIntervalMs must be a positive number");
|
|
37
|
+
return async (request, handlerContext = {}) => {
|
|
38
|
+
const url = new URL(request.url);
|
|
39
|
+
const path = url.pathname;
|
|
40
|
+
try {
|
|
41
|
+
const start = path.match(/^\/v1\/agents\/([^/]+)\/runs$/);
|
|
42
|
+
if (start && request.method === "POST") {
|
|
43
|
+
const body = await readJson(request);
|
|
44
|
+
if (!hasOwn(body, "input")) throw badRequest("input is required");
|
|
45
|
+
const sessionId = optionalId(body.sessionId, "sessionId");
|
|
46
|
+
const model = optionalId(body.model, "model");
|
|
47
|
+
const reasoning = optionalReasoning(body.reasoning);
|
|
48
|
+
return json(await options.fevex.startAgent(decodeURIComponent(start[1]), {
|
|
49
|
+
input: body.input,
|
|
50
|
+
...model ? { model } : {},
|
|
51
|
+
...reasoning === void 0 ? {} : { reasoning },
|
|
52
|
+
...sessionId ? { sessionId } : {},
|
|
53
|
+
...handlerContext.context ? { context: handlerContext.context } : {}
|
|
54
|
+
}), 202);
|
|
55
|
+
}
|
|
56
|
+
const startWorkflow = path.match(/^\/v1\/workflows\/([^/]+)\/runs$/);
|
|
57
|
+
if (startWorkflow && request.method === "POST") {
|
|
58
|
+
const body = await readJson(request);
|
|
59
|
+
if (!hasOwn(body, "input")) throw badRequest("input is required");
|
|
60
|
+
const sessionId = optionalId(body.sessionId, "sessionId");
|
|
61
|
+
const model = optionalId(body.model, "model");
|
|
62
|
+
const reasoning = optionalReasoning(body.reasoning);
|
|
63
|
+
return json(await options.fevex.startWorkflow(decodeURIComponent(startWorkflow[1]), {
|
|
64
|
+
input: body.input,
|
|
65
|
+
...model ? { model } : {},
|
|
66
|
+
...reasoning === void 0 ? {} : { reasoning },
|
|
67
|
+
...sessionId ? { sessionId } : {},
|
|
68
|
+
...handlerContext.context ? { context: handlerContext.context } : {}
|
|
69
|
+
}), 202);
|
|
70
|
+
}
|
|
71
|
+
const startTeam = path.match(/^\/v1\/teams\/([^/]+)\/runs$/);
|
|
72
|
+
if (startTeam && request.method === "POST") {
|
|
73
|
+
const body = await readJson(request);
|
|
74
|
+
if (!hasOwn(body, "input")) throw badRequest("Run input is required");
|
|
75
|
+
const sessionId = optionalId(body.sessionId, "sessionId");
|
|
76
|
+
const model = optionalId(body.model, "model");
|
|
77
|
+
const reasoning = optionalReasoning(body.reasoning);
|
|
78
|
+
return json(await options.fevex.startTeam(decodeURIComponent(startTeam[1]), {
|
|
79
|
+
input: body.input,
|
|
80
|
+
...model ? { model } : {},
|
|
81
|
+
...reasoning === void 0 ? {} : { reasoning },
|
|
82
|
+
...sessionId ? { sessionId } : {},
|
|
83
|
+
...handlerContext.context ? { context: handlerContext.context } : {}
|
|
84
|
+
}), 202);
|
|
85
|
+
}
|
|
86
|
+
const events = path.match(/^\/v1\/runs\/([^/]+)\/events$/);
|
|
87
|
+
if (events && request.method === "GET") {
|
|
88
|
+
const runId = decodeURIComponent(events[1]);
|
|
89
|
+
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
90
|
+
const after = request.headers.get("last-event-id")?.trim() || void 0;
|
|
91
|
+
const initial = await options.fevex.listEvents(runId, {
|
|
92
|
+
after,
|
|
93
|
+
limit: eventPageSize
|
|
94
|
+
});
|
|
95
|
+
const disconnected = new AbortController();
|
|
96
|
+
const iterator = observeEvents(options.fevex, runId, initial, after, pollIntervalMs, AbortSignal.any([request.signal, disconnected.signal]), eventPageSize);
|
|
97
|
+
return versioned(new Response(iteratorStream(iterator, () => disconnected.abort()), { headers: {
|
|
98
|
+
"content-type": `${SSE_TYPE}; charset=utf-8`,
|
|
99
|
+
"cache-control": "no-cache, no-transform"
|
|
100
|
+
} }));
|
|
101
|
+
}
|
|
102
|
+
const resume = path.match(/^\/v1\/runs\/([^/]+)\/resume$/);
|
|
103
|
+
if (resume && request.method === "POST") {
|
|
104
|
+
const runId = decodeURIComponent(resume[1]);
|
|
105
|
+
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
106
|
+
const actor = handlerContext.context?.actor;
|
|
107
|
+
if (!actor?.id?.trim()) throw new HttpProtocolError(401, "ACTOR_REQUIRED", "Authenticated actor is required");
|
|
108
|
+
const resolution = readResolution(await readJson(request), actor);
|
|
109
|
+
return json(await options.fevex.resumeRun(runId, resolution), 202);
|
|
110
|
+
}
|
|
111
|
+
const recover = path.match(/^\/v1\/runs\/([^/]+)\/recover$/);
|
|
112
|
+
if (recover && request.method === "POST") {
|
|
113
|
+
const runId = decodeURIComponent(recover[1]);
|
|
114
|
+
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
115
|
+
const actor = handlerContext.context?.actor;
|
|
116
|
+
if (!actor?.id?.trim()) throw new HttpProtocolError(401, "ACTOR_REQUIRED", "Authenticated actor is required");
|
|
117
|
+
return json(await options.fevex.recoverRun(runId, { actor }), 202);
|
|
118
|
+
}
|
|
119
|
+
const run = path.match(/^\/v1\/runs\/([^/]+)$/);
|
|
120
|
+
if (run && request.method === "GET") {
|
|
121
|
+
const value = await options.fevex.getRun(decodeURIComponent(run[1]));
|
|
122
|
+
if (!value) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
123
|
+
return json(value);
|
|
124
|
+
}
|
|
125
|
+
if (run && request.method === "DELETE") {
|
|
126
|
+
const runId = decodeURIComponent(run[1]);
|
|
127
|
+
const value = await options.fevex.getRun(runId);
|
|
128
|
+
if (!value) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
129
|
+
if (value.status === "running" || value.status === "paused") {
|
|
130
|
+
if (!await options.fevex.cancelRun(runId) && (await options.fevex.getRun(runId))?.status === value.status) throw new HttpProtocolError(409, "RUN_CONFLICT", "Run could not be cancelled");
|
|
131
|
+
}
|
|
132
|
+
return versioned(new Response(null, { status: 204 }));
|
|
133
|
+
}
|
|
134
|
+
if (start || startWorkflow || startTeam || events || resume || recover || run) throw new HttpProtocolError(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
135
|
+
throw notFound("ROUTE_NOT_FOUND", "Route not found");
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return problem(error, url.pathname, options.onError);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
var FevexHttpError = class extends Error {
|
|
142
|
+
problem;
|
|
143
|
+
name = "FevexHttpError";
|
|
144
|
+
constructor(problem) {
|
|
145
|
+
super(problem.detail ?? problem.title);
|
|
146
|
+
this.problem = problem;
|
|
147
|
+
}
|
|
148
|
+
get status() {
|
|
149
|
+
return this.problem.status;
|
|
150
|
+
}
|
|
151
|
+
get code() {
|
|
152
|
+
return this.problem.code;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
function createFevexHttpClient(options) {
|
|
156
|
+
const baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
157
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
158
|
+
const request = async (path, init) => {
|
|
159
|
+
const response = await fetcher(`${baseUrl}${path}`, init);
|
|
160
|
+
await assertResponse(response, JSON_TYPE);
|
|
161
|
+
return response.json();
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
startRun(agentName, body) {
|
|
165
|
+
return request(`/v1/agents/${encodeURIComponent(agentName)}/runs`, jsonInit("POST", body));
|
|
166
|
+
},
|
|
167
|
+
startWorkflow(workflowName, body) {
|
|
168
|
+
return request(`/v1/workflows/${encodeURIComponent(workflowName)}/runs`, jsonInit("POST", body));
|
|
169
|
+
},
|
|
170
|
+
startTeam(teamName, body) {
|
|
171
|
+
return request(`/v1/teams/${encodeURIComponent(teamName)}/runs`, jsonInit("POST", body));
|
|
172
|
+
},
|
|
173
|
+
getRun(runId) {
|
|
174
|
+
return request(`/v1/runs/${encodeURIComponent(runId)}`);
|
|
175
|
+
},
|
|
176
|
+
observeRun(runId, observeOptions = {}) {
|
|
177
|
+
return { async *[Symbol.asyncIterator]() {
|
|
178
|
+
const response = await fetcher(`${baseUrl}/v1/runs/${encodeURIComponent(runId)}/events`, {
|
|
179
|
+
headers: observeOptions.after ? { "last-event-id": observeOptions.after } : void 0,
|
|
180
|
+
signal: observeOptions.signal
|
|
181
|
+
});
|
|
182
|
+
await assertResponse(response, SSE_TYPE);
|
|
183
|
+
if (!response.body) throw new TypeError("Fevex event response has no body");
|
|
184
|
+
yield* parseEventStream(response.body);
|
|
185
|
+
} };
|
|
186
|
+
},
|
|
187
|
+
resumeRun(runId, body) {
|
|
188
|
+
return request(`/v1/runs/${encodeURIComponent(runId)}/resume`, jsonInit("POST", body));
|
|
189
|
+
},
|
|
190
|
+
recoverRun(runId) {
|
|
191
|
+
return request(`/v1/runs/${encodeURIComponent(runId)}/recover`, { method: "POST" });
|
|
192
|
+
},
|
|
193
|
+
async cancelRun(runId) {
|
|
194
|
+
await assertResponse(await fetcher(`${baseUrl}/v1/runs/${encodeURIComponent(runId)}`, { method: "DELETE" }));
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async function* observeEvents(fevex, runId, initial, after, pollIntervalMs, signal, pageSize) {
|
|
199
|
+
const encoder = new TextEncoder();
|
|
200
|
+
let pending = initial;
|
|
201
|
+
let cursor = after;
|
|
202
|
+
let closedEmptyReads = 0;
|
|
203
|
+
while (!signal.aborted) {
|
|
204
|
+
for (const event of pending) {
|
|
205
|
+
if (signal.aborted) return;
|
|
206
|
+
cursor = event.id;
|
|
207
|
+
yield encoder.encode(formatEvent(event));
|
|
208
|
+
}
|
|
209
|
+
const run = await fevex.getRun(runId);
|
|
210
|
+
if (!run) return;
|
|
211
|
+
if (run.status !== "running" && pending.length === 0) {
|
|
212
|
+
closedEmptyReads += 1;
|
|
213
|
+
if (closedEmptyReads >= 2) return;
|
|
214
|
+
} else closedEmptyReads = 0;
|
|
215
|
+
if (pending.length < pageSize) await wait(pollIntervalMs, signal);
|
|
216
|
+
if (signal.aborted) return;
|
|
217
|
+
pending = await fevex.listEvents(runId, {
|
|
218
|
+
after: cursor,
|
|
219
|
+
limit: pageSize
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function iteratorStream(iterator, cancel) {
|
|
224
|
+
return new ReadableStream({
|
|
225
|
+
async pull(controller) {
|
|
226
|
+
try {
|
|
227
|
+
const next = await iterator.next();
|
|
228
|
+
if (next.done) controller.close();
|
|
229
|
+
else controller.enqueue(next.value);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
controller.error(error);
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
async cancel() {
|
|
235
|
+
cancel();
|
|
236
|
+
await iterator.return(void 0);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
async function* parseEventStream(body) {
|
|
241
|
+
const reader = body.getReader();
|
|
242
|
+
const decoder = new TextDecoder();
|
|
243
|
+
let buffer = "";
|
|
244
|
+
let finished = false;
|
|
245
|
+
try {
|
|
246
|
+
while (true) {
|
|
247
|
+
const { done, value } = await reader.read();
|
|
248
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
249
|
+
let boundary = findBoundary(buffer);
|
|
250
|
+
while (boundary) {
|
|
251
|
+
const frame = buffer.slice(0, boundary.index);
|
|
252
|
+
buffer = buffer.slice(boundary.index + boundary.length);
|
|
253
|
+
const data = frame.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
|
|
254
|
+
if (data) yield JSON.parse(data);
|
|
255
|
+
boundary = findBoundary(buffer);
|
|
256
|
+
}
|
|
257
|
+
if (done) {
|
|
258
|
+
if (buffer.trim()) throw new TypeError("Fevex event stream ended with an incomplete frame");
|
|
259
|
+
finished = true;
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} finally {
|
|
264
|
+
if (!finished) await reader.cancel();
|
|
265
|
+
reader.releaseLock();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function findBoundary(value) {
|
|
269
|
+
const lf = value.indexOf("\n\n");
|
|
270
|
+
const crlf = value.indexOf("\r\n\r\n");
|
|
271
|
+
if (lf < 0 && crlf < 0) return void 0;
|
|
272
|
+
return crlf >= 0 && (lf < 0 || crlf < lf) ? {
|
|
273
|
+
index: crlf,
|
|
274
|
+
length: 4
|
|
275
|
+
} : {
|
|
276
|
+
index: lf,
|
|
277
|
+
length: 2
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function formatEvent(event) {
|
|
281
|
+
return `id: ${event.id}\nevent: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`;
|
|
282
|
+
}
|
|
283
|
+
function readResolution(body, actor) {
|
|
284
|
+
if (body.type === "elicitation" && typeof body.requestId === "string" && body.requestId.trim() && hasOwn(body, "value")) return {
|
|
285
|
+
type: "elicitation",
|
|
286
|
+
requestId: body.requestId,
|
|
287
|
+
value: body.value,
|
|
288
|
+
actor
|
|
289
|
+
};
|
|
290
|
+
if (body.type === "approval" && typeof body.approvalId === "string" && (body.decision === "approve" || body.decision === "reject")) return {
|
|
291
|
+
type: "approval",
|
|
292
|
+
approvalId: body.approvalId,
|
|
293
|
+
decision: body.decision,
|
|
294
|
+
actor
|
|
295
|
+
};
|
|
296
|
+
if (body.type === "tool_execution" && typeof body.toolCallId === "string" && body.decision === "retry") return {
|
|
297
|
+
type: "tool_execution",
|
|
298
|
+
toolCallId: body.toolCallId,
|
|
299
|
+
decision: "retry",
|
|
300
|
+
actor
|
|
301
|
+
};
|
|
302
|
+
if (body.type === "tool_execution" && typeof body.toolCallId === "string" && body.decision === "use_output" && hasOwn(body, "output")) return {
|
|
303
|
+
type: "tool_execution",
|
|
304
|
+
toolCallId: body.toolCallId,
|
|
305
|
+
decision: "use_output",
|
|
306
|
+
output: body.output,
|
|
307
|
+
actor
|
|
308
|
+
};
|
|
309
|
+
if (body.type === "timer") return {
|
|
310
|
+
type: "timer",
|
|
311
|
+
actor
|
|
312
|
+
};
|
|
313
|
+
if (body.type === "event" && typeof body.eventName === "string" && body.eventName.trim()) return {
|
|
314
|
+
type: "event",
|
|
315
|
+
eventName: body.eventName,
|
|
316
|
+
...hasOwn(body, "payload") ? { payload: body.payload } : {},
|
|
317
|
+
actor
|
|
318
|
+
};
|
|
319
|
+
throw badRequest("Invalid run resolution");
|
|
320
|
+
}
|
|
321
|
+
async function readJson(request) {
|
|
322
|
+
if (!request.headers.get("content-type")?.toLowerCase().includes(JSON_TYPE)) throw new HttpProtocolError(415, "UNSUPPORTED_MEDIA_TYPE", "Expected application/json");
|
|
323
|
+
let value;
|
|
324
|
+
try {
|
|
325
|
+
value = await request.json();
|
|
326
|
+
} catch {
|
|
327
|
+
throw badRequest("Request body must be valid JSON");
|
|
328
|
+
}
|
|
329
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw badRequest("Request body must be a JSON object");
|
|
330
|
+
return value;
|
|
331
|
+
}
|
|
332
|
+
function optionalId(value, name) {
|
|
333
|
+
if (value === void 0) return void 0;
|
|
334
|
+
if (typeof value !== "string" || !value.trim()) throw badRequest(`${name} must be a string`);
|
|
335
|
+
return value.trim();
|
|
336
|
+
}
|
|
337
|
+
function optionalReasoning(value) {
|
|
338
|
+
if (value === void 0) return void 0;
|
|
339
|
+
if (typeof value !== "string" || ![
|
|
340
|
+
"provider-default",
|
|
341
|
+
"none",
|
|
342
|
+
"minimal",
|
|
343
|
+
"low",
|
|
344
|
+
"medium",
|
|
345
|
+
"high",
|
|
346
|
+
"xhigh",
|
|
347
|
+
"max"
|
|
348
|
+
].includes(value)) throw badRequest("reasoning must be a valid effort");
|
|
349
|
+
return value;
|
|
350
|
+
}
|
|
351
|
+
function hasOwn(value, key) {
|
|
352
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
353
|
+
}
|
|
354
|
+
function jsonInit(method, body) {
|
|
355
|
+
return {
|
|
356
|
+
method,
|
|
357
|
+
headers: { "content-type": JSON_TYPE },
|
|
358
|
+
body: JSON.stringify(body)
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
function json(value, status = 200) {
|
|
362
|
+
return versioned(Response.json(value, {
|
|
363
|
+
status,
|
|
364
|
+
headers: { "content-type": JSON_TYPE }
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
function versioned(response) {
|
|
368
|
+
response.headers.set(FEVEX_HTTP_PROTOCOL_VERSION_HEADER, "3");
|
|
369
|
+
return response;
|
|
370
|
+
}
|
|
371
|
+
async function assertResponse(response, contentType) {
|
|
372
|
+
const version = response.headers.get(FEVEX_HTTP_PROTOCOL_VERSION_HEADER);
|
|
373
|
+
if (version !== "3") throw new TypeError(`Unsupported Fevex HTTP protocol version "${version ?? "missing"}"`);
|
|
374
|
+
if (!response.ok) {
|
|
375
|
+
if (!response.headers.get("content-type")?.includes(PROBLEM_TYPE)) throw new TypeError(`Expected ${PROBLEM_TYPE} response`);
|
|
376
|
+
const value = await response.json().catch(() => void 0);
|
|
377
|
+
if (!isProblemDetails(value)) throw new TypeError("Invalid Fevex Problem Details response");
|
|
378
|
+
throw new FevexHttpError(value);
|
|
379
|
+
}
|
|
380
|
+
if (contentType && !response.headers.get("content-type")?.includes(contentType)) throw new TypeError(`Expected ${contentType} response`);
|
|
381
|
+
}
|
|
382
|
+
function isProblemDetails(value) {
|
|
383
|
+
if (!value || typeof value !== "object") return false;
|
|
384
|
+
const problem = value;
|
|
385
|
+
return typeof problem.type === "string" && typeof problem.title === "string" && typeof problem.status === "number" && typeof problem.code === "string" && (problem.detail === void 0 || typeof problem.detail === "string") && (problem.instance === void 0 || typeof problem.instance === "string");
|
|
386
|
+
}
|
|
387
|
+
var HttpProtocolError = class extends Error {
|
|
388
|
+
status;
|
|
389
|
+
code;
|
|
390
|
+
constructor(status, code, message) {
|
|
391
|
+
super(message);
|
|
392
|
+
this.status = status;
|
|
393
|
+
this.code = code;
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
function badRequest(message, code = "INVALID_REQUEST") {
|
|
397
|
+
return new HttpProtocolError(400, code, message);
|
|
398
|
+
}
|
|
399
|
+
function notFound(code, message) {
|
|
400
|
+
return new HttpProtocolError(404, code, message);
|
|
401
|
+
}
|
|
402
|
+
function problem(error, instance, onError) {
|
|
403
|
+
let status = 500;
|
|
404
|
+
let code = "INTERNAL_ERROR";
|
|
405
|
+
let title = "Internal Server Error";
|
|
406
|
+
let detail;
|
|
407
|
+
if (error instanceof HttpProtocolError) {
|
|
408
|
+
({status, code} = error);
|
|
409
|
+
title = error.message;
|
|
410
|
+
detail = error.message;
|
|
411
|
+
} else {
|
|
412
|
+
const runError = readFevexRunError(error);
|
|
413
|
+
if (runError) {
|
|
414
|
+
code = runError.code;
|
|
415
|
+
status = statusForRunErrorCode(runError.code);
|
|
416
|
+
title = titleForStatus(status);
|
|
417
|
+
detail = runError.message;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const value = {
|
|
421
|
+
type: `urn:fevex:problem:${code.toLowerCase()}`,
|
|
422
|
+
title,
|
|
423
|
+
status,
|
|
424
|
+
code,
|
|
425
|
+
...detail ? { detail } : {},
|
|
426
|
+
instance
|
|
427
|
+
};
|
|
428
|
+
if (status >= 500) try {
|
|
429
|
+
onError?.(error, value);
|
|
430
|
+
} catch {}
|
|
431
|
+
return versioned(new Response(JSON.stringify(value), {
|
|
432
|
+
status,
|
|
433
|
+
headers: { "content-type": PROBLEM_TYPE }
|
|
434
|
+
}));
|
|
435
|
+
}
|
|
436
|
+
function readFevexRunError(error) {
|
|
437
|
+
if (error instanceof FevexRunError) return error;
|
|
438
|
+
if (!error || typeof error !== "object") return void 0;
|
|
439
|
+
const value = error;
|
|
440
|
+
return typeof value.message === "string" && typeof value.code === "string" && FEVEX_RUN_ERROR_CODES.has(value.code) ? {
|
|
441
|
+
code: value.code,
|
|
442
|
+
message: value.message
|
|
443
|
+
} : void 0;
|
|
444
|
+
}
|
|
445
|
+
function statusForRunErrorCode(code) {
|
|
446
|
+
if (code === "AGENT_NOT_FOUND" || code === "WORKFLOW_NOT_FOUND" || code === "TEAM_NOT_FOUND" || code === "SESSION_NOT_FOUND") return 404;
|
|
447
|
+
if (code === "APPROVAL_INVALID" || code === "INVALID_CURSOR") return 400;
|
|
448
|
+
if (code === "POLICY_DENIED") return 403;
|
|
449
|
+
return 409;
|
|
450
|
+
}
|
|
451
|
+
function titleForStatus(status) {
|
|
452
|
+
if (status === 404) return "Not Found";
|
|
453
|
+
if (status === 400) return "Bad Request";
|
|
454
|
+
if (status === 403) return "Forbidden";
|
|
455
|
+
return "Conflict";
|
|
456
|
+
}
|
|
457
|
+
function wait(ms, signal) {
|
|
458
|
+
return new Promise((resolve) => {
|
|
459
|
+
const timeout = setTimeout(finish, ms);
|
|
460
|
+
function finish() {
|
|
461
|
+
clearTimeout(timeout);
|
|
462
|
+
signal.removeEventListener("abort", finish);
|
|
463
|
+
resolve();
|
|
464
|
+
}
|
|
465
|
+
if (signal.aborted) finish();
|
|
466
|
+
else signal.addEventListener("abort", finish, { once: true });
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
//#endregion
|
|
470
|
+
export { FEVEX_HTTP_PROTOCOL_VERSION, FEVEX_HTTP_PROTOCOL_VERSION_HEADER, FevexHttpError, createFevexHttpClient, createFevexHttpHandler };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { f as RunId, l as JsonValue, s as JsonObject } from "./
|
|
2
|
-
import { ModelMetadata, ModelUsage } from "./
|
|
3
|
-
import {
|
|
4
|
-
//#region src/observability/
|
|
1
|
+
import { f as RunId, l as JsonValue, s as JsonObject } from "./types-CuoRx12Q.mjs";
|
|
2
|
+
import { r as ModelMetadata, s as ModelUsage } from "./index-CTIwrVf9.mjs";
|
|
3
|
+
import { M as SessionId } from "./index-Dx_LotWZ.mjs";
|
|
4
|
+
//#region src/observability/trace.d.ts
|
|
5
|
+
/** Final state represented by an exported run trace. */
|
|
5
6
|
type TraceStatus = 'completed' | 'failed' | 'cancelled';
|
|
6
7
|
type TraceSpanKind = 'model' | 'tool';
|
|
7
8
|
type TraceContentKind = 'run.output' | 'model.output' | 'error.message';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { t as ExactDefinition } from "./exact-definition-NHBBFlFR.mjs";
|
|
2
|
+
import { o as ExecutionContext } from "./types-CuoRx12Q.mjs";
|
|
3
|
+
import { n as AgentLimits } from "./index-Dx_LotWZ.mjs";
|
|
4
|
+
import { t as WorkflowAgentResult } from "./index-DviHtsLo.mjs";
|
|
5
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
6
|
+
//#region src/teams/team.d.ts
|
|
7
|
+
interface TeamMember {
|
|
8
|
+
agent: string;
|
|
9
|
+
role: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
12
|
+
interface TeamLimits extends AgentLimits {
|
|
13
|
+
maxDelegations?: number;
|
|
14
|
+
maxParallel?: number;
|
|
15
|
+
}
|
|
16
|
+
interface TeamDelegation<TInput = unknown> {
|
|
17
|
+
agent: string;
|
|
18
|
+
task: TInput;
|
|
19
|
+
context?: ExecutionContext;
|
|
20
|
+
limits?: AgentLimits;
|
|
21
|
+
expectedOutput?: string;
|
|
22
|
+
constraints?: string[];
|
|
23
|
+
}
|
|
24
|
+
interface TeamHandoff<TInput = unknown> extends Omit<TeamDelegation<TInput>, 'agent'> {
|
|
25
|
+
from: string;
|
|
26
|
+
to: string;
|
|
27
|
+
reason: string;
|
|
28
|
+
}
|
|
29
|
+
type TeamTaskResult<TOutput = unknown> = WorkflowAgentResult<TOutput> & {
|
|
30
|
+
delegationId: string;
|
|
31
|
+
agentName: string;
|
|
32
|
+
};
|
|
33
|
+
interface TeamStep {
|
|
34
|
+
delegate<TInput = unknown, TOutput = unknown>(delegationId: string, delegation: TeamDelegation<TInput>): Promise<TeamTaskResult<TOutput>>;
|
|
35
|
+
handoff<TInput = unknown, TOutput = unknown>(delegationId: string, handoff: TeamHandoff<TInput>): Promise<TeamTaskResult<TOutput>>;
|
|
36
|
+
parallel<TTasks extends Record<string, () => Promise<unknown>>>(stepId: string, tasks: TTasks): Promise<{ [TKey in keyof TTasks]: Awaited<ReturnType<TTasks[TKey]>>; }>;
|
|
37
|
+
}
|
|
38
|
+
interface TeamDefinition<TInput = unknown, TOutput = unknown> {
|
|
39
|
+
name: string;
|
|
40
|
+
version?: string;
|
|
41
|
+
supervisor: string;
|
|
42
|
+
members: TeamMember[];
|
|
43
|
+
limits?: TeamLimits;
|
|
44
|
+
inputSchema?: StandardSchemaV1<unknown, TInput>;
|
|
45
|
+
outputSchema?: StandardSchemaV1<unknown, TOutput>;
|
|
46
|
+
run(team: TeamStep, input: TInput): TOutput | Promise<TOutput>;
|
|
47
|
+
}
|
|
48
|
+
declare function defineTeam<T extends TeamDefinition>(team: ExactDefinition<T, TeamDefinition>): T;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { TeamMember as a, defineTeam as c, TeamLimits as i, TeamDelegation as n, TeamStep as o, TeamHandoff as r, TeamTaskResult as s, TeamDefinition as t };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { o as ExecutionContext, s as JsonObject, t as AgentEvent } from "./types-CuoRx12Q.mjs";
|
|
2
|
+
import { M as SessionId, a as AgentRun, h as ElicitationRequest } from "./index-Dx_LotWZ.mjs";
|
|
3
|
+
import { t as Fevex } from "./fevex-Ddyi6z6L.mjs";
|
|
4
|
+
//#region src/channels/channel.d.ts
|
|
5
|
+
interface ChannelMessage {
|
|
6
|
+
id: string;
|
|
7
|
+
deliveryId: string;
|
|
8
|
+
conversationId: string;
|
|
9
|
+
threadId?: string;
|
|
10
|
+
content: string;
|
|
11
|
+
actor?: ExecutionContext['actor'];
|
|
12
|
+
metadata?: JsonObject;
|
|
13
|
+
}
|
|
14
|
+
interface ChannelOutput {
|
|
15
|
+
deliveryId: string;
|
|
16
|
+
conversationId: string;
|
|
17
|
+
threadId?: string;
|
|
18
|
+
content: string;
|
|
19
|
+
metadata?: JsonObject;
|
|
20
|
+
}
|
|
21
|
+
interface ChannelContext {
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}
|
|
24
|
+
interface ChannelAdapter<TInput = unknown, TOutput = unknown> {
|
|
25
|
+
name: string;
|
|
26
|
+
parse(input: TInput, context: ChannelContext): Promise<ChannelMessage | null>;
|
|
27
|
+
deliver(output: ChannelOutput, context: ChannelContext): Promise<TOutput>;
|
|
28
|
+
deliverElicitation?(request: ElicitationRequest, context: ChannelContext): Promise<TOutput>;
|
|
29
|
+
}
|
|
30
|
+
type ChannelEventType = 'channel.received' | 'channel.delivered' | 'channel.failed';
|
|
31
|
+
type ChannelFailurePhase = 'parse' | 'run' | 'deliver';
|
|
32
|
+
interface ChannelEventBase {
|
|
33
|
+
id: string;
|
|
34
|
+
timestamp: string;
|
|
35
|
+
adapter: string;
|
|
36
|
+
messageId?: string;
|
|
37
|
+
deliveryId?: string;
|
|
38
|
+
conversationId?: string;
|
|
39
|
+
threadId?: string;
|
|
40
|
+
}
|
|
41
|
+
type ChannelEvent = (ChannelEventBase & {
|
|
42
|
+
type: 'channel.received';
|
|
43
|
+
actor?: ExecutionContext['actor'];
|
|
44
|
+
}) | (ChannelEventBase & {
|
|
45
|
+
type: 'channel.delivered';
|
|
46
|
+
}) | (ChannelEventBase & {
|
|
47
|
+
type: 'channel.failed';
|
|
48
|
+
phase: ChannelFailurePhase;
|
|
49
|
+
error: string;
|
|
50
|
+
});
|
|
51
|
+
type ChannelRunEvent = ChannelEvent | AgentEvent;
|
|
52
|
+
declare class ChannelError extends Error {
|
|
53
|
+
readonly code: string;
|
|
54
|
+
readonly safeMessage: string;
|
|
55
|
+
readonly name = "ChannelError";
|
|
56
|
+
constructor(code: string, safeMessage: string, options?: ErrorOptions);
|
|
57
|
+
}
|
|
58
|
+
interface ChannelRunOptions<TInput = unknown, TDelivery = unknown> {
|
|
59
|
+
fevex: Fevex;
|
|
60
|
+
adapter: ChannelAdapter<TInput, TDelivery>;
|
|
61
|
+
agentName: string;
|
|
62
|
+
resolveSessionId?: (message: ChannelMessage) => SessionId | undefined | Promise<SessionId | undefined>;
|
|
63
|
+
onEvent?: (event: ChannelEvent) => void;
|
|
64
|
+
signal?: AbortSignal;
|
|
65
|
+
}
|
|
66
|
+
type ChannelRunResult<TDelivery = unknown> = {
|
|
67
|
+
ignored: true;
|
|
68
|
+
events: ChannelRunEvent[];
|
|
69
|
+
} | {
|
|
70
|
+
ignored: false;
|
|
71
|
+
message: ChannelMessage;
|
|
72
|
+
run: AgentRun;
|
|
73
|
+
output: ChannelOutput;
|
|
74
|
+
delivery: TDelivery;
|
|
75
|
+
events: ChannelRunEvent[];
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/channels/handle-channel-input.d.ts
|
|
79
|
+
/** Parses one channel input, runs the configured agent, and delivers its output. */
|
|
80
|
+
declare function handleChannelInput<TInput, TDelivery>(input: TInput, options: ChannelRunOptions<TInput, TDelivery>): Promise<ChannelRunResult<TDelivery>>;
|
|
81
|
+
//#endregion
|
|
82
|
+
export { ChannelEvent as a, ChannelMessage as c, ChannelRunOptions as d, ChannelRunResult as f, ChannelError as i, ChannelOutput as l, ChannelAdapter as n, ChannelEventType as o, ChannelContext as r, ChannelFailurePhase as s, handleChannelInput as t, ChannelRunEvent as u };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { g as ToolSpec, i as AgentMessage, l as JsonValue, m as ToolCall, s as JsonObject } from "./types-CuoRx12Q.mjs";
|
|
2
|
+
//#region src/models/model.d.ts
|
|
3
|
+
/** Provider-neutral reasoning levels accepted by model gateways. */
|
|
4
|
+
type ReasoningEffort = 'provider-default' | 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
5
|
+
interface ModelUsage {
|
|
6
|
+
inputTokens?: number;
|
|
7
|
+
outputTokens?: number;
|
|
8
|
+
totalTokens?: number;
|
|
9
|
+
}
|
|
10
|
+
type ToolChoice = 'auto' | 'required' | 'none' | {
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
interface ModelInput {
|
|
14
|
+
messages: AgentMessage[];
|
|
15
|
+
tools?: ToolSpec[];
|
|
16
|
+
toolChoice?: ToolChoice;
|
|
17
|
+
reasoning?: ReasoningEffort;
|
|
18
|
+
modelOptions?: Record<string, unknown>;
|
|
19
|
+
outputSchema?: JsonObject;
|
|
20
|
+
maxOutputTokens?: number;
|
|
21
|
+
providerState?: unknown;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}
|
|
24
|
+
interface ModelResult<TOutput = unknown> {
|
|
25
|
+
output?: TOutput;
|
|
26
|
+
toolCalls?: ToolCall[];
|
|
27
|
+
usage?: ModelUsage;
|
|
28
|
+
providerState?: unknown;
|
|
29
|
+
}
|
|
30
|
+
interface ModelMetadata {
|
|
31
|
+
provider?: string;
|
|
32
|
+
model?: string;
|
|
33
|
+
}
|
|
34
|
+
interface ModelGateway {
|
|
35
|
+
stream(input: ModelInput): AsyncIterable<ModelStreamEvent>;
|
|
36
|
+
metadata?: ModelMetadata;
|
|
37
|
+
stateCodec?: {
|
|
38
|
+
serialize(state: unknown): JsonValue;
|
|
39
|
+
restore(state: JsonValue): unknown;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
type ModelStreamEvent<TOutput = unknown> = {
|
|
43
|
+
type: 'output.delta';
|
|
44
|
+
delta: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'completed';
|
|
47
|
+
result: ModelResult<TOutput>;
|
|
48
|
+
};
|
|
49
|
+
type ModelRef = string | ModelGateway;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { ModelResult as a, ReasoningEffort as c, ModelRef as i, ToolChoice as l, ModelInput as n, ModelStreamEvent as o, ModelMetadata as r, ModelUsage as s, ModelGateway as t };
|