@fevex/core 0.1.0-alpha.0 → 0.1.0-alpha.10

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.
Files changed (52) hide show
  1. package/README.md +1110 -52
  2. package/dist/agents/index.d.mts +2 -23
  3. package/dist/agents/index.mjs +1 -1
  4. package/dist/artifacts/index.d.mts +2 -0
  5. package/dist/artifacts/index.mjs +2 -0
  6. package/dist/artifacts-gUzemET7.mjs +440 -0
  7. package/dist/channels/index.d.mts +2 -0
  8. package/dist/channels/index.mjs +192 -0
  9. package/dist/evals/index.d.mts +153 -0
  10. package/dist/evals/index.mjs +422 -0
  11. package/dist/fevex-_KOsOsB8.d.mts +129 -0
  12. package/dist/http/index.d.mts +150 -0
  13. package/dist/http/index.mjs +692 -0
  14. package/dist/index-26ilbzAs.d.mts +50 -0
  15. package/dist/index-B8EcvWeN.d.mts +103 -0
  16. package/dist/index-BEqYWean.d.mts +118 -0
  17. package/dist/index-Btth7rdL.d.mts +58 -0
  18. package/dist/index-CFzrvDQ0.d.mts +21 -0
  19. package/dist/index-CIHWc5V1.d.mts +116 -0
  20. package/dist/index-D7r0puBi.d.mts +64 -0
  21. package/dist/index-DHcfIfh-.d.mts +224 -0
  22. package/dist/index-DUhNa7IR.d.mts +73 -0
  23. package/dist/index-lCCFokc6.d.mts +617 -0
  24. package/dist/index.d.mts +39 -15
  25. package/dist/index.mjs +4962 -208
  26. package/dist/knowledge/index.d.mts +2 -0
  27. package/dist/knowledge/index.mjs +289 -0
  28. package/dist/model-stream-JQdHDDcj.mjs +131 -0
  29. package/dist/models/index.d.mts +2 -27
  30. package/dist/observability/index.d.mts +2 -0
  31. package/dist/observability/index.mjs +1 -0
  32. package/dist/policies/index.d.mts +2 -0
  33. package/dist/policies/index.mjs +6 -0
  34. package/dist/run-error-Cr17wPGH.mjs +23 -0
  35. package/dist/run-support-CmZ6Xo6H.mjs +162 -0
  36. package/dist/runtime/index.d.mts +2 -17
  37. package/dist/runtime/index.mjs +354 -1
  38. package/dist/sandbox/index.d.mts +2 -0
  39. package/dist/sandbox/index.mjs +147 -0
  40. package/dist/teams/index.d.mts +2 -0
  41. package/dist/teams/index.mjs +2 -0
  42. package/dist/teams-Ctz676G4.mjs +82 -0
  43. package/dist/testing/index.d.mts +40 -8
  44. package/dist/testing/index.mjs +668 -23
  45. package/dist/tools/index.d.mts +3 -31
  46. package/dist/tools/index.mjs +442 -2
  47. package/dist/types-CckDlhYo.d.mts +575 -0
  48. package/dist/workflows/index.d.mts +2 -0
  49. package/dist/workflows/index.mjs +6 -0
  50. package/package.json +43 -3
  51. package/dist/exact-definition-NHBBFlFR.d.mts +0 -4
  52. package/dist/index-D_RBJmVt.d.mts +0 -44
