@fevex/core 0.1.0-alpha.4 → 0.1.0-alpha.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/README.md +167 -2
- package/dist/agents/index.d.mts +1 -1
- package/dist/artifacts/index.d.mts +2 -0
- package/dist/artifacts/index.mjs +2 -0
- package/dist/artifacts-gUzemET7.mjs +440 -0
- package/dist/channels/index.d.mts +1 -1
- package/dist/evals/index.d.mts +4 -4
- package/dist/{fevex-BoPbZ-Tw.d.mts → fevex-B5NxFKcV.d.mts} +41 -11
- package/dist/http/index.d.mts +65 -5
- package/dist/http/index.mjs +236 -16
- package/dist/{index-DyyNLuwO.d.mts → index--_LdSEuF.d.mts} +3 -3
- package/dist/{index-CrOId2px.d.mts → index-BFnWUu7j.d.mts} +1 -1
- package/dist/{index-CTIwrVf9.d.mts → index-BPwkgdo3.d.mts} +1 -1
- package/dist/{index-CknU-glw.d.mts → index-Br-zPxZH.d.mts} +2 -2
- package/dist/{index-CaE864Kz.d.mts → index-CGmHXV31.d.mts} +35 -3
- package/dist/{index-CqOjvtQ9.d.mts → index-CKQCNvJz.d.mts} +4 -2
- package/dist/{index-dkFyTNh4.d.mts → index-Cb3AB98n.d.mts} +2 -2
- package/dist/{index-voIZhQXB.d.mts → index-D6lnI92z.d.mts} +3 -3
- package/dist/{index-C-IFfCNw.d.mts → index-Dsulk-n6.d.mts} +3 -3
- package/dist/{index-hhbgvfIt.d.mts → index-aayvtf0J.d.mts} +2 -2
- package/dist/index.d.mts +13 -13
- package/dist/index.mjs +444 -95
- package/dist/knowledge/index.d.mts +1 -1
- package/dist/model-stream-JQdHDDcj.mjs +131 -0
- package/dist/models/index.d.mts +1 -1
- package/dist/observability/index.d.mts +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/{model-stream-u2xMsEaf.mjs → run-support-CmZ6Xo6H.mjs} +41 -130
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.mjs +43 -1
- package/dist/sandbox/index.d.mts +1 -1
- package/dist/sandbox/index.mjs +1 -1
- package/dist/teams/index.d.mts +1 -1
- package/dist/testing/index.d.mts +8 -7
- package/dist/testing/index.mjs +94 -2
- package/dist/tools/index.d.mts +2 -2
- package/dist/types-BDVUoAU6.d.mts +559 -0
- package/dist/workflows/index.d.mts +1 -1
- package/package.json +6 -2
- package/dist/types-CuoRx12Q.d.mts +0 -333
|
@@ -1,14 +1,39 @@
|
|
|
1
|
-
import { f as RunId, t as AgentEvent } from "./types-
|
|
2
|
-
import { t as ModelGateway } from "./index-
|
|
3
|
-
import { A as
|
|
4
|
-
import { r as ContextProvider, s as MemoryStore } from "./index-
|
|
5
|
-
import { r as ObservabilityOptions } from "./index-
|
|
6
|
-
import { r as Sandbox } from "./index-
|
|
7
|
-
import { g as ToolDefinition, s as ConnectionDefinition } from "./index-
|
|
8
|
-
import { r as PolicyDefinition } from "./index-
|
|
9
|
-
import { n as WorkflowDefinition } from "./index-
|
|
10
|
-
import { t as TeamDefinition } from "./index-
|
|
1
|
+
import { F as ArtifactStore, f as RunId, o as ExecutionContext, t as AgentEvent } from "./types-BDVUoAU6.mjs";
|
|
2
|
+
import { t as ModelGateway } from "./index-BPwkgdo3.mjs";
|
|
3
|
+
import { A as RunRecord, C as PurgeRunsResult, F as Session, I as SessionId, M as RunResult, P as RunStore, S as PurgeRunsOptions, a as AgentRun, b as ListEventsOptions, f as CredentialStore, j as RunRequest, q as WorkflowRun, t as AgentDefinition, w as ResumeRunResolution, z as TeamRun } from "./index-CGmHXV31.mjs";
|
|
4
|
+
import { r as ContextProvider, s as MemoryStore } from "./index-aayvtf0J.mjs";
|
|
5
|
+
import { r as ObservabilityOptions } from "./index-D6lnI92z.mjs";
|
|
6
|
+
import { r as Sandbox } from "./index-BFnWUu7j.mjs";
|
|
7
|
+
import { g as ToolDefinition, s as ConnectionDefinition } from "./index-CKQCNvJz.mjs";
|
|
8
|
+
import { r as PolicyDefinition } from "./index-Cb3AB98n.mjs";
|
|
9
|
+
import { n as WorkflowDefinition } from "./index-Br-zPxZH.mjs";
|
|
10
|
+
import { t as TeamDefinition } from "./index-Dsulk-n6.mjs";
|
|
11
11
|
//#region src/fevex.d.ts
|
|
12
|
+
interface FevexAdmissionRequest {
|
|
13
|
+
kind: 'agent' | 'workflow' | 'team';
|
|
14
|
+
name: string;
|
|
15
|
+
request: RunRequest;
|
|
16
|
+
activeRuns: number;
|
|
17
|
+
activeTenantRuns: number;
|
|
18
|
+
}
|
|
19
|
+
/** Optional host-level admission controls applied before a top-level run starts. */
|
|
20
|
+
interface FevexAdmission {
|
|
21
|
+
/** Maximum concurrent top-level runs in this runtime. */
|
|
22
|
+
maxActiveRuns?: number;
|
|
23
|
+
/** Maximum concurrent top-level runs for one tenant. */
|
|
24
|
+
maxActiveRunsPerTenant?: number;
|
|
25
|
+
/** Defaults to a non-empty `context.attributes.tenantId` string. */
|
|
26
|
+
tenantKey?: (context?: ExecutionContext) => string | undefined;
|
|
27
|
+
/** Custom admission check, called after the built-in limits. */
|
|
28
|
+
authorize?: (request: FevexAdmissionRequest) => boolean | Promise<boolean>;
|
|
29
|
+
}
|
|
30
|
+
interface FevexLimits {
|
|
31
|
+
/**
|
|
32
|
+
* Maximum non-control events persisted for one run. Control events such as
|
|
33
|
+
* pause, resume, approval and terminal transitions are always persisted.
|
|
34
|
+
*/
|
|
35
|
+
maxEventsPerRun?: number;
|
|
36
|
+
}
|
|
12
37
|
/** Provider-neutral definitions and adapters used to create one Fevex runtime. */
|
|
13
38
|
interface FevexConfig {
|
|
14
39
|
models: Record<string, ModelGateway>;
|
|
@@ -22,9 +47,13 @@ interface FevexConfig {
|
|
|
22
47
|
runStore?: RunStore;
|
|
23
48
|
credentialStore?: CredentialStore;
|
|
24
49
|
sandbox?: Sandbox;
|
|
50
|
+
/** Optional artifact store exposed to tools as `context.artifacts`. */
|
|
51
|
+
artifacts?: ArtifactStore;
|
|
25
52
|
policies?: PolicyDefinition[];
|
|
26
53
|
onEvent?: (event: AgentEvent) => void;
|
|
27
54
|
observability?: ObservabilityOptions;
|
|
55
|
+
admission?: FevexAdmission;
|
|
56
|
+
limits?: FevexLimits;
|
|
28
57
|
}
|
|
29
58
|
interface Fevex {
|
|
30
59
|
startAgent<TInput = unknown, TOutput = unknown>(name: string, request: RunRequest<TInput, TOutput>): Promise<AgentRun<TOutput>>;
|
|
@@ -46,6 +75,7 @@ interface Fevex {
|
|
|
46
75
|
type?: string;
|
|
47
76
|
};
|
|
48
77
|
}): Promise<RunRecord<TOutput>>;
|
|
78
|
+
purgeRuns(options?: PurgeRunsOptions): Promise<PurgeRunsResult>;
|
|
49
79
|
compactSession(sessionId: SessionId, summary: string): Promise<Session>;
|
|
50
80
|
flushObservability(): Promise<void>;
|
|
51
81
|
}
|
|
@@ -57,4 +87,4 @@ interface Fevex {
|
|
|
57
87
|
*/
|
|
58
88
|
declare function createFevex(config: FevexConfig): Fevex;
|
|
59
89
|
//#endregion
|
|
60
|
-
export { FevexConfig as n, createFevex as r, Fevex as t };
|
|
90
|
+
export { FevexLimits as a, FevexConfig as i, FevexAdmission as n, createFevex as o, FevexAdmissionRequest as r, Fevex as t };
|
package/dist/http/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { l as JsonValue, o as ExecutionContext, t as AgentEvent } from "../types-
|
|
2
|
-
import { c as ReasoningEffort } from "../index-
|
|
3
|
-
import {
|
|
4
|
-
import { t as Fevex } from "../fevex-
|
|
1
|
+
import { D as ArtifactCatalog, F as ArtifactStore, f as RunId, k as ArtifactDescriptor, l as JsonValue, o as ExecutionContext, t as AgentEvent } from "../types-BDVUoAU6.mjs";
|
|
2
|
+
import { c as ReasoningEffort } from "../index-BPwkgdo3.mjs";
|
|
3
|
+
import { A as RunRecord, I as SessionId, a as AgentRun, q as WorkflowRun, z as TeamRun } from "../index-CGmHXV31.mjs";
|
|
4
|
+
import { t as Fevex } from "../fevex-B5NxFKcV.mjs";
|
|
5
5
|
//#region src/http/protocol.d.ts
|
|
6
6
|
declare const FEVEX_HTTP_PROTOCOL_VERSION = "3";
|
|
7
7
|
declare const FEVEX_HTTP_PROTOCOL_VERSION_HEADER = "Fevex-Protocol-Version";
|
|
@@ -10,6 +10,8 @@ interface StartRunHttpRequest<TInput extends JsonValue = JsonValue> {
|
|
|
10
10
|
model?: string;
|
|
11
11
|
reasoning?: ReasoningEffort;
|
|
12
12
|
sessionId?: SessionId;
|
|
13
|
+
/** Maximum wall-clock time for the run, including time spent paused. */
|
|
14
|
+
deadlineMs?: number;
|
|
13
15
|
}
|
|
14
16
|
type ResumeRunHttpRequest = {
|
|
15
17
|
type: 'elicitation';
|
|
@@ -47,11 +49,66 @@ interface FevexProblemDetails {
|
|
|
47
49
|
interface FevexHttpHandlerContext {
|
|
48
50
|
context?: ExecutionContext;
|
|
49
51
|
}
|
|
52
|
+
/** Host-facing resource access check. */
|
|
53
|
+
type FevexHttpAccess = {
|
|
54
|
+
action: 'start';
|
|
55
|
+
kind: 'agent' | 'workflow' | 'team';
|
|
56
|
+
name: string;
|
|
57
|
+
sessionId?: SessionId;
|
|
58
|
+
context?: ExecutionContext;
|
|
59
|
+
} | {
|
|
60
|
+
action: 'read' | 'observe' | 'cancel' | 'resume' | 'recover';
|
|
61
|
+
runId: RunId;
|
|
62
|
+
context?: ExecutionContext;
|
|
63
|
+
};
|
|
64
|
+
/** Host-facing artifact access check. */
|
|
65
|
+
type FevexArtifactAccess = {
|
|
66
|
+
action: 'read' | 'delete';
|
|
67
|
+
kind: 'artifact';
|
|
68
|
+
artifactId: string;
|
|
69
|
+
context?: ExecutionContext;
|
|
70
|
+
} | {
|
|
71
|
+
action: 'read';
|
|
72
|
+
kind: 'artifacts';
|
|
73
|
+
runId: RunId;
|
|
74
|
+
context?: ExecutionContext;
|
|
75
|
+
};
|
|
50
76
|
interface FevexHttpHandlerOptions {
|
|
51
77
|
fevex: Fevex;
|
|
52
78
|
pollIntervalMs?: number;
|
|
53
79
|
/** Events per SSE read (default 100, maximum 1000). */
|
|
54
80
|
eventPageSize?: number;
|
|
81
|
+
/** Maximum concurrent SSE streams (default unlimited). */
|
|
82
|
+
maxConnections?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Authorizes a resource operation before the handler reads or mutates a run,
|
|
85
|
+
* or starts a run (new or existing session). Return false for a 403 response.
|
|
86
|
+
* Omit to preserve the host's existing trusted-network behavior.
|
|
87
|
+
*/
|
|
88
|
+
authorize?: (access: FevexHttpAccess) => boolean | Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Byte store used by the artifact routes. When omitted, artifact routes
|
|
91
|
+
* return 501.
|
|
92
|
+
*/
|
|
93
|
+
artifacts?: ArtifactStore;
|
|
94
|
+
/**
|
|
95
|
+
* Metadata catalog used to list artifacts for a run. When omitted, the
|
|
96
|
+
* run-artifact listing route returns 501.
|
|
97
|
+
*/
|
|
98
|
+
artifactCatalog?: ArtifactCatalog;
|
|
99
|
+
/**
|
|
100
|
+
* Authorizes artifact reads, listings and deletions. Omit to preserve the
|
|
101
|
+
* host's existing trusted-network behavior.
|
|
102
|
+
*/
|
|
103
|
+
authorizeArtifact?: (access: FevexArtifactAccess) => boolean | Promise<boolean>;
|
|
104
|
+
/**
|
|
105
|
+
* Called after a run starts so the host can persist run and session ownership.
|
|
106
|
+
* If it throws, the handler cancels the new run and returns 500. A process
|
|
107
|
+
* crash between start and this callback leaves the run unowned; hosts must
|
|
108
|
+
* treat unowned runs as inaccessible. Runs created outside the HTTP handler
|
|
109
|
+
* are not reported.
|
|
110
|
+
*/
|
|
111
|
+
onRunStarted?: (run: RunRecord, context?: ExecutionContext) => void | Promise<void>;
|
|
55
112
|
onError?: (error: unknown, problem: FevexProblemDetails) => void;
|
|
56
113
|
}
|
|
57
114
|
type FevexHttpHandler = (request: Request, context?: FevexHttpHandlerContext) => Promise<Response>;
|
|
@@ -73,6 +130,9 @@ interface FevexHttpClient {
|
|
|
73
130
|
resumeRun<TOutput = JsonValue>(runId: string, request: ResumeRunHttpRequest): Promise<RunRecord<TOutput>>;
|
|
74
131
|
recoverRun<TOutput = JsonValue>(runId: string): Promise<RunRecord<TOutput>>;
|
|
75
132
|
cancelRun(runId: string): Promise<void>;
|
|
133
|
+
getArtifact(artifactId: string): Promise<Response>;
|
|
134
|
+
listArtifacts(runId: string): Promise<ArtifactDescriptor[]>;
|
|
135
|
+
deleteArtifact(artifactId: string): Promise<void>;
|
|
76
136
|
}
|
|
77
137
|
//#endregion
|
|
78
138
|
//#region src/http/transport.d.ts
|
|
@@ -87,4 +147,4 @@ declare class FevexHttpError extends Error {
|
|
|
87
147
|
}
|
|
88
148
|
declare function createFevexHttpClient(options: FevexHttpClientOptions): FevexHttpClient;
|
|
89
149
|
//#endregion
|
|
90
|
-
export { FEVEX_HTTP_PROTOCOL_VERSION, FEVEX_HTTP_PROTOCOL_VERSION_HEADER, FevexHttpClient, FevexHttpClientOptions, FevexHttpError, FevexHttpFetch, FevexHttpHandler, FevexHttpHandlerContext, FevexHttpHandlerOptions, FevexProblemDetails, ObserveRunOptions, ResumeRunHttpRequest, StartRunHttpRequest, createFevexHttpClient, createFevexHttpHandler };
|
|
150
|
+
export { FEVEX_HTTP_PROTOCOL_VERSION, FEVEX_HTTP_PROTOCOL_VERSION_HEADER, FevexArtifactAccess, FevexHttpAccess, FevexHttpClient, FevexHttpClientOptions, FevexHttpError, FevexHttpFetch, FevexHttpHandler, FevexHttpHandlerContext, FevexHttpHandlerOptions, FevexProblemDetails, ObserveRunOptions, ResumeRunHttpRequest, StartRunHttpRequest, createFevexHttpClient, createFevexHttpHandler };
|
package/dist/http/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { o as ArtifactError } from "../artifacts-gUzemET7.mjs";
|
|
1
2
|
import { t as FevexRunError } from "../run-error-Cr17wPGH.mjs";
|
|
3
|
+
import { t as MAX_DEADLINE_MS } from "../run-support-CmZ6Xo6H.mjs";
|
|
2
4
|
//#region src/http/protocol.ts
|
|
3
5
|
const FEVEX_HTTP_PROTOCOL_VERSION = "3";
|
|
4
6
|
const FEVEX_HTTP_PROTOCOL_VERSION_HEADER = "Fevex-Protocol-Version";
|
|
@@ -21,6 +23,7 @@ const FEVEX_RUN_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
21
23
|
"CHECKPOINT_UNSUPPORTED",
|
|
22
24
|
"RUN_DEFINITION_CHANGED",
|
|
23
25
|
"POLICY_DENIED",
|
|
26
|
+
"ADMISSION_DENIED",
|
|
24
27
|
"CREDENTIAL_NOT_FOUND",
|
|
25
28
|
"SANDBOX_REQUIRED",
|
|
26
29
|
"ELICITATION_INVALID",
|
|
@@ -32,69 +35,135 @@ const FEVEX_RUN_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
32
35
|
function createFevexHttpHandler(options) {
|
|
33
36
|
const pollIntervalMs = options.pollIntervalMs ?? 100;
|
|
34
37
|
const eventPageSize = options.eventPageSize ?? 100;
|
|
38
|
+
const maxConnections = options.maxConnections;
|
|
35
39
|
if (!Number.isSafeInteger(eventPageSize) || eventPageSize < 1 || eventPageSize > 1e3) throw new TypeError("eventPageSize must be an integer between 1 and 1000");
|
|
36
40
|
if (!Number.isFinite(pollIntervalMs) || pollIntervalMs < 1) throw new TypeError("pollIntervalMs must be a positive number");
|
|
41
|
+
if (maxConnections !== void 0 && (!Number.isSafeInteger(maxConnections) || maxConnections < 1)) throw new TypeError("maxConnections must be a positive safe integer");
|
|
42
|
+
let activeConnections = 0;
|
|
43
|
+
const authorize = async (access) => {
|
|
44
|
+
if (options.authorize && !await options.authorize(access)) throw new HttpProtocolError(403, "FORBIDDEN", "Forbidden");
|
|
45
|
+
};
|
|
46
|
+
const authorizeArtifact = async (access) => {
|
|
47
|
+
if (options.authorizeArtifact && !await options.authorizeArtifact(access)) throw new HttpProtocolError(403, "FORBIDDEN", "Forbidden");
|
|
48
|
+
};
|
|
37
49
|
return async (request, handlerContext = {}) => {
|
|
38
50
|
const url = new URL(request.url);
|
|
39
51
|
const path = url.pathname;
|
|
52
|
+
const commitStart = async (run) => {
|
|
53
|
+
try {
|
|
54
|
+
await options.onRunStarted?.(run, handlerContext.context);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
await options.fevex.cancelRun(run.id).catch(() => {});
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
40
60
|
try {
|
|
41
61
|
const start = path.match(/^\/v1\/agents\/([^/]+)\/runs$/);
|
|
42
62
|
if (start && request.method === "POST") {
|
|
43
63
|
const body = await readJson(request);
|
|
44
64
|
if (!hasOwn(body, "input")) throw badRequest("input is required");
|
|
65
|
+
const name = decodeURIComponent(start[1]);
|
|
45
66
|
const sessionId = optionalId(body.sessionId, "sessionId");
|
|
46
67
|
const model = optionalId(body.model, "model");
|
|
47
68
|
const reasoning = optionalReasoning(body.reasoning);
|
|
48
|
-
|
|
69
|
+
const deadlineMs = optionalDeadline(body.deadlineMs, "deadlineMs");
|
|
70
|
+
await authorize({
|
|
71
|
+
action: "start",
|
|
72
|
+
kind: "agent",
|
|
73
|
+
name,
|
|
74
|
+
sessionId,
|
|
75
|
+
context: handlerContext.context
|
|
76
|
+
});
|
|
77
|
+
const run = await options.fevex.startAgent(name, {
|
|
49
78
|
input: body.input,
|
|
50
79
|
...model ? { model } : {},
|
|
51
80
|
...reasoning === void 0 ? {} : { reasoning },
|
|
81
|
+
...deadlineMs === void 0 ? {} : { deadlineMs },
|
|
52
82
|
...sessionId ? { sessionId } : {},
|
|
53
83
|
...handlerContext.context ? { context: handlerContext.context } : {}
|
|
54
|
-
})
|
|
84
|
+
});
|
|
85
|
+
await commitStart(run);
|
|
86
|
+
return json(run, 202);
|
|
55
87
|
}
|
|
56
88
|
const startWorkflow = path.match(/^\/v1\/workflows\/([^/]+)\/runs$/);
|
|
57
89
|
if (startWorkflow && request.method === "POST") {
|
|
58
90
|
const body = await readJson(request);
|
|
59
91
|
if (!hasOwn(body, "input")) throw badRequest("input is required");
|
|
92
|
+
const name = decodeURIComponent(startWorkflow[1]);
|
|
60
93
|
const sessionId = optionalId(body.sessionId, "sessionId");
|
|
61
94
|
const model = optionalId(body.model, "model");
|
|
62
95
|
const reasoning = optionalReasoning(body.reasoning);
|
|
63
|
-
|
|
96
|
+
const deadlineMs = optionalDeadline(body.deadlineMs, "deadlineMs");
|
|
97
|
+
await authorize({
|
|
98
|
+
action: "start",
|
|
99
|
+
kind: "workflow",
|
|
100
|
+
name,
|
|
101
|
+
sessionId,
|
|
102
|
+
context: handlerContext.context
|
|
103
|
+
});
|
|
104
|
+
const run = await options.fevex.startWorkflow(name, {
|
|
64
105
|
input: body.input,
|
|
65
106
|
...model ? { model } : {},
|
|
66
107
|
...reasoning === void 0 ? {} : { reasoning },
|
|
108
|
+
...deadlineMs === void 0 ? {} : { deadlineMs },
|
|
67
109
|
...sessionId ? { sessionId } : {},
|
|
68
110
|
...handlerContext.context ? { context: handlerContext.context } : {}
|
|
69
|
-
})
|
|
111
|
+
});
|
|
112
|
+
await commitStart(run);
|
|
113
|
+
return json(run, 202);
|
|
70
114
|
}
|
|
71
115
|
const startTeam = path.match(/^\/v1\/teams\/([^/]+)\/runs$/);
|
|
72
116
|
if (startTeam && request.method === "POST") {
|
|
73
117
|
const body = await readJson(request);
|
|
74
118
|
if (!hasOwn(body, "input")) throw badRequest("Run input is required");
|
|
119
|
+
const name = decodeURIComponent(startTeam[1]);
|
|
75
120
|
const sessionId = optionalId(body.sessionId, "sessionId");
|
|
76
121
|
const model = optionalId(body.model, "model");
|
|
77
122
|
const reasoning = optionalReasoning(body.reasoning);
|
|
78
|
-
|
|
123
|
+
const deadlineMs = optionalDeadline(body.deadlineMs, "deadlineMs");
|
|
124
|
+
await authorize({
|
|
125
|
+
action: "start",
|
|
126
|
+
kind: "team",
|
|
127
|
+
name,
|
|
128
|
+
sessionId,
|
|
129
|
+
context: handlerContext.context
|
|
130
|
+
});
|
|
131
|
+
const run = await options.fevex.startTeam(name, {
|
|
79
132
|
input: body.input,
|
|
80
133
|
...model ? { model } : {},
|
|
81
134
|
...reasoning === void 0 ? {} : { reasoning },
|
|
135
|
+
...deadlineMs === void 0 ? {} : { deadlineMs },
|
|
82
136
|
...sessionId ? { sessionId } : {},
|
|
83
137
|
...handlerContext.context ? { context: handlerContext.context } : {}
|
|
84
|
-
})
|
|
138
|
+
});
|
|
139
|
+
await commitStart(run);
|
|
140
|
+
return json(run, 202);
|
|
85
141
|
}
|
|
86
142
|
const events = path.match(/^\/v1\/runs\/([^/]+)\/events$/);
|
|
87
143
|
if (events && request.method === "GET") {
|
|
88
144
|
const runId = decodeURIComponent(events[1]);
|
|
145
|
+
await authorize({
|
|
146
|
+
action: "observe",
|
|
147
|
+
runId,
|
|
148
|
+
context: handlerContext.context
|
|
149
|
+
});
|
|
89
150
|
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
90
151
|
const after = request.headers.get("last-event-id")?.trim() || void 0;
|
|
91
152
|
const initial = await options.fevex.listEvents(runId, {
|
|
92
153
|
after,
|
|
93
154
|
limit: eventPageSize
|
|
94
155
|
});
|
|
156
|
+
if (maxConnections !== void 0 && activeConnections >= maxConnections) throw new HttpProtocolError(429, "CONNECTION_LIMIT", "Too many event streams");
|
|
157
|
+
activeConnections += 1;
|
|
158
|
+
let released = false;
|
|
159
|
+
const release = () => {
|
|
160
|
+
if (released) return;
|
|
161
|
+
released = true;
|
|
162
|
+
activeConnections -= 1;
|
|
163
|
+
};
|
|
95
164
|
const disconnected = new AbortController();
|
|
96
165
|
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: {
|
|
166
|
+
return versioned(new Response(iteratorStream(iterator, () => disconnected.abort(), release), { headers: {
|
|
98
167
|
"content-type": `${SSE_TYPE}; charset=utf-8`,
|
|
99
168
|
"cache-control": "no-cache, no-transform"
|
|
100
169
|
} }));
|
|
@@ -102,28 +171,99 @@ function createFevexHttpHandler(options) {
|
|
|
102
171
|
const resume = path.match(/^\/v1\/runs\/([^/]+)\/resume$/);
|
|
103
172
|
if (resume && request.method === "POST") {
|
|
104
173
|
const runId = decodeURIComponent(resume[1]);
|
|
105
|
-
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
106
174
|
const actor = handlerContext.context?.actor;
|
|
107
175
|
if (!actor?.id?.trim()) throw new HttpProtocolError(401, "ACTOR_REQUIRED", "Authenticated actor is required");
|
|
176
|
+
await authorize({
|
|
177
|
+
action: "resume",
|
|
178
|
+
runId,
|
|
179
|
+
context: handlerContext.context
|
|
180
|
+
});
|
|
181
|
+
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
108
182
|
const resolution = readResolution(await readJson(request), actor);
|
|
109
183
|
return json(await options.fevex.resumeRun(runId, resolution), 202);
|
|
110
184
|
}
|
|
111
185
|
const recover = path.match(/^\/v1\/runs\/([^/]+)\/recover$/);
|
|
112
186
|
if (recover && request.method === "POST") {
|
|
113
187
|
const runId = decodeURIComponent(recover[1]);
|
|
114
|
-
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
115
188
|
const actor = handlerContext.context?.actor;
|
|
116
189
|
if (!actor?.id?.trim()) throw new HttpProtocolError(401, "ACTOR_REQUIRED", "Authenticated actor is required");
|
|
190
|
+
await authorize({
|
|
191
|
+
action: "recover",
|
|
192
|
+
runId,
|
|
193
|
+
context: handlerContext.context
|
|
194
|
+
});
|
|
195
|
+
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
117
196
|
return json(await options.fevex.recoverRun(runId, { actor }), 202);
|
|
118
197
|
}
|
|
198
|
+
const runArtifacts = path.match(/^\/v1\/runs\/([^/]+)\/artifacts$/);
|
|
199
|
+
if (runArtifacts && request.method === "GET") {
|
|
200
|
+
const runId = decodeURIComponent(runArtifacts[1]);
|
|
201
|
+
await authorizeArtifact({
|
|
202
|
+
action: "read",
|
|
203
|
+
kind: "artifacts",
|
|
204
|
+
runId,
|
|
205
|
+
context: handlerContext.context
|
|
206
|
+
});
|
|
207
|
+
if (!options.artifactCatalog) throw new HttpProtocolError(501, "ARTIFACT_CATALOG_NOT_CONFIGURED", "Artifact catalog is not configured");
|
|
208
|
+
if (!await options.fevex.getRun(runId)) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
209
|
+
const limit = optionalLimit(url.searchParams.get("limit"));
|
|
210
|
+
return json((await options.artifactCatalog.list({
|
|
211
|
+
runId,
|
|
212
|
+
...limit === void 0 ? {} : { limit }
|
|
213
|
+
}, artifactContext(handlerContext, request))).map(({ descriptor }) => descriptor));
|
|
214
|
+
}
|
|
215
|
+
const artifactRoute = path.match(/^\/v1\/artifacts\/([^/]+)$/);
|
|
216
|
+
if (artifactRoute && (request.method === "GET" || request.method === "HEAD")) {
|
|
217
|
+
const artifactId = decodeURIComponent(artifactRoute[1]);
|
|
218
|
+
await authorizeArtifact({
|
|
219
|
+
action: "read",
|
|
220
|
+
kind: "artifact",
|
|
221
|
+
artifactId,
|
|
222
|
+
context: handlerContext.context
|
|
223
|
+
});
|
|
224
|
+
if (!options.artifacts) throw new HttpProtocolError(501, "ARTIFACTS_NOT_CONFIGURED", "Artifact store is not configured");
|
|
225
|
+
const context = artifactContext(handlerContext, request);
|
|
226
|
+
if (request.method === "HEAD" && options.artifacts.head) {
|
|
227
|
+
const descriptor = await options.artifacts.head(artifactId, context);
|
|
228
|
+
if (!descriptor) throw notFound("ARTIFACT_NOT_FOUND", "Artifact not found");
|
|
229
|
+
return artifactResponse(descriptor, null);
|
|
230
|
+
}
|
|
231
|
+
const content = await options.artifacts.get(artifactId, context);
|
|
232
|
+
if (!content) throw notFound("ARTIFACT_NOT_FOUND", "Artifact not found");
|
|
233
|
+
return artifactResponse(content.descriptor, request.method === "HEAD" ? null : content.bytes);
|
|
234
|
+
}
|
|
235
|
+
if (artifactRoute && request.method === "DELETE") {
|
|
236
|
+
const artifactId = decodeURIComponent(artifactRoute[1]);
|
|
237
|
+
await authorizeArtifact({
|
|
238
|
+
action: "delete",
|
|
239
|
+
kind: "artifact",
|
|
240
|
+
artifactId,
|
|
241
|
+
context: handlerContext.context
|
|
242
|
+
});
|
|
243
|
+
if (!options.artifacts) throw new HttpProtocolError(501, "ARTIFACTS_NOT_CONFIGURED", "Artifact store is not configured");
|
|
244
|
+
if (!options.artifacts.delete) throw new HttpProtocolError(501, "ARTIFACT_DELETE_UNSUPPORTED", "Artifact store does not support deletion");
|
|
245
|
+
if (!await options.artifacts.delete(artifactId, artifactContext(handlerContext, request))) throw notFound("ARTIFACT_NOT_FOUND", "Artifact not found");
|
|
246
|
+
return versioned(new Response(null, { status: 204 }));
|
|
247
|
+
}
|
|
119
248
|
const run = path.match(/^\/v1\/runs\/([^/]+)$/);
|
|
120
249
|
if (run && request.method === "GET") {
|
|
121
|
-
const
|
|
250
|
+
const runId = decodeURIComponent(run[1]);
|
|
251
|
+
await authorize({
|
|
252
|
+
action: "read",
|
|
253
|
+
runId,
|
|
254
|
+
context: handlerContext.context
|
|
255
|
+
});
|
|
256
|
+
const value = await options.fevex.getRun(runId);
|
|
122
257
|
if (!value) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
123
258
|
return json(value);
|
|
124
259
|
}
|
|
125
260
|
if (run && request.method === "DELETE") {
|
|
126
261
|
const runId = decodeURIComponent(run[1]);
|
|
262
|
+
await authorize({
|
|
263
|
+
action: "cancel",
|
|
264
|
+
runId,
|
|
265
|
+
context: handlerContext.context
|
|
266
|
+
});
|
|
127
267
|
const value = await options.fevex.getRun(runId);
|
|
128
268
|
if (!value) throw notFound("RUN_NOT_FOUND", "Run not found");
|
|
129
269
|
if (value.status === "running" || value.status === "paused") {
|
|
@@ -131,7 +271,7 @@ function createFevexHttpHandler(options) {
|
|
|
131
271
|
}
|
|
132
272
|
return versioned(new Response(null, { status: 204 }));
|
|
133
273
|
}
|
|
134
|
-
if (start || startWorkflow || startTeam || events || resume || recover || run) throw new HttpProtocolError(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
274
|
+
if (start || startWorkflow || startTeam || events || resume || recover || runArtifacts || artifactRoute || run) throw new HttpProtocolError(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
135
275
|
throw notFound("ROUTE_NOT_FOUND", "Route not found");
|
|
136
276
|
} catch (error) {
|
|
137
277
|
return problem(error, url.pathname, options.onError);
|
|
@@ -192,6 +332,17 @@ function createFevexHttpClient(options) {
|
|
|
192
332
|
},
|
|
193
333
|
async cancelRun(runId) {
|
|
194
334
|
await assertResponse(await fetcher(`${baseUrl}/v1/runs/${encodeURIComponent(runId)}`, { method: "DELETE" }));
|
|
335
|
+
},
|
|
336
|
+
async getArtifact(artifactId) {
|
|
337
|
+
const response = await fetcher(`${baseUrl}/v1/artifacts/${encodeURIComponent(artifactId)}`);
|
|
338
|
+
await assertResponse(response);
|
|
339
|
+
return response;
|
|
340
|
+
},
|
|
341
|
+
listArtifacts(runId) {
|
|
342
|
+
return request(`/v1/runs/${encodeURIComponent(runId)}/artifacts`);
|
|
343
|
+
},
|
|
344
|
+
async deleteArtifact(artifactId) {
|
|
345
|
+
await assertResponse(await fetcher(`${baseUrl}/v1/artifacts/${encodeURIComponent(artifactId)}`, { method: "DELETE" }));
|
|
195
346
|
}
|
|
196
347
|
};
|
|
197
348
|
}
|
|
@@ -220,18 +371,28 @@ async function* observeEvents(fevex, runId, initial, after, pollIntervalMs, sign
|
|
|
220
371
|
});
|
|
221
372
|
}
|
|
222
373
|
}
|
|
223
|
-
function iteratorStream(iterator, cancel) {
|
|
374
|
+
function iteratorStream(iterator, cancel, done) {
|
|
375
|
+
let finished = false;
|
|
376
|
+
const finish = () => {
|
|
377
|
+
if (finished) return;
|
|
378
|
+
finished = true;
|
|
379
|
+
done?.();
|
|
380
|
+
};
|
|
224
381
|
return new ReadableStream({
|
|
225
382
|
async pull(controller) {
|
|
226
383
|
try {
|
|
227
384
|
const next = await iterator.next();
|
|
228
|
-
if (next.done)
|
|
229
|
-
|
|
385
|
+
if (next.done) {
|
|
386
|
+
finish();
|
|
387
|
+
controller.close();
|
|
388
|
+
} else controller.enqueue(next.value);
|
|
230
389
|
} catch (error) {
|
|
390
|
+
finish();
|
|
231
391
|
controller.error(error);
|
|
232
392
|
}
|
|
233
393
|
},
|
|
234
394
|
async cancel() {
|
|
395
|
+
finish();
|
|
235
396
|
cancel();
|
|
236
397
|
await iterator.return(void 0);
|
|
237
398
|
}
|
|
@@ -280,6 +441,37 @@ function findBoundary(value) {
|
|
|
280
441
|
function formatEvent(event) {
|
|
281
442
|
return `id: ${event.id}\nevent: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`;
|
|
282
443
|
}
|
|
444
|
+
function artifactContext(handlerContext, request) {
|
|
445
|
+
const tenantId = handlerContext.context?.attributes?.tenantId;
|
|
446
|
+
if (tenantId !== void 0 && typeof tenantId !== "string") throw badRequest("tenantId attribute must be a string");
|
|
447
|
+
const actor = handlerContext.context?.actor;
|
|
448
|
+
return {
|
|
449
|
+
...typeof tenantId === "string" ? { tenantId } : {},
|
|
450
|
+
...actor === void 0 ? {} : { actor },
|
|
451
|
+
signal: request.signal
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function optionalLimit(value) {
|
|
455
|
+
if (value === null) return void 0;
|
|
456
|
+
const parsed = Number(value);
|
|
457
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1) throw badRequest("limit must be a positive integer");
|
|
458
|
+
return parsed;
|
|
459
|
+
}
|
|
460
|
+
function artifactResponse(descriptor, bytes) {
|
|
461
|
+
return versioned(new Response(bytes === null ? null : bytes.slice().buffer, { headers: {
|
|
462
|
+
"content-type": descriptor.mimeType,
|
|
463
|
+
"content-length": String(descriptor.size),
|
|
464
|
+
"content-disposition": contentDisposition(descriptor.filename),
|
|
465
|
+
"cache-control": "private, max-age=0, must-revalidate",
|
|
466
|
+
etag: `"${descriptor.sha256}"`,
|
|
467
|
+
"x-content-type-options": "nosniff",
|
|
468
|
+
"fevex-artifact-id": descriptor.artifactId,
|
|
469
|
+
"fevex-artifact-sha256": descriptor.sha256
|
|
470
|
+
} }));
|
|
471
|
+
}
|
|
472
|
+
function contentDisposition(filename) {
|
|
473
|
+
return `attachment; filename="${filename.replace(/[^\x20-\x7e]/gu, "_").replace(/["\\]/gu, "_")}"; filename*=UTF-8''${encodeURIComponent(filename).replace(/'/gu, "%27")}`;
|
|
474
|
+
}
|
|
283
475
|
function readResolution(body, actor) {
|
|
284
476
|
if (body.type === "elicitation" && typeof body.requestId === "string" && body.requestId.trim() && hasOwn(body, "value")) return {
|
|
285
477
|
type: "elicitation",
|
|
@@ -334,6 +526,16 @@ function optionalId(value, name) {
|
|
|
334
526
|
if (typeof value !== "string" || !value.trim()) throw badRequest(`${name} must be a string`);
|
|
335
527
|
return value.trim();
|
|
336
528
|
}
|
|
529
|
+
function optionalPositiveInteger(value, name) {
|
|
530
|
+
if (value === void 0) return void 0;
|
|
531
|
+
if (!Number.isSafeInteger(value) || value < 1) throw badRequest(`${name} must be a positive integer`);
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
function optionalDeadline(value, name) {
|
|
535
|
+
const deadlineMs = optionalPositiveInteger(value, name);
|
|
536
|
+
if (deadlineMs !== void 0 && deadlineMs > 2147483647) throw badRequest(`${name} must be at most ${MAX_DEADLINE_MS}`);
|
|
537
|
+
return deadlineMs;
|
|
538
|
+
}
|
|
337
539
|
function optionalReasoning(value) {
|
|
338
540
|
if (value === void 0) return void 0;
|
|
339
541
|
if (typeof value !== "string" || ![
|
|
@@ -408,6 +610,11 @@ function problem(error, instance, onError) {
|
|
|
408
610
|
({status, code} = error);
|
|
409
611
|
title = error.message;
|
|
410
612
|
detail = error.message;
|
|
613
|
+
} else if (error instanceof ArtifactError) {
|
|
614
|
+
code = error.code;
|
|
615
|
+
status = statusForArtifactErrorCode(error.code);
|
|
616
|
+
title = titleForStatus(status);
|
|
617
|
+
detail = error.message;
|
|
411
618
|
} else {
|
|
412
619
|
const runError = readFevexRunError(error);
|
|
413
620
|
if (runError) {
|
|
@@ -446,13 +653,26 @@ function statusForRunErrorCode(code) {
|
|
|
446
653
|
if (code === "AGENT_NOT_FOUND" || code === "WORKFLOW_NOT_FOUND" || code === "TEAM_NOT_FOUND" || code === "SESSION_NOT_FOUND") return 404;
|
|
447
654
|
if (code === "APPROVAL_INVALID" || code === "INVALID_CURSOR") return 400;
|
|
448
655
|
if (code === "POLICY_DENIED") return 403;
|
|
656
|
+
if (code === "ADMISSION_DENIED") return 429;
|
|
449
657
|
return 409;
|
|
450
658
|
}
|
|
659
|
+
function statusForArtifactErrorCode(code) {
|
|
660
|
+
if (code === "ARTIFACT_INVALID_ID" || code === "ARTIFACT_INVALID_INPUT" || code === "ARTIFACT_INVALID_CONTEXT") return 400;
|
|
661
|
+
if (code === "ARTIFACT_TOO_LARGE") return 413;
|
|
662
|
+
if (code === "ARTIFACT_MIME_UNSUPPORTED") return 415;
|
|
663
|
+
if (code === "ARTIFACT_CONFLICT") return 409;
|
|
664
|
+
return 500;
|
|
665
|
+
}
|
|
451
666
|
function titleForStatus(status) {
|
|
452
|
-
if (status === 404) return "Not Found";
|
|
453
667
|
if (status === 400) return "Bad Request";
|
|
454
668
|
if (status === 403) return "Forbidden";
|
|
455
|
-
return "
|
|
669
|
+
if (status === 404) return "Not Found";
|
|
670
|
+
if (status === 409) return "Conflict";
|
|
671
|
+
if (status === 413) return "Payload Too Large";
|
|
672
|
+
if (status === 415) return "Unsupported Media Type";
|
|
673
|
+
if (status === 429) return "Too Many Requests";
|
|
674
|
+
if (status === 501) return "Not Implemented";
|
|
675
|
+
return "Internal Server Error";
|
|
456
676
|
}
|
|
457
677
|
function wait(ms, signal) {
|
|
458
678
|
return new Promise((resolve) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { f as RunId, o as ExecutionContext, s as JsonObject, t as AgentEvent } from "./types-
|
|
2
|
-
import {
|
|
3
|
-
import { t as Fevex } from "./fevex-
|
|
1
|
+
import { f as RunId, o as ExecutionContext, s as JsonObject, t as AgentEvent } from "./types-BDVUoAU6.mjs";
|
|
2
|
+
import { I as SessionId, a as AgentRun, h as ElicitationRequest } from "./index-CGmHXV31.mjs";
|
|
3
|
+
import { t as Fevex } from "./fevex-B5NxFKcV.mjs";
|
|
4
4
|
//#region src/channels/channel.d.ts
|
|
5
5
|
interface ChannelMessage {
|
|
6
6
|
id: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as ToolSpec, i as AgentMessage, l as JsonValue, m as ToolCall, s as JsonObject } from "./types-
|
|
1
|
+
import { g as ToolSpec, i as AgentMessage, l as JsonValue, m as ToolCall, s as JsonObject } from "./types-BDVUoAU6.mjs";
|
|
2
2
|
//#region src/models/model.d.ts
|
|
3
3
|
/** Provider-neutral reasoning levels accepted by model gateways. */
|
|
4
4
|
type ReasoningEffort = 'provider-default' | 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as ExactDefinition } from "./exact-definition-NHBBFlFR.mjs";
|
|
2
|
-
import { f as RunId, l as JsonValue, o as ExecutionContext, s as JsonObject } from "./types-
|
|
3
|
-
import {
|
|
2
|
+
import { f as RunId, l as JsonValue, o as ExecutionContext, s as JsonObject } from "./types-BDVUoAU6.mjs";
|
|
3
|
+
import { I as SessionId, M as RunResult, j as RunRequest, n as AgentLimits } from "./index-CGmHXV31.mjs";
|
|
4
4
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
5
5
|
//#region src/workflows/workflow.d.ts
|
|
6
6
|
/** Context shared with workflow steps and compensation handlers. */
|