@vercel/factory 0.0.13 → 0.0.14
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 +1 -1
- package/dist/api.d.mts +225 -0
- package/dist/api.mjs +312 -0
- package/dist/api.mjs.map +1 -0
- package/dist/approval-JX2Px9IC.mjs +132 -0
- package/dist/approval-JX2Px9IC.mjs.map +1 -0
- package/dist/blob/index.d.mts +4 -3
- package/dist/blob/index.mjs +21 -15
- package/dist/blob/index.mjs.map +1 -1
- package/dist/budget-DzSiIA4t.mjs +42 -0
- package/dist/budget-DzSiIA4t.mjs.map +1 -0
- package/dist/build-factory.mjs +1 -1
- package/dist/{change-CzEAoFVE.mjs → change-D2U6v7Ek.mjs} +10 -76
- package/dist/change-D2U6v7Ek.mjs.map +1 -0
- package/dist/communication-Kd9nU5RP.mjs +30 -0
- package/dist/communication-Kd9nU5RP.mjs.map +1 -0
- package/dist/connectors/index.d.mts +3 -2
- package/dist/connectors/index.mjs +53 -26
- package/dist/connectors/index.mjs.map +1 -1
- package/dist/connectors/slack.d.mts +13 -2
- package/dist/connectors/slack.mjs +18 -2
- package/dist/connectors/slack.mjs.map +1 -1
- package/dist/coordination-Cq08hb1l.mjs +76 -0
- package/dist/coordination-Cq08hb1l.mjs.map +1 -0
- package/dist/dispatch-BaZS3PT8.d.mts +76 -0
- package/dist/{driver-BJutB0PE.d.mts → driver-BC0Mt5KG.d.mts} +2 -2
- package/dist/driver-Bbd25rNM.mjs.map +1 -1
- package/dist/{dispatch-B77cuPxh.d.mts → engine-DFHU2Pe-.d.mts} +356 -288
- package/dist/engine-WaUM2cGA.mjs +1068 -0
- package/dist/engine-WaUM2cGA.mjs.map +1 -0
- package/dist/eve/index.d.mts +44 -334
- package/dist/eve/index.mjs +51 -38
- package/dist/eve/index.mjs.map +1 -1
- package/dist/{factory-config-BJcjsPKl.mjs → factory-config-BoRXOw43.mjs} +5 -41
- package/dist/factory-config-BoRXOw43.mjs.map +1 -0
- package/dist/{github-DXsxboUL.d.mts → github-C5HNBN6p.d.mts} +11 -3
- package/dist/github.d.mts +2 -2
- package/dist/github.mjs +15 -1
- package/dist/github.mjs.map +1 -1
- package/dist/{id-DwCihQr4.mjs → id-BLIkCVue.mjs} +4 -2
- package/dist/{id-DwCihQr4.mjs.map → id-BLIkCVue.mjs.map} +1 -1
- package/dist/index-Bw6hggoH.d.mts +40 -0
- package/dist/index.d.mts +176 -6
- package/dist/index.mjs +50 -652
- package/dist/index.mjs.map +1 -1
- package/dist/postgres/index.d.mts +1 -1
- package/dist/{approval-CwhTP1XB.mjs → task-CcOyOJ3k.mjs} +18 -133
- package/dist/task-CcOyOJ3k.mjs.map +1 -0
- package/package.json +5 -1
- package/dist/approval-CwhTP1XB.mjs.map +0 -1
- package/dist/change-CzEAoFVE.mjs.map +0 -1
- package/dist/factory-config-BJcjsPKl.mjs.map +0 -1
- package/dist/index-Cy4jfXh5.d.mts +0 -67
- package/dist/signal-CHVEmzvI.d.mts +0 -59
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ persistence, agent tools, and provider adapters for durable, auditable software
|
|
|
5
5
|
|
|
6
6
|
The FDK extends Eve incrementally. Durable workflows retain authority over policy, budgets,
|
|
7
7
|
state transitions, retries, and external effects while agents and coding harnesses return bounded
|
|
8
|
-
results. The V1 reference runtime uses
|
|
8
|
+
results. The V1 reference runtime uses Blob, AI SDK `HarnessAgent`, and Vercel Sandbox,
|
|
9
9
|
with independent verification and human-owned merges.
|
|
10
10
|
|
|
11
11
|
See the [repository README](../../README.md) for development instructions and the
|
package/dist/api.d.mts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { l as AgentRouteRegistry, r as DispatchBudget } from "./dispatch-BaZS3PT8.mjs";
|
|
2
|
+
import { Tt as Task, h as FactoryStores, j as Repository, wt as ExecutionReference, yt as AgentSession } from "./engine-DFHU2Pe-.mjs";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/api.d.ts
|
|
5
|
+
declare const apiAgentSchema: z.ZodObject<{
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
description: z.ZodString;
|
|
8
|
+
routeId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
requiresRepository: z.ZodBoolean;
|
|
10
|
+
requiresChange: z.ZodBoolean;
|
|
11
|
+
}, z.core.$strict>;
|
|
12
|
+
type ApiAgent = z.infer<typeof apiAgentSchema>;
|
|
13
|
+
declare const createSessionRequestSchema: z.ZodObject<{
|
|
14
|
+
operationId: z.ZodString;
|
|
15
|
+
agent: z.ZodString;
|
|
16
|
+
repository: z.ZodOptional<z.ZodString>;
|
|
17
|
+
changeId: z.ZodOptional<z.ZodString>;
|
|
18
|
+
message: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
type CreateSessionRequest = z.infer<typeof createSessionRequestSchema>;
|
|
21
|
+
declare const sessionViewSchema: z.ZodObject<{
|
|
22
|
+
session: z.ZodObject<{
|
|
23
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
24
|
+
id: z.ZodString;
|
|
25
|
+
owner: z.ZodString;
|
|
26
|
+
agent: z.ZodString;
|
|
27
|
+
repositoryId: z.ZodOptional<z.ZodString>;
|
|
28
|
+
routeId: z.ZodOptional<z.ZodString>;
|
|
29
|
+
message: z.ZodString;
|
|
30
|
+
changeId: z.ZodOptional<z.ZodString>;
|
|
31
|
+
taskId: z.ZodOptional<z.ZodString>;
|
|
32
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
provider: z.ZodString;
|
|
34
|
+
sessionId: z.ZodString;
|
|
35
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
36
|
+
harness: z.ZodOptional<z.ZodString>;
|
|
37
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
38
|
+
}, z.core.$strict>>;
|
|
39
|
+
notifications: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
40
|
+
eventId: z.ZodString;
|
|
41
|
+
repositoryIds: z.ZodArray<z.ZodString>;
|
|
42
|
+
taskId: z.ZodOptional<z.ZodString>;
|
|
43
|
+
changeId: z.ZodOptional<z.ZodString>;
|
|
44
|
+
replyTo: z.ZodObject<{
|
|
45
|
+
channel: z.ZodString;
|
|
46
|
+
address: z.ZodString;
|
|
47
|
+
}, z.core.$strict>;
|
|
48
|
+
outcome: z.ZodEnum<{
|
|
49
|
+
message: "message";
|
|
50
|
+
accepted: "accepted";
|
|
51
|
+
started: "started";
|
|
52
|
+
succeeded: "succeeded";
|
|
53
|
+
failed: "failed";
|
|
54
|
+
needs_human: "needs_human";
|
|
55
|
+
question: "question";
|
|
56
|
+
digest: "digest";
|
|
57
|
+
rolled_back: "rolled_back";
|
|
58
|
+
budget_warning: "budget_warning";
|
|
59
|
+
budget_exhausted: "budget_exhausted";
|
|
60
|
+
}>;
|
|
61
|
+
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
62
|
+
}, z.core.$strict>>>;
|
|
63
|
+
createdAt: z.ZodISODateTime;
|
|
64
|
+
}, z.core.$strict>;
|
|
65
|
+
task: z.ZodNullable<z.ZodObject<{
|
|
66
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
67
|
+
id: z.ZodString;
|
|
68
|
+
repositoryIds: z.ZodArray<z.ZodString>;
|
|
69
|
+
kind: z.ZodString;
|
|
70
|
+
area: z.ZodOptional<z.ZodString>;
|
|
71
|
+
state: z.ZodEnum<{
|
|
72
|
+
succeeded: "succeeded";
|
|
73
|
+
failed: "failed";
|
|
74
|
+
needs_human: "needs_human";
|
|
75
|
+
queued: "queued";
|
|
76
|
+
running: "running";
|
|
77
|
+
stalled: "stalled";
|
|
78
|
+
verifying: "verifying";
|
|
79
|
+
cancelled: "cancelled";
|
|
80
|
+
}>;
|
|
81
|
+
approval: z.ZodOptional<z.ZodEnum<{
|
|
82
|
+
required: "required";
|
|
83
|
+
granted: "granted";
|
|
84
|
+
denied: "denied";
|
|
85
|
+
}>>;
|
|
86
|
+
origin: z.ZodObject<{
|
|
87
|
+
signalId: z.ZodOptional<z.ZodString>;
|
|
88
|
+
parentTaskId: z.ZodOptional<z.ZodString>;
|
|
89
|
+
operator: z.ZodOptional<z.ZodString>;
|
|
90
|
+
}, z.core.$strict>;
|
|
91
|
+
dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
92
|
+
replyTo: z.ZodObject<{
|
|
93
|
+
channel: z.ZodString;
|
|
94
|
+
address: z.ZodString;
|
|
95
|
+
}, z.core.$strict>;
|
|
96
|
+
attempt: z.ZodNumber;
|
|
97
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
98
|
+
provider: z.ZodString;
|
|
99
|
+
sessionId: z.ZodString;
|
|
100
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
101
|
+
harness: z.ZodOptional<z.ZodString>;
|
|
102
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
103
|
+
}, z.core.$strict>>;
|
|
104
|
+
lastProgressAt: z.ZodOptional<z.ZodISODateTime>;
|
|
105
|
+
stalledAt: z.ZodOptional<z.ZodISODateTime>;
|
|
106
|
+
stalledReason: z.ZodOptional<z.ZodString>;
|
|
107
|
+
reservedUsd: z.ZodOptional<z.ZodNumber>;
|
|
108
|
+
reservedAt: z.ZodOptional<z.ZodISODateTime>;
|
|
109
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
110
|
+
costUsd: z.ZodNumber;
|
|
111
|
+
inputTokens: z.ZodNumber;
|
|
112
|
+
outputTokens: z.ZodNumber;
|
|
113
|
+
cacheReadTokens: z.ZodNumber;
|
|
114
|
+
cacheWriteTokens: z.ZodNumber;
|
|
115
|
+
steps: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
116
|
+
}, z.core.$strict>>;
|
|
117
|
+
settledUsd: z.ZodOptional<z.ZodNumber>;
|
|
118
|
+
question: z.ZodOptional<z.ZodObject<{
|
|
119
|
+
text: z.ZodString;
|
|
120
|
+
options: z.ZodArray<z.ZodString>;
|
|
121
|
+
answer: z.ZodOptional<z.ZodString>;
|
|
122
|
+
answeredBy: z.ZodOptional<z.ZodString>;
|
|
123
|
+
}, z.core.$strict>>;
|
|
124
|
+
questionTaskId: z.ZodOptional<z.ZodString>;
|
|
125
|
+
answerEventIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
126
|
+
changeId: z.ZodOptional<z.ZodString>;
|
|
127
|
+
reportRef: z.ZodOptional<z.ZodString>;
|
|
128
|
+
createdAt: z.ZodISODateTime;
|
|
129
|
+
updatedAt: z.ZodISODateTime;
|
|
130
|
+
}, z.core.$strict>>;
|
|
131
|
+
execution: z.ZodNullable<z.ZodObject<{
|
|
132
|
+
provider: z.ZodString;
|
|
133
|
+
sessionId: z.ZodString;
|
|
134
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
135
|
+
harness: z.ZodOptional<z.ZodString>;
|
|
136
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
137
|
+
}, z.core.$strict>>;
|
|
138
|
+
question: z.ZodNullable<z.ZodObject<{
|
|
139
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
140
|
+
id: z.ZodString;
|
|
141
|
+
repositoryIds: z.ZodArray<z.ZodString>;
|
|
142
|
+
kind: z.ZodString;
|
|
143
|
+
area: z.ZodOptional<z.ZodString>;
|
|
144
|
+
state: z.ZodEnum<{
|
|
145
|
+
succeeded: "succeeded";
|
|
146
|
+
failed: "failed";
|
|
147
|
+
needs_human: "needs_human";
|
|
148
|
+
queued: "queued";
|
|
149
|
+
running: "running";
|
|
150
|
+
stalled: "stalled";
|
|
151
|
+
verifying: "verifying";
|
|
152
|
+
cancelled: "cancelled";
|
|
153
|
+
}>;
|
|
154
|
+
approval: z.ZodOptional<z.ZodEnum<{
|
|
155
|
+
required: "required";
|
|
156
|
+
granted: "granted";
|
|
157
|
+
denied: "denied";
|
|
158
|
+
}>>;
|
|
159
|
+
origin: z.ZodObject<{
|
|
160
|
+
signalId: z.ZodOptional<z.ZodString>;
|
|
161
|
+
parentTaskId: z.ZodOptional<z.ZodString>;
|
|
162
|
+
operator: z.ZodOptional<z.ZodString>;
|
|
163
|
+
}, z.core.$strict>;
|
|
164
|
+
dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
165
|
+
replyTo: z.ZodObject<{
|
|
166
|
+
channel: z.ZodString;
|
|
167
|
+
address: z.ZodString;
|
|
168
|
+
}, z.core.$strict>;
|
|
169
|
+
attempt: z.ZodNumber;
|
|
170
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
171
|
+
provider: z.ZodString;
|
|
172
|
+
sessionId: z.ZodString;
|
|
173
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
174
|
+
harness: z.ZodOptional<z.ZodString>;
|
|
175
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
176
|
+
}, z.core.$strict>>;
|
|
177
|
+
lastProgressAt: z.ZodOptional<z.ZodISODateTime>;
|
|
178
|
+
stalledAt: z.ZodOptional<z.ZodISODateTime>;
|
|
179
|
+
stalledReason: z.ZodOptional<z.ZodString>;
|
|
180
|
+
reservedUsd: z.ZodOptional<z.ZodNumber>;
|
|
181
|
+
reservedAt: z.ZodOptional<z.ZodISODateTime>;
|
|
182
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
183
|
+
costUsd: z.ZodNumber;
|
|
184
|
+
inputTokens: z.ZodNumber;
|
|
185
|
+
outputTokens: z.ZodNumber;
|
|
186
|
+
cacheReadTokens: z.ZodNumber;
|
|
187
|
+
cacheWriteTokens: z.ZodNumber;
|
|
188
|
+
steps: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
189
|
+
}, z.core.$strict>>;
|
|
190
|
+
settledUsd: z.ZodOptional<z.ZodNumber>;
|
|
191
|
+
question: z.ZodOptional<z.ZodObject<{
|
|
192
|
+
text: z.ZodString;
|
|
193
|
+
options: z.ZodArray<z.ZodString>;
|
|
194
|
+
answer: z.ZodOptional<z.ZodString>;
|
|
195
|
+
answeredBy: z.ZodOptional<z.ZodString>;
|
|
196
|
+
}, z.core.$strict>>;
|
|
197
|
+
questionTaskId: z.ZodOptional<z.ZodString>;
|
|
198
|
+
answerEventIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
199
|
+
changeId: z.ZodOptional<z.ZodString>;
|
|
200
|
+
reportRef: z.ZodOptional<z.ZodString>;
|
|
201
|
+
createdAt: z.ZodISODateTime;
|
|
202
|
+
updatedAt: z.ZodISODateTime;
|
|
203
|
+
}, z.core.$strict>>;
|
|
204
|
+
}, z.core.$strict>;
|
|
205
|
+
type SessionView = z.infer<typeof sessionViewSchema>;
|
|
206
|
+
interface FactoryApiOptions {
|
|
207
|
+
stores: FactoryStores;
|
|
208
|
+
agents: readonly ApiAgent[];
|
|
209
|
+
routes: AgentRouteRegistry;
|
|
210
|
+
repositories: readonly string[];
|
|
211
|
+
budget: DispatchBudget;
|
|
212
|
+
authenticate(request: Request): Promise<{
|
|
213
|
+
id: string;
|
|
214
|
+
} | Response>;
|
|
215
|
+
ensureRepository(slug: string): Promise<Repository>;
|
|
216
|
+
start(session: AgentSession, task: Task | null, message: string, operationId: string): Promise<ExecutionReference>;
|
|
217
|
+
forward(session: AgentSession, execution: ExecutionReference, path: string, request: Request): Promise<Response>;
|
|
218
|
+
reportError?(error: unknown): void;
|
|
219
|
+
}
|
|
220
|
+
declare function createFactoryApi(options: FactoryApiOptions): {
|
|
221
|
+
handle: (request: Request) => Promise<Response>;
|
|
222
|
+
};
|
|
223
|
+
//#endregion
|
|
224
|
+
export { ApiAgent, CreateSessionRequest, FactoryApiOptions, SessionView, apiAgentSchema, createFactoryApi, createSessionRequestSchema, sessionViewSchema };
|
|
225
|
+
//# sourceMappingURL=api.d.mts.map
|
package/dist/api.mjs
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { l as taskIdSchema, n as changeIdSchema } from "./id-BLIkCVue.mjs";
|
|
2
|
+
import { n as executionReferenceSchema, u as taskSchema } from "./task-CcOyOJ3k.mjs";
|
|
3
|
+
import { a as BudgetExhaustedError, c as dispatchTask, l as InvalidTransitionError, s as DispatchRefusedError } from "./change-D2U6v7Ek.mjs";
|
|
4
|
+
import { n as RecordNotFoundError, r as VersionConflictError } from "./driver-Bbd25rNM.mjs";
|
|
5
|
+
import { a as SessionConflictError, l as agentSessionSchema } from "./engine-WaUM2cGA.mjs";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
//#region src/api.ts
|
|
8
|
+
const apiAgentSchema = z.strictObject({
|
|
9
|
+
id: z.string().regex(/^[a-z][a-z0-9-]{0,31}$/u).describe("Agent name selected at session creation."),
|
|
10
|
+
description: z.string().describe("What this agent does."),
|
|
11
|
+
routeId: z.string().optional().describe("Declared specialist route; absent for conversations."),
|
|
12
|
+
requiresRepository: z.boolean().describe("Whether creation requires a configured repository."),
|
|
13
|
+
requiresChange: z.boolean().describe("Whether creation requires an existing change ID.")
|
|
14
|
+
});
|
|
15
|
+
const createSessionRequestSchema = z.strictObject({
|
|
16
|
+
operationId: z.string().trim().min(1).max(200).describe("Client-generated idempotency key; retain when retrying creation."),
|
|
17
|
+
agent: apiAgentSchema.shape.id,
|
|
18
|
+
repository: z.string().min(1).optional().describe("Configured owner/repo slug."),
|
|
19
|
+
changeId: changeIdSchema.optional().describe("Existing change to review, verify, or continue."),
|
|
20
|
+
message: agentSessionSchema.shape.message
|
|
21
|
+
});
|
|
22
|
+
const sessionViewSchema = z.strictObject({
|
|
23
|
+
session: agentSessionSchema.describe("Durable interaction binding."),
|
|
24
|
+
task: taskSchema.nullable().describe("Current task state, if workflow-backed."),
|
|
25
|
+
execution: executionReferenceSchema.nullable().describe("Current execution; may change after recovery."),
|
|
26
|
+
question: taskSchema.nullable().describe("Open Factory question requiring an authenticated answer.")
|
|
27
|
+
});
|
|
28
|
+
const messageSchema = z.strictObject({
|
|
29
|
+
message: agentSessionSchema.shape.message,
|
|
30
|
+
turnPolicy: z.enum(["steer", "queue"]).default("steer").describe("How to handle an active turn."),
|
|
31
|
+
executionId: z.string().min(1).describe("Observed execution ID; stale writes are rejected.")
|
|
32
|
+
});
|
|
33
|
+
const inputSchema = z.strictObject({
|
|
34
|
+
executionId: z.string().min(1).describe("Observed provider session ID; rejects stale input responses."),
|
|
35
|
+
inputResponses: z.array(z.strictObject({
|
|
36
|
+
requestId: z.string().describe("Pending Eve input request ID."),
|
|
37
|
+
optionId: z.string().optional().describe("Selected option ID, when answering a choice."),
|
|
38
|
+
text: z.string().optional().describe("Freeform input response, when allowed.")
|
|
39
|
+
})).min(1).describe("Responses to pending human-input requests.")
|
|
40
|
+
});
|
|
41
|
+
const controlSchema = z.strictObject({
|
|
42
|
+
executionId: z.string().min(1).optional().describe("Observed provider session ID; guards against a replaced execution."),
|
|
43
|
+
turnId: z.string().min(1).optional().describe("Observed turn ID for cooperative interruption.")
|
|
44
|
+
});
|
|
45
|
+
const answerSchema = z.strictObject({
|
|
46
|
+
questionId: taskIdSchema.describe("Question Task belonging to this operator session."),
|
|
47
|
+
answer: z.string().min(1).max(16e3).describe("Authenticated human answer, persisted immutably.")
|
|
48
|
+
});
|
|
49
|
+
var ApiError = class extends Error {
|
|
50
|
+
status;
|
|
51
|
+
constructor(status, message) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.status = status;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const json = (value, status = 200) => Response.json(value, {
|
|
57
|
+
status,
|
|
58
|
+
headers: { "cache-control": "no-store" }
|
|
59
|
+
});
|
|
60
|
+
function createFactoryApi(options) {
|
|
61
|
+
const { stores } = options;
|
|
62
|
+
const agents = options.agents.map((agent) => apiAgentSchema.parse(agent));
|
|
63
|
+
if (new Set(agents.map((agent) => agent.id)).size !== agents.length) throw new Error("Duplicate API agent");
|
|
64
|
+
for (const agent of agents) if (agent.routeId !== void 0 && options.routes.get(agent.routeId)?.agent !== agent.id) throw new Error(`API agent ${agent.id} must select one of its registered routes`);
|
|
65
|
+
async function view(session) {
|
|
66
|
+
session = await stores.sessions.get(session.id) ?? session;
|
|
67
|
+
const task = session.taskId === void 0 ? null : await stores.tasks.get(session.taskId);
|
|
68
|
+
const question = task?.questionTaskId === void 0 ? null : await stores.tasks.get(task.questionTaskId);
|
|
69
|
+
return {
|
|
70
|
+
session,
|
|
71
|
+
task,
|
|
72
|
+
execution: task?.execution ?? session.execution ?? null,
|
|
73
|
+
question: task?.state === "needs_human" && question?.state === "needs_human" ? question : null
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function assertRepository(id) {
|
|
77
|
+
const repository = await stores.repositories.get(id);
|
|
78
|
+
if (repository === null || !repository.enabled || !options.repositories.includes(repository.slug)) throw new ApiError(403, "The session repository is no longer enabled and configured");
|
|
79
|
+
}
|
|
80
|
+
async function owned(id, owner) {
|
|
81
|
+
const session = await stores.sessions.get(id);
|
|
82
|
+
if (session === null || session.owner !== owner) throw new ApiError(404, "Session not found");
|
|
83
|
+
if (!agents.some((agent) => agent.id === session.agent)) throw new ApiError(409, "Session agent is no longer configured");
|
|
84
|
+
if (session.repositoryId !== void 0) await assertRepository(session.repositoryId);
|
|
85
|
+
return session;
|
|
86
|
+
}
|
|
87
|
+
async function launch(session) {
|
|
88
|
+
if (session.taskId === void 0) {
|
|
89
|
+
if (session.execution === void 0) {
|
|
90
|
+
const execution = await options.start(session, null, session.message, `api:${session.id}`);
|
|
91
|
+
session = await stores.sessions.bind(session.id, { execution });
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
const task = await stores.tasks.get(session.taskId);
|
|
95
|
+
if (task?.state === "queued") {
|
|
96
|
+
const answers = await Promise.all((task.answerEventIds ?? []).map((id) => stores.answers.get(id)));
|
|
97
|
+
const message = [
|
|
98
|
+
`You are assigned Factory task ${task.id}. Read it before starting.`,
|
|
99
|
+
session.changeId === void 0 ? "" : `Existing change: ${session.changeId}.`,
|
|
100
|
+
session.message,
|
|
101
|
+
...answers.flatMap((answer) => answer === null ? [] : [`${answer.question}\nAnswer: ${answer.answer}`])
|
|
102
|
+
].filter(Boolean).join("\n\n");
|
|
103
|
+
try {
|
|
104
|
+
await dispatchTask(stores, task.id, {
|
|
105
|
+
budget: options.budget,
|
|
106
|
+
launch: (running) => options.start(session, running, message, `factory-task:${running.id}:${running.attempt}`)
|
|
107
|
+
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (!(error instanceof DispatchRefusedError || error instanceof BudgetExhaustedError || error instanceof InvalidTransitionError || error instanceof VersionConflictError)) throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return view(session);
|
|
114
|
+
}
|
|
115
|
+
async function create(request, owner, conversation) {
|
|
116
|
+
const input = createSessionRequestSchema.parse(await body(request));
|
|
117
|
+
const agent = agents.find((candidate) => candidate.id === input.agent);
|
|
118
|
+
if (agent === void 0) throw new ApiError(400, `Unknown agent. Choose: ${agents.map((item) => item.id).join(", ")}`);
|
|
119
|
+
if (agent.routeId === void 0 !== conversation) throw new ApiError(400, conversation ? "Specialist work must be submitted through POST /api/v1/signals" : "Use POST /api/v1/sessions for conversations");
|
|
120
|
+
if (agent.requiresRepository && input.repository === void 0) throw new ApiError(400, `${agent.id} requires a repository`);
|
|
121
|
+
if (agent.requiresChange && input.changeId === void 0) throw new ApiError(400, `${agent.id} requires an existing changeId`);
|
|
122
|
+
const slug = input.repository?.toLowerCase();
|
|
123
|
+
if (slug !== void 0 && !options.repositories.includes(slug)) throw new ApiError(403, "Repository is not configured");
|
|
124
|
+
const repository = slug === void 0 ? void 0 : await options.ensureRepository(slug);
|
|
125
|
+
if (repository !== void 0) await assertRepository(repository.id);
|
|
126
|
+
if (input.changeId !== void 0) {
|
|
127
|
+
const change = await stores.changes.get(input.changeId);
|
|
128
|
+
if (change === null || change.repositoryId !== repository?.id) throw new ApiError(400, "changeId must identify a change in the selected repository");
|
|
129
|
+
if (change.state !== "verifying" && change.state !== "ready") throw new ApiError(409, "Change is no longer open for work");
|
|
130
|
+
}
|
|
131
|
+
let session = await stores.sessions.create({
|
|
132
|
+
operationId: input.operationId,
|
|
133
|
+
owner,
|
|
134
|
+
agent: agent.id,
|
|
135
|
+
repositoryId: repository?.id,
|
|
136
|
+
routeId: agent.routeId,
|
|
137
|
+
message: input.message,
|
|
138
|
+
changeId: input.changeId
|
|
139
|
+
});
|
|
140
|
+
if (agent.routeId !== void 0 && session.taskId === void 0) {
|
|
141
|
+
const route = options.routes.get(agent.routeId);
|
|
142
|
+
if (repository === void 0) throw new ApiError(400, "Specialist work requires a repository");
|
|
143
|
+
const replyTo = {
|
|
144
|
+
channel: "api",
|
|
145
|
+
address: session.id
|
|
146
|
+
};
|
|
147
|
+
const signal = await stores.signals.create({
|
|
148
|
+
repositoryId: repository.id,
|
|
149
|
+
source: "api",
|
|
150
|
+
deliveryId: session.id,
|
|
151
|
+
replyTo,
|
|
152
|
+
payload: {
|
|
153
|
+
agent: agent.id,
|
|
154
|
+
routeId: route.id,
|
|
155
|
+
message: input.message,
|
|
156
|
+
changeId: input.changeId
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
if (signal.outcome === "pending") try {
|
|
160
|
+
await stores.signals.decide(signal.id, "accepted", { reason: `Authenticated operator selected ${route.id}` });
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (!(error instanceof VersionConflictError || error instanceof InvalidTransitionError)) throw error;
|
|
163
|
+
}
|
|
164
|
+
const task = await stores.tasks.create({
|
|
165
|
+
repositoryIds: [repository.id],
|
|
166
|
+
kind: route.taskKind,
|
|
167
|
+
origin: {
|
|
168
|
+
signalId: signal.id,
|
|
169
|
+
operator: owner
|
|
170
|
+
},
|
|
171
|
+
replyTo,
|
|
172
|
+
changeId: input.changeId,
|
|
173
|
+
dedupeKey: `api:${session.id}`
|
|
174
|
+
});
|
|
175
|
+
session = await stores.sessions.bind(session.id, { taskId: task.id });
|
|
176
|
+
}
|
|
177
|
+
return json(await launch(session), 202);
|
|
178
|
+
}
|
|
179
|
+
async function proxy(session, request, suffix, payload) {
|
|
180
|
+
const current = await view(session);
|
|
181
|
+
const observed = payload !== null && typeof payload === "object" && "executionId" in payload ? payload.executionId : new URL(request.url).searchParams.get("executionId");
|
|
182
|
+
if (current.execution === null) throw new ApiError(409, "Execution is not available yet; refresh the session");
|
|
183
|
+
if (observed !== void 0 && observed !== null && observed !== current.execution.sessionId) throw new ApiError(409, "Execution changed; refresh the session before continuing");
|
|
184
|
+
if (request.method === "POST" && suffix !== "/cancel" && current.task !== null && current.task.state !== "running") throw new ApiError(409, `Task is ${current.task.state}. Answer its question or create new work instead of messaging an inactive task`);
|
|
185
|
+
const upstream = new Request(request.url, {
|
|
186
|
+
method: request.method,
|
|
187
|
+
signal: request.signal,
|
|
188
|
+
headers: { "content-type": "application/json" },
|
|
189
|
+
...request.method === "POST" ? { body: JSON.stringify(payload !== null && typeof payload === "object" ? Object.fromEntries(Object.entries(payload).filter(([key]) => key !== "executionId")) : {}) } : {}
|
|
190
|
+
});
|
|
191
|
+
const result = await options.forward(session, current.execution, suffix, upstream);
|
|
192
|
+
const streamHeaders = Object.fromEntries([
|
|
193
|
+
"x-eve-session-id",
|
|
194
|
+
"x-eve-stream-format",
|
|
195
|
+
"x-eve-stream-version",
|
|
196
|
+
"x-eve-stream-tail-index"
|
|
197
|
+
].flatMap((name) => {
|
|
198
|
+
const value = result.headers.get(name);
|
|
199
|
+
return value === null ? [] : [[name, value]];
|
|
200
|
+
}));
|
|
201
|
+
return new Response(result.body, {
|
|
202
|
+
status: result.status,
|
|
203
|
+
headers: {
|
|
204
|
+
"content-type": result.headers.get("content-type") ?? "application/json",
|
|
205
|
+
"cache-control": "no-store",
|
|
206
|
+
"x-accel-buffering": "no",
|
|
207
|
+
...streamHeaders
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async function handle(request) {
|
|
212
|
+
try {
|
|
213
|
+
const auth = await options.authenticate(request);
|
|
214
|
+
if (auth instanceof Response) return auth;
|
|
215
|
+
const url = new URL(request.url);
|
|
216
|
+
const path = url.pathname.replace(/^\/api\/v1\/?/u, "").split("/").filter(Boolean);
|
|
217
|
+
const [resource, id, action] = path;
|
|
218
|
+
if (path.length > 3) throw new ApiError(404, "API route not found");
|
|
219
|
+
if (request.method === "GET" && path.length === 1) {
|
|
220
|
+
if (resource === "agents") return json({ agents });
|
|
221
|
+
if (resource === "repositories") return json({ repositories: options.repositories });
|
|
222
|
+
const requestedRepository = resource === "changes" ? url.searchParams.get("repository") : null;
|
|
223
|
+
if (requestedRepository !== null && !options.repositories.includes(requestedRepository)) throw new ApiError(403, "Repository is not configured");
|
|
224
|
+
const enabledIds = new Set((await stores.repositories.list()).filter((repo) => repo.enabled && options.repositories.includes(repo.slug) && (requestedRepository === null || repo.slug === requestedRepository)).map((repo) => repo.id));
|
|
225
|
+
if (resource === "changes") return json({ changes: (await stores.changes.list()).filter((change) => enabledIds.has(change.repositoryId) && (change.state === "verifying" || change.state === "ready")) });
|
|
226
|
+
if (resource === "sessions") {
|
|
227
|
+
const sessions = (await stores.sessions.list()).filter((session) => session.owner === auth.id && agents.some((agent) => agent.id === session.agent) && (session.repositoryId === void 0 || enabledIds.has(session.repositoryId))).sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
228
|
+
return json({ sessions: await Promise.all(sessions.map(view)) });
|
|
229
|
+
}
|
|
230
|
+
if (resource === "tasks") return json({ tasks: (await stores.tasks.list()).filter((task) => task.origin.operator === auth.id && task.repositoryIds.every((id) => enabledIds.has(id))) });
|
|
231
|
+
}
|
|
232
|
+
if (request.method === "POST" && path.length === 1 && (resource === "signals" || resource === "sessions")) return await create(request, auth.id, resource === "sessions");
|
|
233
|
+
if (resource !== "sessions" || id === void 0) throw new ApiError(404, "API route not found");
|
|
234
|
+
const session = await owned(id, auth.id);
|
|
235
|
+
if (request.method === "GET" && action === void 0) return json(await view(session));
|
|
236
|
+
if (request.method === "GET" && action === "stream") {
|
|
237
|
+
const query = new URLSearchParams();
|
|
238
|
+
for (const name of ["startIndex", "includeTailIndex"]) {
|
|
239
|
+
const value = url.searchParams.get(name);
|
|
240
|
+
if (value !== null) query.set(name, value);
|
|
241
|
+
}
|
|
242
|
+
return await proxy(session, request, `/stream?${query}`);
|
|
243
|
+
}
|
|
244
|
+
if (request.method !== "POST") throw new ApiError(405, "Use GET or POST for this route");
|
|
245
|
+
if (action === "messages") return await proxy(session, request, "", messageSchema.parse(await body(request)));
|
|
246
|
+
if (action === "input") return await proxy(session, request, "", inputSchema.parse(await body(request)));
|
|
247
|
+
if (action === "dispatch") return json(await launch(session), 202);
|
|
248
|
+
if (action === "answer") {
|
|
249
|
+
const input = answerSchema.parse(await body(request));
|
|
250
|
+
const current = await view(session);
|
|
251
|
+
const question = await stores.tasks.get(input.questionId);
|
|
252
|
+
if (question === null || question.origin.parentTaskId !== current.task?.id || question.replyTo.channel !== "api" || question.replyTo.address !== session.id) throw new ApiError(403, "Question does not belong to this interaction");
|
|
253
|
+
await stores.tasks.answerQuestion({
|
|
254
|
+
questionTaskId: question.id,
|
|
255
|
+
answer: input.answer,
|
|
256
|
+
answeredBy: auth.id
|
|
257
|
+
});
|
|
258
|
+
return json(await launch(session), 202);
|
|
259
|
+
}
|
|
260
|
+
if ([
|
|
261
|
+
"interrupt",
|
|
262
|
+
"cancel",
|
|
263
|
+
"compact",
|
|
264
|
+
"clear",
|
|
265
|
+
"reset"
|
|
266
|
+
].includes(action ?? "")) {
|
|
267
|
+
const input = controlSchema.parse(await body(request));
|
|
268
|
+
const current = await view(session);
|
|
269
|
+
if (input.executionId !== void 0 && input.executionId !== current.execution?.sessionId) throw new ApiError(409, "Execution changed; refresh the session");
|
|
270
|
+
if ((action === "cancel" || action === "reset") && current.task !== null) {
|
|
271
|
+
if (![
|
|
272
|
+
"succeeded",
|
|
273
|
+
"failed",
|
|
274
|
+
"cancelled"
|
|
275
|
+
].includes(current.task.state)) await stores.tasks.transition(current.task.id, "cancelled", { reason: `Cancelled by ${auth.id}` });
|
|
276
|
+
if (current.question !== null) await stores.tasks.transition(current.question.id, "cancelled", { reason: "Parent task cancelled" });
|
|
277
|
+
if (current.execution !== null) {
|
|
278
|
+
const response = await proxy(session, request, "/cancel", input);
|
|
279
|
+
if (!response.ok) return response;
|
|
280
|
+
}
|
|
281
|
+
return json(await view(session));
|
|
282
|
+
}
|
|
283
|
+
return await proxy(session, request, `/${action === "interrupt" ? "cancel" : action}`, input);
|
|
284
|
+
}
|
|
285
|
+
throw new ApiError(404, "API route not found");
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (error instanceof ApiError) return json({ error: error.message }, error.status);
|
|
288
|
+
if (error instanceof z.ZodError) return json({
|
|
289
|
+
error: "Invalid request",
|
|
290
|
+
issues: error.issues
|
|
291
|
+
}, 400);
|
|
292
|
+
if (error instanceof RecordNotFoundError) return json({ error: error.message }, 404);
|
|
293
|
+
if (error instanceof VersionConflictError || error instanceof InvalidTransitionError || error instanceof SessionConflictError) return json({ error: error.message }, 409);
|
|
294
|
+
options.reportError?.(error);
|
|
295
|
+
return json({ error: "Factory request failed; retry with the same operationId or refresh the session" }, 500);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { handle };
|
|
299
|
+
}
|
|
300
|
+
async function body(request) {
|
|
301
|
+
const text = await request.text();
|
|
302
|
+
if (text.length > 64e3) throw new ApiError(413, "Request body is too large");
|
|
303
|
+
try {
|
|
304
|
+
return text.trim() === "" ? {} : JSON.parse(text);
|
|
305
|
+
} catch {
|
|
306
|
+
throw new ApiError(400, "Request body must be JSON");
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
310
|
+
export { apiAgentSchema, createFactoryApi, createSessionRequestSchema, sessionViewSchema };
|
|
311
|
+
|
|
312
|
+
//# sourceMappingURL=api.mjs.map
|
package/dist/api.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.mjs","names":[],"sources":["../src/api.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { type AgentRouteRegistry } from \"./agent-routes\";\nimport { BudgetExhaustedError, DispatchRefusedError, dispatchTask, type DispatchBudget } from \"./dispatch\";\nimport { changeIdSchema, taskIdSchema } from \"./schema/id\";\nimport { agentSessionSchema, type AgentSession } from \"./schema/session\";\nimport { taskSchema, executionReferenceSchema, type ExecutionReference, type Task } from \"./schema/task\";\nimport { InvalidTransitionError } from \"./schema/transitions\";\nimport { RecordNotFoundError, VersionConflictError } from \"./store/driver\";\nimport { SessionConflictError, type FactoryStores } from \"./store/engine\";\nimport type { Repository } from \"./schema/repository\";\n\nexport const apiAgentSchema = z.strictObject({\n id: z.string().regex(/^[a-z][a-z0-9-]{0,31}$/u).describe(\"Agent name selected at session creation.\"),\n description: z.string().describe(\"What this agent does.\"),\n routeId: z.string().optional().describe(\"Declared specialist route; absent for conversations.\"),\n requiresRepository: z.boolean().describe(\"Whether creation requires a configured repository.\"),\n requiresChange: z.boolean().describe(\"Whether creation requires an existing change ID.\"),\n});\nexport type ApiAgent = z.infer<typeof apiAgentSchema>;\n\nexport const createSessionRequestSchema = z.strictObject({\n operationId: z.string().trim().min(1).max(200).describe(\"Client-generated idempotency key; retain when retrying creation.\"),\n agent: apiAgentSchema.shape.id,\n repository: z.string().min(1).optional().describe(\"Configured owner/repo slug.\"),\n changeId: changeIdSchema.optional().describe(\"Existing change to review, verify, or continue.\"),\n message: agentSessionSchema.shape.message,\n});\nexport type CreateSessionRequest = z.infer<typeof createSessionRequestSchema>;\n\nexport const sessionViewSchema = z.strictObject({\n session: agentSessionSchema.describe(\"Durable interaction binding.\"),\n task: taskSchema.nullable().describe(\"Current task state, if workflow-backed.\"),\n execution: executionReferenceSchema.nullable().describe(\"Current execution; may change after recovery.\"),\n question: taskSchema.nullable().describe(\"Open Factory question requiring an authenticated answer.\"),\n});\nexport type SessionView = z.infer<typeof sessionViewSchema>;\n\nconst messageSchema = z.strictObject({\n message: agentSessionSchema.shape.message,\n turnPolicy: z.enum([\"steer\", \"queue\"]).default(\"steer\").describe(\"How to handle an active turn.\"),\n executionId: z.string().min(1).describe(\"Observed execution ID; stale writes are rejected.\"),\n});\nconst inputSchema = z.strictObject({\n executionId: z.string().min(1).describe(\"Observed provider session ID; rejects stale input responses.\"),\n inputResponses: z.array(z.strictObject({\n requestId: z.string().describe(\"Pending Eve input request ID.\"),\n optionId: z.string().optional().describe(\"Selected option ID, when answering a choice.\"),\n text: z.string().optional().describe(\"Freeform input response, when allowed.\"),\n })).min(1).describe(\"Responses to pending human-input requests.\"),\n});\nconst controlSchema = z.strictObject({\n executionId: z.string().min(1).optional().describe(\"Observed provider session ID; guards against a replaced execution.\"),\n turnId: z.string().min(1).optional().describe(\"Observed turn ID for cooperative interruption.\"),\n});\nconst answerSchema = z.strictObject({\n questionId: taskIdSchema.describe(\"Question Task belonging to this operator session.\"),\n answer: z.string().min(1).max(16000).describe(\"Authenticated human answer, persisted immutably.\"),\n});\n\nexport interface FactoryApiOptions {\n stores: FactoryStores;\n agents: readonly ApiAgent[];\n routes: AgentRouteRegistry;\n repositories: readonly string[];\n budget: DispatchBudget;\n authenticate(request: Request): Promise<{ id: string } | Response>;\n ensureRepository(slug: string): Promise<Repository>;\n start(session: AgentSession, task: Task | null, message: string, operationId: string): Promise<ExecutionReference>;\n forward(session: AgentSession, execution: ExecutionReference, path: string, request: Request): Promise<Response>;\n reportError?(error: unknown): void;\n}\n\nclass ApiError extends Error {\n constructor(readonly status: number, message: string) { super(message); }\n}\n\nconst json = (value: unknown, status = 200) => Response.json(value, {\n status, headers: { \"cache-control\": \"no-store\" },\n});\n\nexport function createFactoryApi(options: FactoryApiOptions) {\n const { stores } = options;\n const agents = options.agents.map((agent) => apiAgentSchema.parse(agent));\n if (new Set(agents.map((agent) => agent.id)).size !== agents.length) throw new Error(\"Duplicate API agent\");\n for (const agent of agents) {\n if (agent.routeId !== undefined && options.routes.get(agent.routeId)?.agent !== agent.id) {\n throw new Error(`API agent ${agent.id} must select one of its registered routes`);\n }\n }\n\n async function view(session: AgentSession): Promise<SessionView> {\n session = await stores.sessions.get(session.id) ?? session;\n const task = session.taskId === undefined ? null : await stores.tasks.get(session.taskId);\n const question = task?.questionTaskId === undefined ? null : await stores.tasks.get(task.questionTaskId);\n return {\n session, task, execution: task?.execution ?? session.execution ?? null,\n question: task?.state === \"needs_human\" && question?.state === \"needs_human\" ? question : null,\n };\n }\n\n async function assertRepository(id: string) {\n const repository = await stores.repositories.get(id);\n if (repository === null || !repository.enabled || !options.repositories.includes(repository.slug)) {\n throw new ApiError(403, \"The session repository is no longer enabled and configured\");\n }\n }\n\n async function owned(id: string, owner: string) {\n const session = await stores.sessions.get(id);\n if (session === null || session.owner !== owner) throw new ApiError(404, \"Session not found\");\n if (!agents.some((agent) => agent.id === session.agent)) throw new ApiError(409, \"Session agent is no longer configured\");\n if (session.repositoryId !== undefined) await assertRepository(session.repositoryId);\n return session;\n }\n\n async function launch(session: AgentSession) {\n if (session.taskId === undefined) {\n if (session.execution === undefined) {\n const execution = await options.start(session, null, session.message, `api:${session.id}`);\n session = await stores.sessions.bind(session.id, { execution });\n }\n } else {\n const task = await stores.tasks.get(session.taskId);\n if (task?.state === \"queued\") {\n const answers = await Promise.all((task.answerEventIds ?? []).map((id) => stores.answers.get(id)));\n const message = [\n `You are assigned Factory task ${task.id}. Read it before starting.`,\n session.changeId === undefined ? \"\" : `Existing change: ${session.changeId}.`,\n session.message,\n ...answers.flatMap((answer) => answer === null ? [] : [`${answer.question}\\nAnswer: ${answer.answer}`]),\n ].filter(Boolean).join(\"\\n\\n\");\n try {\n await dispatchTask(stores, task.id, {\n budget: options.budget,\n launch: (running) => options.start(session, running, message, `factory-task:${running.id}:${running.attempt}`),\n });\n } catch (error) {\n if (!(error instanceof DispatchRefusedError || error instanceof BudgetExhaustedError || error instanceof InvalidTransitionError || error instanceof VersionConflictError)) throw error;\n }\n }\n }\n return view(session);\n }\n\n async function create(request: Request, owner: string, conversation: boolean) {\n const input = createSessionRequestSchema.parse(await body(request));\n const agent = agents.find((candidate) => candidate.id === input.agent);\n if (agent === undefined) throw new ApiError(400, `Unknown agent. Choose: ${agents.map((item) => item.id).join(\", \")}`);\n if ((agent.routeId === undefined) !== conversation) throw new ApiError(400, conversation ? \"Specialist work must be submitted through POST /api/v1/signals\" : \"Use POST /api/v1/sessions for conversations\");\n if (agent.requiresRepository && input.repository === undefined) throw new ApiError(400, `${agent.id} requires a repository`);\n if (agent.requiresChange && input.changeId === undefined) throw new ApiError(400, `${agent.id} requires an existing changeId`);\n const slug = input.repository?.toLowerCase();\n if (slug !== undefined && !options.repositories.includes(slug)) throw new ApiError(403, \"Repository is not configured\");\n const repository = slug === undefined ? undefined : await options.ensureRepository(slug);\n if (repository !== undefined) await assertRepository(repository.id);\n if (input.changeId !== undefined) {\n const change = await stores.changes.get(input.changeId);\n if (change === null || change.repositoryId !== repository?.id) throw new ApiError(400, \"changeId must identify a change in the selected repository\");\n if (change.state !== \"verifying\" && change.state !== \"ready\") throw new ApiError(409, \"Change is no longer open for work\");\n }\n let session = await stores.sessions.create({\n operationId: input.operationId, owner, agent: agent.id, repositoryId: repository?.id,\n routeId: agent.routeId, message: input.message, changeId: input.changeId,\n });\n if (agent.routeId !== undefined && session.taskId === undefined) {\n const route = options.routes.get(agent.routeId)!;\n if (repository === undefined) throw new ApiError(400, \"Specialist work requires a repository\");\n const replyTo = { channel: \"api\", address: session.id };\n const signal = await stores.signals.create({\n repositoryId: repository.id, source: \"api\", deliveryId: session.id, replyTo,\n payload: { agent: agent.id, routeId: route.id, message: input.message, changeId: input.changeId },\n });\n if (signal.outcome === \"pending\") {\n try { await stores.signals.decide(signal.id, \"accepted\", { reason: `Authenticated operator selected ${route.id}` }); }\n catch (error) { if (!(error instanceof VersionConflictError || error instanceof InvalidTransitionError)) throw error; }\n }\n const task = await stores.tasks.create({\n repositoryIds: [repository.id], kind: route.taskKind, origin: { signalId: signal.id, operator: owner },\n replyTo, changeId: input.changeId, dedupeKey: `api:${session.id}`,\n });\n session = await stores.sessions.bind(session.id, { taskId: task.id });\n }\n return json(await launch(session), 202);\n }\n\n async function proxy(session: AgentSession, request: Request, suffix: string, payload?: unknown) {\n const current = await view(session);\n const observed = payload !== null && typeof payload === \"object\" && \"executionId\" in payload ? payload.executionId : new URL(request.url).searchParams.get(\"executionId\");\n if (current.execution === null) throw new ApiError(409, \"Execution is not available yet; refresh the session\");\n if (observed !== undefined && observed !== null && observed !== current.execution.sessionId) throw new ApiError(409, \"Execution changed; refresh the session before continuing\");\n if (request.method === \"POST\" && suffix !== \"/cancel\" && current.task !== null && current.task.state !== \"running\") {\n throw new ApiError(409, `Task is ${current.task.state}. Answer its question or create new work instead of messaging an inactive task`);\n }\n const upstream = new Request(request.url, {\n method: request.method, signal: request.signal,\n headers: { \"content-type\": \"application/json\" },\n ...(request.method === \"POST\" ? { body: JSON.stringify(payload !== null && typeof payload === \"object\" ? Object.fromEntries(Object.entries(payload).filter(([key]) => key !== \"executionId\")) : {}) } : {}),\n });\n const result = await options.forward(session, current.execution, suffix, upstream);\n const streamHeaders = Object.fromEntries([\"x-eve-session-id\", \"x-eve-stream-format\", \"x-eve-stream-version\", \"x-eve-stream-tail-index\"].flatMap((name) => {\n const value = result.headers.get(name);\n return value === null ? [] : [[name, value]];\n }));\n return new Response(result.body, { status: result.status, headers: {\n \"content-type\": result.headers.get(\"content-type\") ?? \"application/json\",\n \"cache-control\": \"no-store\", \"x-accel-buffering\": \"no\",\n ...streamHeaders,\n } });\n }\n\n async function handle(request: Request): Promise<Response> {\n try {\n const auth = await options.authenticate(request);\n if (auth instanceof Response) return auth;\n const url = new URL(request.url);\n const path = url.pathname.replace(/^\\/api\\/v1\\/?/u, \"\").split(\"/\").filter(Boolean);\n const [resource, id, action] = path;\n if (path.length > 3) throw new ApiError(404, \"API route not found\");\n if (request.method === \"GET\" && path.length === 1) {\n if (resource === \"agents\") return json({ agents });\n if (resource === \"repositories\") return json({ repositories: options.repositories });\n const requestedRepository = resource === \"changes\" ? url.searchParams.get(\"repository\") : null;\n if (requestedRepository !== null && !options.repositories.includes(requestedRepository)) throw new ApiError(403, \"Repository is not configured\");\n const enabledIds = new Set((await stores.repositories.list()).filter((repo) => repo.enabled && options.repositories.includes(repo.slug) && (requestedRepository === null || repo.slug === requestedRepository)).map((repo) => repo.id));\n if (resource === \"changes\") return json({ changes: (await stores.changes.list()).filter((change) => enabledIds.has(change.repositoryId) && (change.state === \"verifying\" || change.state === \"ready\")) });\n if (resource === \"sessions\") {\n const sessions = (await stores.sessions.list()).filter((session) => session.owner === auth.id && agents.some((agent) => agent.id === session.agent) && (session.repositoryId === undefined || enabledIds.has(session.repositoryId)))\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n return json({ sessions: await Promise.all(sessions.map(view)) });\n }\n if (resource === \"tasks\") return json({ tasks: (await stores.tasks.list()).filter((task) => task.origin.operator === auth.id && task.repositoryIds.every((id) => enabledIds.has(id))) });\n }\n if (request.method === \"POST\" && path.length === 1 && (resource === \"signals\" || resource === \"sessions\")) return await create(request, auth.id, resource === \"sessions\");\n if (resource !== \"sessions\" || id === undefined) throw new ApiError(404, \"API route not found\");\n const session = await owned(id, auth.id);\n if (request.method === \"GET\" && action === undefined) return json(await view(session));\n if (request.method === \"GET\" && action === \"stream\") {\n const query = new URLSearchParams();\n for (const name of [\"startIndex\", \"includeTailIndex\"]) {\n const value = url.searchParams.get(name);\n if (value !== null) query.set(name, value);\n }\n return await proxy(session, request, `/stream?${query}`);\n }\n if (request.method !== \"POST\") throw new ApiError(405, \"Use GET or POST for this route\");\n if (action === \"messages\") return await proxy(session, request, \"\", messageSchema.parse(await body(request)));\n if (action === \"input\") return await proxy(session, request, \"\", inputSchema.parse(await body(request)));\n if (action === \"dispatch\") return json(await launch(session), 202);\n if (action === \"answer\") {\n const input = answerSchema.parse(await body(request));\n const current = await view(session);\n const question = await stores.tasks.get(input.questionId);\n if (question === null || question.origin.parentTaskId !== current.task?.id || question.replyTo.channel !== \"api\" || question.replyTo.address !== session.id) {\n throw new ApiError(403, \"Question does not belong to this interaction\");\n }\n await stores.tasks.answerQuestion({ questionTaskId: question.id, answer: input.answer, answeredBy: auth.id });\n return json(await launch(session), 202);\n }\n if ([\"interrupt\", \"cancel\", \"compact\", \"clear\", \"reset\"].includes(action ?? \"\")) {\n const input = controlSchema.parse(await body(request));\n const current = await view(session);\n if (input.executionId !== undefined && input.executionId !== current.execution?.sessionId) throw new ApiError(409, \"Execution changed; refresh the session\");\n if ((action === \"cancel\" || action === \"reset\") && current.task !== null) {\n if (![\"succeeded\", \"failed\", \"cancelled\"].includes(current.task.state)) {\n await stores.tasks.transition(current.task.id, \"cancelled\", { reason: `Cancelled by ${auth.id}` });\n }\n if (current.question !== null) await stores.tasks.transition(current.question.id, \"cancelled\", { reason: \"Parent task cancelled\" });\n if (current.execution !== null) {\n const response = await proxy(session, request, \"/cancel\", input);\n if (!response.ok) return response;\n }\n return json(await view(session));\n }\n return await proxy(session, request, `/${action === \"interrupt\" ? \"cancel\" : action}`, input);\n }\n throw new ApiError(404, \"API route not found\");\n } catch (error) {\n if (error instanceof ApiError) return json({ error: error.message }, error.status);\n if (error instanceof z.ZodError) return json({ error: \"Invalid request\", issues: error.issues }, 400);\n if (error instanceof RecordNotFoundError) return json({ error: error.message }, 404);\n if (error instanceof VersionConflictError || error instanceof InvalidTransitionError || error instanceof SessionConflictError) return json({ error: error.message }, 409);\n options.reportError?.(error);\n return json({ error: \"Factory request failed; retry with the same operationId or refresh the session\" }, 500);\n }\n }\n return { handle };\n}\n\nasync function body(request: Request): Promise<unknown> {\n const text = await request.text();\n if (text.length > 64000) throw new ApiError(413, \"Request body is too large\");\n try { return text.trim() === \"\" ? {} : JSON.parse(text); }\n catch { throw new ApiError(400, \"Request body must be JSON\"); }\n}\n"],"mappings":"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"}
|