@@ -1,17 +1,2 @@
1
- import { a as ExecutionContext, t as AgentEvent } from "../index-D_RBJmVt.mjs";
2
- import { ModelUsage } from "../models/index.mjs";
3
- import { StandardSchemaV1 } from "@standard-schema/spec";
4
- //#region src/runtime/index.d.ts
5
- interface RunRequest<TInput = unknown, TOutput = unknown> {
6
- input: TInput;
7
- context?: ExecutionContext;
8
- outputSchema?: StandardSchemaV1<unknown, TOutput>;
9
- signal?: AbortSignal;
10
- }
11
- interface RunResult<TOutput = unknown> {
12
- output: TOutput;
13
- events?: AgentEvent[];
14
- usage?: ModelUsage;
15
- }
16
- //#endregion
17
- export { RunRequest, RunResult };
1
+ import { $ as SessionCompaction, A as ElicitationMode, B as ResumeRunResolution, C as ApprovalMode, D as CoordinatorRun, E as CoordinatorCheckpoint, F as ExecutionCreate, G as RunLease, H as RetainableRunStore, I as ListEventsOptions, J as RunRequest, K as RunPause, L as PendingToolExecution, M as ElicitationResolution, N as EventResolution, O as CredentialStore, P as ExecutionCommit, Q as Session, R as PurgeRunsOptions, S as AgentRunPause, T as ApprovalResolution, U as RunCheckpoint, V as RetainableRunStatus, W as RunCorrelation, X as RunStatus, Y as RunResult, Z as RunStore, _ as createDigestContextCompactor, _t as validatePurgeRunsOptions, at as ToolExecutionRecord, b as resolveContextBudget, c as InMemoryRunStore, ct as WorkflowBudgetUsage, d as ContextCompactionStats, dt as WorkflowRun, et as SessionId, f as ContextCompactor, ft as WorkflowStepRecord, g as ResolvedContextBudget, gt as validateListEventsOptions, h as ModelContextCompactorOptions, ht as isRetainableRunStore, it as TimerResolution, j as ElicitationRequest, k as DurableRunStore, l as ContextCompactionInput, lt as WorkflowCheckpoint, m as DigestContextCompactorOptions, mt as isDurableRunStore, nt as TeamCheckpoint, ot as ToolExecutionResolution, p as ContextTokenEstimator, pt as WorkflowWaitRecord, q as RunRecord, rt as TeamRun, st as ToolExecutionStatus, tt as StoredRunCheckpoint, u as ContextCompactionOptions, ut as WorkflowCompensationRecord, v as createModelContextCompactor, w as ApprovalRequest, x as AgentRun, y as estimateContextTokens, z as PurgeRunsResult } from "../index-lCCFokc6.mjs";
2
+ export { AgentRun, AgentRunPause, ApprovalMode, ApprovalRequest, ApprovalResolution, ContextCompactionInput, ContextCompactionOptions, ContextCompactionStats, ContextCompactor, ContextTokenEstimator, CoordinatorCheckpoint, CoordinatorRun, CredentialStore, DigestContextCompactorOptions, DurableRunStore, ElicitationMode, ElicitationRequest, ElicitationResolution, EventResolution, ExecutionCommit, ExecutionCreate, InMemoryRunStore, ListEventsOptions, ModelContextCompactorOptions, PendingToolExecution, PurgeRunsOptions, PurgeRunsResult, ResolvedContextBudget, ResumeRunResolution, RetainableRunStatus, RetainableRunStore, RunCheckpoint, RunCorrelation, RunLease, RunPause, RunRecord, RunRequest, RunResult, RunStatus, RunStore, Session, SessionCompaction, SessionId, StoredRunCheckpoint, TeamCheckpoint, TeamRun, TimerResolution, ToolExecutionRecord, ToolExecutionResolution, ToolExecutionStatus, WorkflowBudgetUsage, WorkflowCheckpoint, WorkflowCompensationRecord, WorkflowRun, WorkflowStepRecord, WorkflowWaitRecord, createDigestContextCompactor, createModelContextCompactor, estimateContextTokens, isDurableRunStore, isRetainableRunStore, resolveContextBudget, validateListEventsOptions, validatePurgeRunsOptions };
@@ -1 +1,354 @@
1
- export {};
1
+ import { t as FevexRunError } from "../run-error-Cr17wPGH.mjs";
2
+ //#region src/runtime/compaction.ts
3
+ /** Validates a context budget and fills in defaults. */
4
+ function resolveContextBudget(budget, label) {
5
+ if (budget === void 0) return void 0;
6
+ if (!isRecord(budget)) throw new TypeError(`${label} must be an object`);
7
+ const contextWindow = budget.contextWindow;
8
+ if (!Number.isSafeInteger(contextWindow) || contextWindow <= 0) throw new TypeError(`${label}.contextWindow must be a positive safe integer`);
9
+ const reserveOutputTokens = budget.reserveOutputTokens ?? 0;
10
+ if (!Number.isSafeInteger(reserveOutputTokens) || reserveOutputTokens < 0 || reserveOutputTokens >= contextWindow) throw new TypeError(`${label}.reserveOutputTokens must be a non-negative safe integer below contextWindow`);
11
+ const usable = contextWindow - reserveOutputTokens;
12
+ const compactAt = budget.compactAt ?? .8;
13
+ if (typeof compactAt !== "number" || !Number.isFinite(compactAt) || compactAt <= 0 || compactAt > 1) throw new TypeError(`${label}.compactAt must be greater than 0 and at most 1`);
14
+ const targetTokens = budget.targetTokens ?? Math.max(1, Math.floor(usable * Math.min(.5, compactAt * .9)));
15
+ if (!Number.isSafeInteger(targetTokens) || targetTokens <= 0 || targetTokens >= usable) throw new TypeError(`${label}.targetTokens must be a positive safe integer below the usable window`);
16
+ if (targetTokens > Math.floor(usable * compactAt)) throw new TypeError(`${label}.targetTokens must not exceed the compaction threshold`);
17
+ const safetyFactor = budget.safetyFactor ?? 1.1;
18
+ if (typeof safetyFactor !== "number" || !Number.isFinite(safetyFactor) || safetyFactor < 1 || safetyFactor > 2) throw new TypeError(`${label}.safetyFactor must be between 1 and 2`);
19
+ return {
20
+ contextWindow,
21
+ reserveOutputTokens,
22
+ compactAt,
23
+ targetTokens,
24
+ safetyFactor
25
+ };
26
+ }
27
+ /**
28
+ * Rough provider-neutral estimate: about four characters per token plus
29
+ * message and tool framing. Hosts can inject a real tokenizer instead.
30
+ */
31
+ function estimateContextTokens(input) {
32
+ let characters = 0;
33
+ for (const message of input.messages) {
34
+ characters += message.role.length + message.content.length + 16;
35
+ if (message.name !== void 0) characters += message.name.length;
36
+ if (message.toolCallId !== void 0) characters += message.toolCallId.length;
37
+ if (message.toolCalls !== void 0) characters += JSON.stringify(message.toolCalls).length;
38
+ }
39
+ if (input.tools?.length) characters += JSON.stringify(input.tools).length;
40
+ return Math.max(1, Math.ceil(characters / 4));
41
+ }
42
+ const DEFAULT_COMPACTOR_PROMPT = "You compact conversation history for another agent. Preserve decisions, approvals, constraints, identifiers, tool results and open tasks. Return only the summary.";
43
+ /**
44
+ * Creates a semantic compactor backed by a model. Use a cheap, fast model and
45
+ * keep it separate from the agent model when possible. Large transcripts are
46
+ * summarized in chunks and then merged.
47
+ */
48
+ function createModelContextCompactor(options) {
49
+ const maxOutputTokens = options.maxOutputTokens ?? 1024;
50
+ if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens <= 0) throw new TypeError("Model compactor maxOutputTokens must be a positive safe integer");
51
+ const maxInputChars = options.maxInputChars ?? 12e4;
52
+ if (!Number.isSafeInteger(maxInputChars) || maxInputChars < 1e3) throw new TypeError("Model compactor maxInputChars must be a safe integer of at least 1,000");
53
+ const systemPrompt = options.systemPrompt ?? DEFAULT_COMPACTOR_PROMPT;
54
+ const summarize = async (text, instruction, signal) => {
55
+ const stream = options.model.stream({
56
+ messages: [{
57
+ role: "system",
58
+ content: systemPrompt
59
+ }, {
60
+ role: "user",
61
+ content: `${instruction}\n\n${text || "(empty)"}`
62
+ }],
63
+ maxOutputTokens,
64
+ ...signal === void 0 ? {} : { signal }
65
+ });
66
+ let deltas = "";
67
+ let output;
68
+ for await (const event of stream) if (event.type === "output.delta") deltas += event.delta;
69
+ else output = event.result.output;
70
+ const summary = typeof output === "string" ? output : deltas;
71
+ if (!summary.trim()) throw new Error("Model context compactor returned an empty summary");
72
+ return summary.trim();
73
+ };
74
+ return { async compact(input) {
75
+ let current = formatTranscript(input.messages);
76
+ let depth = 0;
77
+ while (current.length > maxInputChars && depth < 4) {
78
+ const summaries = [];
79
+ for (const chunk of splitText(current, maxInputChars)) summaries.push(await summarize(chunk, "Summarize this part of a longer conversation. Preserve decisions, constraints, identifiers, tool results and open tasks.", input.signal));
80
+ current = summaries.join("\n\n");
81
+ depth += 1;
82
+ }
83
+ if (current.length > maxInputChars) current = `${current.slice(0, maxInputChars - 1)}…`;
84
+ return [{
85
+ role: "system",
86
+ content: await summarize(current, `Merge the following into one summary in at most ${input.targetTokens} tokens.`, input.signal)
87
+ }];
88
+ } };
89
+ }
90
+ function formatTranscript(messages) {
91
+ return messages.map((message) => {
92
+ const toolCalls = message.toolCalls?.length ? `\nTool calls: ${message.toolCalls.map((call) => `${call.name}(${JSON.stringify(call.input)})`).join(", ")}` : "";
93
+ const name = message.name === void 0 ? "" : ` (${message.name})`;
94
+ return `${message.role}${name}: ${message.content}${toolCalls}`;
95
+ }).join("\n\n");
96
+ }
97
+ function splitText(text, maxChars) {
98
+ const chunks = [];
99
+ let rest = text;
100
+ while (rest.length > maxChars) {
101
+ let cut = rest.lastIndexOf("\n", maxChars);
102
+ if (cut < Math.floor(maxChars / 2)) cut = maxChars;
103
+ chunks.push(rest.slice(0, cut));
104
+ rest = rest.slice(cut).trimStart();
105
+ }
106
+ if (rest) chunks.push(rest);
107
+ return chunks;
108
+ }
109
+ /**
110
+ * Deterministic compactor used when the host does not inject one. It keeps
111
+ * role-aware excerpts of older messages and drops the oldest excerpts first.
112
+ * It never calls a model.
113
+ */
114
+ function createDigestContextCompactor(options = {}) {
115
+ const maxChars = options.maxCharsPerMessage ?? 400;
116
+ if (!Number.isSafeInteger(maxChars) || maxChars < 40) throw new TypeError("Digest compactor maxCharsPerMessage must be a safe integer of at least 40");
117
+ return { compact(input) {
118
+ if (input.messages.length === 0) return [{
119
+ role: "system",
120
+ content: "[Compacted earlier conversation]"
121
+ }];
122
+ let perMessage = maxChars;
123
+ let lines = input.messages.flatMap((message) => digestMessage(message, perMessage));
124
+ while (input.estimateTokens([{
125
+ role: "system",
126
+ content: digestContent(lines, input.messages.length)
127
+ }]) > input.targetTokens && perMessage > 40) {
128
+ perMessage = Math.max(40, Math.floor(perMessage * .7));
129
+ lines = input.messages.flatMap((message) => digestMessage(message, perMessage));
130
+ }
131
+ let selected = lines;
132
+ let content = digestContent(selected, input.messages.length);
133
+ while (input.estimateTokens([{
134
+ role: "system",
135
+ content
136
+ }]) > input.targetTokens && selected.length > 1) {
137
+ selected = selected.slice(1);
138
+ content = digestContent(selected, input.messages.length);
139
+ }
140
+ const limit = Math.max(80, input.targetTokens * 4);
141
+ if (content.length > limit) content = `${content.slice(0, Math.max(0, limit - 1))}…`;
142
+ return [{
143
+ role: "system",
144
+ content
145
+ }];
146
+ } };
147
+ }
148
+ function digestContent(lines, totalMessages) {
149
+ const omitted = Math.max(0, totalMessages - lines.length);
150
+ return [`[Compacted conversation: ${totalMessages} earlier messages${omitted ? `, ${omitted} omitted` : ""}]`, ...lines].join("\n");
151
+ }
152
+ function digestMessage(message, maxChars) {
153
+ const content = truncate(message.content, maxChars);
154
+ if (message.role === "user") return content ? [`User: ${content}`] : [];
155
+ if (message.role === "assistant") {
156
+ const lines = [];
157
+ if (content) lines.push(`Assistant: ${content}`);
158
+ for (const call of message.toolCalls ?? []) lines.push(`Tool call ${call.name}: ${truncate(JSON.stringify(call.input), Math.min(maxChars, 200))}`);
159
+ return lines;
160
+ }
161
+ if (message.role === "tool") return content ? [`Tool result${message.name === void 0 ? "" : ` (${message.name})`}: ${content}`] : [];
162
+ return content ? [`System: ${content}`] : [];
163
+ }
164
+ function truncate(value, maxChars) {
165
+ const normalized = value.replace(/\s+/g, " ").trim();
166
+ if (normalized.length <= maxChars) return normalized;
167
+ return `${normalized.slice(0, Math.max(0, maxChars - 1))}…`;
168
+ }
169
+ function isRecord(value) {
170
+ return typeof value === "object" && value !== null && !Array.isArray(value);
171
+ }
172
+ //#endregion
173
+ //#region src/runtime/run-store.ts
174
+ function validateListEventsOptions(options) {
175
+ if (options.limit !== void 0 && (!Number.isSafeInteger(options.limit) || options.limit < 1)) throw new TypeError("Event limit must be a positive safe integer");
176
+ if (options.order !== void 0 && options.order !== "asc" && options.order !== "desc") throw new TypeError("Event order must be asc or desc");
177
+ }
178
+ function isRetainableRunStore(store) {
179
+ return typeof store.purgeRuns === "function";
180
+ }
181
+ function validatePurgeRunsOptions(options = {}) {
182
+ const statuses = options.statuses ?? [
183
+ "completed",
184
+ "failed",
185
+ "cancelled"
186
+ ];
187
+ if (statuses.length === 0 || statuses.some((status) => status !== "completed" && status !== "failed" && status !== "cancelled")) throw new TypeError("Purge statuses must contain only completed, failed or cancelled");
188
+ if (options.before !== void 0 && Number.isNaN(Date.parse(options.before))) throw new TypeError("Purge before must be an ISO timestamp");
189
+ if (options.limit !== void 0 && (!Number.isSafeInteger(options.limit) || options.limit < 1)) throw new TypeError("Purge limit must be a positive safe integer");
190
+ return {
191
+ statuses,
192
+ ...options.before === void 0 ? {} : { before: new Date(options.before).toISOString() },
193
+ ...options.limit === void 0 ? {} : { limit: options.limit }
194
+ };
195
+ }
196
+ function isDurableRunStore(store) {
197
+ const value = store;
198
+ return [
199
+ value.getCheckpoint,
200
+ value.getToolExecution,
201
+ value.createExecution,
202
+ value.commitExecution,
203
+ value.acquireLease,
204
+ value.renewLease,
205
+ value.releaseLease
206
+ ].every((method) => typeof method === "function");
207
+ }
208
+ //#endregion
209
+ //#region src/runtime/in-memory-run-store.ts
210
+ /**
211
+ * In-process durable store intended for development and tests.
212
+ *
213
+ * Values are cloned at the boundary so callers cannot mutate persisted state.
214
+ * Data is lost when the process exits.
215
+ */
216
+ var InMemoryRunStore = class {
217
+ #runs = /* @__PURE__ */ new Map();
218
+ #sessions = /* @__PURE__ */ new Map();
219
+ #events = /* @__PURE__ */ new Map();
220
+ #checkpoints = /* @__PURE__ */ new Map();
221
+ #toolExecutions = /* @__PURE__ */ new Map();
222
+ #leases = /* @__PURE__ */ new Map();
223
+ async getRun(runId) {
224
+ const run = this.#runs.get(runId);
225
+ return run === void 0 ? void 0 : structuredClone(run);
226
+ }
227
+ async saveRun(run) {
228
+ this.#runs.set(run.id, structuredClone(run));
229
+ if (!this.#events.has(run.id)) this.#events.set(run.id, []);
230
+ }
231
+ async getSession(sessionId) {
232
+ const session = this.#sessions.get(sessionId);
233
+ return session === void 0 ? void 0 : structuredClone(session);
234
+ }
235
+ async saveSession(session) {
236
+ const current = this.#sessions.get(session.id);
237
+ if (this.#sessionBusy(session.id) || (current?.revision ?? 0) !== (session.revision ?? 0)) throw new FevexRunError("RUN_CONFLICT", `Session "${session.id}" is active or was modified`);
238
+ session.revision = (session.revision ?? 0) + 1;
239
+ this.#sessions.set(session.id, structuredClone(session));
240
+ }
241
+ async appendEvent(event) {
242
+ const events = this.#events.get(event.runId);
243
+ if (!events) throw new Error(`Run "${event.runId}" does not exist`);
244
+ events.push(structuredClone(event));
245
+ }
246
+ async listEvents(runId, options = {}) {
247
+ validateListEventsOptions(options);
248
+ const events = this.#events.get(runId);
249
+ if (!events) throw new Error(`Run "${runId}" does not exist`);
250
+ let start = 0;
251
+ if (options.after !== void 0) {
252
+ const cursor = events.findIndex(({ id }) => id === options.after);
253
+ if (cursor < 0) throw new FevexRunError("INVALID_CURSOR", `Event cursor "${options.after}" does not exist in run "${runId}"`, runId);
254
+ start = cursor + 1;
255
+ }
256
+ const sequence = start ? events[start - 1].sequence : -1;
257
+ const ordered = events.filter((event) => event.sequence > sequence).sort((a, b) => options.order === "desc" ? b.sequence - a.sequence : a.sequence - b.sequence);
258
+ return structuredClone(ordered.slice(0, options.limit));
259
+ }
260
+ async getCheckpoint(runId) {
261
+ const checkpoint = this.#checkpoints.get(runId);
262
+ return checkpoint === void 0 ? void 0 : structuredClone(checkpoint);
263
+ }
264
+ async getToolExecution(runId, toolCallId) {
265
+ const execution = this.#toolExecutions.get(`${runId}:${toolCallId}`);
266
+ return execution === void 0 ? void 0 : structuredClone(execution);
267
+ }
268
+ async createExecution(create) {
269
+ if (this.#runs.has(create.run.id)) return false;
270
+ const session = create.session;
271
+ const currentSession = this.#sessions.get(create.run.sessionId);
272
+ if (!session || session.id !== create.run.sessionId || this.#sessionBusy(session.id) || (currentSession?.revision ?? 0) !== (session.revision ?? 0)) return false;
273
+ const run = structuredClone(create.run);
274
+ run.revision = 1;
275
+ this.#runs.set(run.id, run);
276
+ create.run.revision = 1;
277
+ session.revision = (session.revision ?? 0) + 1;
278
+ this.#sessions.set(session.id, structuredClone(session));
279
+ this.#events.set(run.id, structuredClone(create.events));
280
+ this.#checkpoints.set(run.id, structuredClone(create.checkpoint));
281
+ create.lease.generation = 1;
282
+ this.#leases.set(run.id, structuredClone(create.lease));
283
+ return true;
284
+ }
285
+ async commitExecution(commit) {
286
+ const current = this.#runs.get(commit.run.id);
287
+ if (!current || current.revision !== commit.expectedRevision) return false;
288
+ const lease = this.#leases.get(commit.run.id);
289
+ if (!lease || !commit.lease || !(commit.lease.generation > 0) || lease.ownerId !== commit.lease.ownerId || lease.generation !== commit.lease.generation || !(Date.parse(lease.expiresAt) > Date.now())) return false;
290
+ if (commit.session && (commit.session.id !== current.sessionId || (this.#sessions.get(current.sessionId)?.revision ?? 0) !== (commit.session.revision ?? 0) || this.#sessionBusy(current.sessionId, current.id))) return false;
291
+ const run = structuredClone(commit.run);
292
+ run.revision = commit.expectedRevision + 1;
293
+ this.#runs.set(run.id, run);
294
+ commit.run.revision = run.revision;
295
+ if (commit.session) {
296
+ commit.session.revision = (commit.session.revision ?? 0) + 1;
297
+ this.#sessions.set(commit.session.id, structuredClone(commit.session));
298
+ }
299
+ if (commit.checkpoint === null) this.#checkpoints.delete(run.id);
300
+ else if (commit.checkpoint) this.#checkpoints.set(run.id, structuredClone(commit.checkpoint));
301
+ if (commit.toolExecution) this.#toolExecutions.set(`${run.id}:${commit.toolExecution.toolCallId}`, structuredClone(commit.toolExecution));
302
+ const events = this.#events.get(run.id);
303
+ if (!events) throw new Error(`Run "${run.id}" does not exist`);
304
+ for (const event of commit.events ?? []) events.push(structuredClone(event));
305
+ return true;
306
+ }
307
+ #sessionBusy(sessionId, exceptRunId) {
308
+ return [...this.#runs.values()].some((run) => run.sessionId === sessionId && run.id !== exceptRunId && (run.status === "running" || run.status === "paused"));
309
+ }
310
+ async purgeRuns(options = {}) {
311
+ const { statuses, before, limit } = validatePurgeRunsOptions(options);
312
+ const allowed = new Set(statuses);
313
+ const beforeTime = before === void 0 ? void 0 : Date.parse(before);
314
+ const candidates = [...this.#runs.entries()].filter(([, run]) => allowed.has(run.status) && (beforeTime === void 0 || Date.parse(run.createdAt) < beforeTime)).sort(([, first], [, second]) => Date.parse(first.createdAt) - Date.parse(second.createdAt)).slice(0, limit);
315
+ for (const [runId] of candidates) {
316
+ this.#runs.delete(runId);
317
+ this.#events.delete(runId);
318
+ this.#checkpoints.delete(runId);
319
+ this.#leases.delete(runId);
320
+ for (const key of this.#toolExecutions.keys()) if (key.startsWith(`${runId}:`)) this.#toolExecutions.delete(key);
321
+ }
322
+ const affectedSessions = new Set(candidates.map(([, run]) => run.sessionId));
323
+ const usedSessions = new Set([...this.#runs.values()].map(({ sessionId }) => sessionId));
324
+ let sessions = 0;
325
+ for (const sessionId of affectedSessions) {
326
+ if (usedSessions.has(sessionId)) continue;
327
+ if (this.#sessions.delete(sessionId)) sessions += 1;
328
+ }
329
+ return {
330
+ runs: candidates.length,
331
+ sessions
332
+ };
333
+ }
334
+ async acquireLease(lease) {
335
+ const current = this.#leases.get(lease.runId);
336
+ if (current && Date.parse(current.expiresAt) > Date.now()) return false;
337
+ lease.generation = (current?.generation ?? 0) + 1;
338
+ this.#leases.set(lease.runId, structuredClone(lease));
339
+ return true;
340
+ }
341
+ async renewLease(lease) {
342
+ const current = this.#leases.get(lease.runId);
343
+ if (!current || current.ownerId !== lease.ownerId || current.generation !== lease.generation || !(Date.parse(current.expiresAt) > Date.now())) return false;
344
+ this.#leases.set(lease.runId, structuredClone(lease));
345
+ return true;
346
+ }
347
+ async releaseLease(runId, ownerId, generation) {
348
+ if (!(generation > 0)) return;
349
+ const current = this.#leases.get(runId);
350
+ if (current?.ownerId === ownerId && current.generation === generation) current.expiresAt = (/* @__PURE__ */ new Date(0)).toISOString();
351
+ }
352
+ };
353
+ //#endregion
354
+ export { InMemoryRunStore, createDigestContextCompactor, createModelContextCompactor, estimateContextTokens, isDurableRunStore, isRetainableRunStore, resolveContextBudget, validateListEventsOptions, validatePurgeRunsOptions };
@@ -0,0 +1,2 @@
1
+ import { a as SandboxError, c as sandboxResultToJson, i as SandboxCapabilities, n as createLocalSandbox, o as SandboxRunRequest, r as Sandbox, s as SandboxRunResult, t as LocalSandboxOptions } from "../index-DUhNa7IR.mjs";
2
+ export { LocalSandboxOptions, Sandbox, SandboxCapabilities, SandboxError, SandboxRunRequest, SandboxRunResult, createLocalSandbox, sandboxResultToJson };
@@ -0,0 +1,147 @@
1
+ import { relative, resolve } from "node:path";
2
+ import { spawn } from "node:child_process";
3
+ import { realpathSync } from "node:fs";
4
+ //#region src/sandbox/sandbox.ts
5
+ var SandboxError = class extends Error {
6
+ code;
7
+ safeMessage;
8
+ name = "SandboxError";
9
+ constructor(code, safeMessage, options) {
10
+ super(safeMessage, options);
11
+ this.code = code;
12
+ this.safeMessage = safeMessage;
13
+ }
14
+ };
15
+ function sandboxResultToJson(result) {
16
+ return {
17
+ exitCode: result.exitCode,
18
+ stdout: result.stdout,
19
+ stderr: result.stderr,
20
+ durationMs: result.durationMs,
21
+ timedOut: result.timedOut
22
+ };
23
+ }
24
+ //#endregion
25
+ //#region src/sandbox/local-sandbox.ts
26
+ /** Creates a subprocess sandbox restricted to a root directory and command allowlist. */
27
+ function createLocalSandbox(options) {
28
+ if (!options.rootDir.trim()) throw new SandboxError("SANDBOX_INVALID_CONFIG", "Sandbox rootDir must be non-empty");
29
+ if (!options.commands.length || options.commands.some((command) => !command.trim())) throw new SandboxError("SANDBOX_INVALID_CONFIG", "Sandbox commands allowlist must contain non-empty commands");
30
+ const rootDir = realpathSync(resolve(options.rootDir));
31
+ const allowed = new Set(options.commands);
32
+ const defaultTimeoutMs = options.defaultTimeoutMs ?? 1e4;
33
+ const maxOutputBytes = options.maxOutputBytes ?? 64e3;
34
+ return { async run(request) {
35
+ if (request.capabilities?.network) throw new SandboxError("SANDBOX_NETWORK_UNSUPPORTED", "Local sandbox does not support network access");
36
+ const command = request.command;
37
+ if (!allowed.has(command) || !request.capabilities?.process?.commands?.includes(command)) throw new SandboxError("SANDBOX_COMMAND_DENIED", `Command "${command}" is not allowed`);
38
+ const cwd = resolve(rootDir, request.cwd ?? request.capabilities.filesystem?.cwd ?? ".");
39
+ if (!isInside(rootDir, cwd)) throw new SandboxError("SANDBOX_CWD_DENIED", "Sandbox cwd must stay inside rootDir");
40
+ const timeoutMs = request.timeoutMs ?? request.capabilities.resources?.timeoutMs ?? request.capabilities.process.timeoutMs ?? defaultTimeoutMs;
41
+ const outputLimit = request.maxOutputBytes ?? request.capabilities.resources?.maxOutputBytes ?? maxOutputBytes;
42
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 1) throw new SandboxError("SANDBOX_INVALID_REQUEST", "Sandbox timeoutMs must be positive");
43
+ if (!Number.isInteger(outputLimit) || outputLimit < 1) throw new SandboxError("SANDBOX_INVALID_REQUEST", "Sandbox maxOutputBytes must be positive");
44
+ return runProcess({
45
+ command,
46
+ args: request.args ?? [],
47
+ cwd,
48
+ env: {
49
+ ...options.env ?? {},
50
+ ...request.env ?? {}
51
+ },
52
+ input: request.input,
53
+ timeoutMs,
54
+ maxOutputBytes: outputLimit,
55
+ signal: request.signal
56
+ });
57
+ } };
58
+ }
59
+ async function runProcess(options) {
60
+ const started = Date.now();
61
+ let timedOut = false;
62
+ const stdout = {
63
+ text: "",
64
+ bytes: 0
65
+ };
66
+ const stderr = {
67
+ text: "",
68
+ bytes: 0
69
+ };
70
+ return await new Promise((resolvePromise, reject) => {
71
+ options.signal?.throwIfAborted();
72
+ const child = spawn(options.command, [...options.args], {
73
+ cwd: options.cwd,
74
+ env: options.env,
75
+ shell: false,
76
+ stdio: [
77
+ "pipe",
78
+ "pipe",
79
+ "pipe"
80
+ ]
81
+ });
82
+ let aborted = false;
83
+ let killTimer;
84
+ const terminate = () => {
85
+ if (killTimer !== void 0) return;
86
+ child.kill("SIGTERM");
87
+ killTimer = setTimeout(() => child.kill("SIGKILL"), 100);
88
+ };
89
+ const abort = () => {
90
+ aborted = true;
91
+ clearTimeout(timer);
92
+ terminate();
93
+ };
94
+ const timer = setTimeout(() => {
95
+ timedOut = true;
96
+ terminate();
97
+ }, options.timeoutMs);
98
+ const cleanup = () => {
99
+ clearTimeout(timer);
100
+ clearTimeout(killTimer);
101
+ options.signal?.removeEventListener("abort", abort);
102
+ };
103
+ options.signal?.addEventListener("abort", abort, { once: true });
104
+ if (options.signal?.aborted) abort();
105
+ child.stdout.setEncoding("utf8");
106
+ child.stderr.setEncoding("utf8");
107
+ child.stdout.on("data", (chunk) => {
108
+ appendLimited(stdout, String(chunk), options.maxOutputBytes);
109
+ });
110
+ child.stderr.on("data", (chunk) => {
111
+ appendLimited(stderr, String(chunk), options.maxOutputBytes);
112
+ });
113
+ child.on("error", (error) => {
114
+ cleanup();
115
+ reject(new SandboxError("SANDBOX_PROCESS_ERROR", "Sandbox process failed", { cause: error }));
116
+ });
117
+ child.on("close", (exitCode) => {
118
+ cleanup();
119
+ if (aborted) {
120
+ reject(options.signal?.reason ?? new DOMException("Sandbox aborted", "AbortError"));
121
+ return;
122
+ }
123
+ resolvePromise({
124
+ exitCode,
125
+ stdout: stdout.text,
126
+ stderr: stderr.text,
127
+ durationMs: Date.now() - started,
128
+ timedOut
129
+ });
130
+ });
131
+ if (options.input !== void 0) child.stdin.end(options.input);
132
+ else child.stdin.end();
133
+ });
134
+ }
135
+ function appendLimited(output, chunk, maxBytes) {
136
+ const remaining = maxBytes - output.bytes;
137
+ if (remaining <= 0) return;
138
+ const bytes = Buffer.from(chunk).subarray(0, remaining);
139
+ output.bytes += bytes.length;
140
+ output.text += new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes, { stream: true });
141
+ }
142
+ function isInside(rootDir, value) {
143
+ const path = relative(rootDir, value);
144
+ return path === "" || !path.startsWith("..") && !resolve(path).startsWith("..");
145
+ }
146
+ //#endregion
147
+ export { SandboxError, createLocalSandbox, sandboxResultToJson };
@@ -0,0 +1,2 @@
1
+ import { a as TeamMember, c as defineTeam, i as TeamLimits, n as TeamDelegation, o as TeamStep, r as TeamHandoff, s as TeamTaskResult, t as TeamDefinition } from "../index-26ilbzAs.mjs";
2
+ export { type TeamDefinition, type TeamDelegation, type TeamHandoff, type TeamLimits, type TeamMember, type TeamStep, type TeamTaskResult, defineTeam };
@@ -0,0 +1,2 @@
1
+ import { t as defineTeam } from "../teams-Ctz676G4.mjs";
2
+ export { defineTeam };
@@ -0,0 +1,82 @@
1
+ //#region src/teams/team.ts
2
+ function defineTeam(team) {
3
+ return team;
4
+ }
5
+ /** @internal Compiles teams onto the existing durable workflow engine. */
6
+ function teamAsWorkflow(team) {
7
+ const allowed = /* @__PURE__ */ new Set([team.supervisor, ...team.members.map(({ agent }) => agent)]);
8
+ const limits = team.limits && {
9
+ ...team.limits.maxSteps === void 0 ? {} : { maxSteps: team.limits.maxSteps },
10
+ ...team.limits.maxToolCalls === void 0 ? {} : { maxToolCalls: team.limits.maxToolCalls },
11
+ ...team.limits.maxInputTokens === void 0 ? {} : { maxInputTokens: team.limits.maxInputTokens },
12
+ ...team.limits.maxOutputTokens === void 0 ? {} : { maxOutputTokens: team.limits.maxOutputTokens }
13
+ };
14
+ return {
15
+ name: team.name,
16
+ version: team.version ?? "1",
17
+ inputSchema: team.inputSchema,
18
+ outputSchema: team.outputSchema,
19
+ limits,
20
+ async run(step, input) {
21
+ let delegations = 0;
22
+ const countDelegation = () => {
23
+ delegations += 1;
24
+ if (team.limits?.maxDelegations !== void 0 && delegations > team.limits.maxDelegations) throw new Error(`Team "${team.name}" exceeded maxDelegations limit of ${team.limits.maxDelegations}`);
25
+ };
26
+ const runAgent = async (delegationId, delegation, metadata) => {
27
+ if (!delegationId.trim()) throw new Error("Team delegation id cannot be empty");
28
+ if (!allowed.has(delegation.agent)) throw new Error(`Agent "${delegation.agent}" is not a member of team "${team.name}"`);
29
+ if (delegation.expectedOutput !== void 0 && !delegation.expectedOutput.trim()) throw new Error("Team delegation expectedOutput cannot be empty");
30
+ if (delegation.constraints !== void 0 && (!Array.isArray(delegation.constraints) || delegation.constraints.some((constraint) => typeof constraint !== "string" || !constraint.trim()))) throw new Error("Team delegation constraints must be non-empty strings");
31
+ countDelegation();
32
+ const request = {
33
+ input: delegation.task,
34
+ ...delegation.context === void 0 ? {} : { context: delegation.context },
35
+ ...delegation.limits === void 0 ? {} : { limits: delegation.limits }
36
+ };
37
+ return {
38
+ ...await step.agent(delegationId, delegation.agent, request, { metadata }),
39
+ delegationId,
40
+ agentName: delegation.agent
41
+ };
42
+ };
43
+ return team.run({
44
+ delegate(delegationId, delegation) {
45
+ return runAgent(delegationId, delegation, {
46
+ teamAction: "delegate",
47
+ ...delegation.expectedOutput === void 0 ? {} : { expectedOutput: delegation.expectedOutput },
48
+ ...delegation.constraints === void 0 ? {} : { constraints: delegation.constraints }
49
+ });
50
+ },
51
+ handoff(delegationId, handoff) {
52
+ if (!allowed.has(handoff.from)) throw new Error(`Agent "${handoff.from}" is not a member of team "${team.name}"`);
53
+ if (!handoff.reason.trim()) throw new Error("Team handoff reason cannot be empty");
54
+ return runAgent(delegationId, {
55
+ agent: handoff.to,
56
+ task: handoff.task,
57
+ context: handoff.context,
58
+ limits: handoff.limits,
59
+ expectedOutput: handoff.expectedOutput,
60
+ constraints: handoff.constraints
61
+ }, {
62
+ teamAction: "handoff",
63
+ from: handoff.from,
64
+ reason: handoff.reason,
65
+ ...handoff.expectedOutput === void 0 ? {} : { expectedOutput: handoff.expectedOutput },
66
+ ...handoff.constraints === void 0 ? {} : { constraints: handoff.constraints }
67
+ });
68
+ },
69
+ parallel(stepId, tasks) {
70
+ const width = Object.keys(tasks).length;
71
+ if (team.limits?.maxParallel !== void 0 && width > team.limits.maxParallel) throw new Error(`Team "${team.name}" exceeded maxParallel limit of ${team.limits.maxParallel}`);
72
+ return step.parallel(stepId, tasks, { metadata: {
73
+ teamAction: "merge",
74
+ width
75
+ } });
76
+ }
77
+ }, input);
78
+ }
79
+ };
80
+ }
81
+ //#endregion
82
+ export { teamAsWorkflow as n, defineTeam as t };