stitchkit 0.78.0 → 0.80.0
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/dist/agent-runtime-browser.js +53 -581
- package/dist/agent-runtime-coding-tools.js +6 -5
- package/dist/agent-runtime-harness.js +21 -94
- package/dist/agent-runtime-openrouter.js +1 -1
- package/dist/agent-runtime.js +68 -64
- package/dist/application/kernel.d.ts.map +1 -1
- package/dist/application/schemas.d.ts +2 -0
- package/dist/application/schemas.d.ts.map +1 -1
- package/dist/application/watch-hub.d.ts.map +1 -1
- package/dist/application-diagnostic-journal.js +14 -96
- package/dist/application-opentelemetry.js +6 -92
- package/dist/application-schemas.js +2 -1
- package/dist/application.js +158 -1802
- package/dist/cli.js +13 -11
- package/dist/contract/index.js +7 -4
- package/dist/index-2qzskm8h.js +63 -0
- package/dist/{index-93xp5tgg.js → index-2rwwmr7v.js} +3 -3
- package/dist/{index-kw12fsbc.js → index-3gye9wzb.js} +7 -3
- package/dist/{index-1ckavx4h.js → index-3z73fh2c.js} +1 -49
- package/dist/index-4fpa9dy2.js +51 -0
- package/dist/{index-cwp38wxn.js → index-5mtc969c.js} +2 -2
- package/dist/index-5s3zajp8.js +192 -0
- package/dist/index-6s7n2v50.js +583 -0
- package/dist/{index-qaajjfp6.js → index-758zx2ha.js} +15 -94
- package/dist/{index-qyrqwr4c.js → index-77fekveh.js} +4 -1
- package/dist/{index-k45qqrdh.js → index-7ag81v2f.js} +13 -166
- package/dist/{index-n1g2xm6a.js → index-7gnkny4z.js} +124 -1
- package/dist/index-7zbps32p.js +89 -0
- package/dist/index-85vfqd7m.js +135 -0
- package/dist/{index-4ntp63ps.js → index-9s6z8vgf.js} +18 -142
- package/dist/index-a916km3r.js +45 -0
- package/dist/index-b9aefrqd.js +20 -0
- package/dist/index-dre2ywck.js +48 -0
- package/dist/{index-s5tn4kdv.js → index-dwf1f2ap.js} +3 -3
- package/dist/{index-wwst0td5.js → index-dx9xehwt.js} +1 -1
- package/dist/{index-5r0ak8fr.js → index-dxesg10d.js} +4 -4
- package/dist/{index-aczggrty.js → index-dxjjv399.js} +2 -2
- package/dist/{index-j6mfaw26.js → index-egaabxkz.js} +3 -3
- package/dist/index-evcnmsc3.js +866 -0
- package/dist/{index-efm026pw.js → index-fxz0v7vg.js} +86 -86
- package/dist/{index-56fm73re.js → index-hb5pf3s4.js} +1 -1
- package/dist/{index-n7apa6sy.js → index-k9ay6v6d.js} +24 -275
- package/dist/index-kzfs85xp.js +9 -0
- package/dist/{index-vbf2p6me.js → index-m9kzax52.js} +91 -89
- package/dist/{index-22by16v6.js → index-mgtxfe6b.js} +1 -1
- package/dist/index-p7hgdyhb.js +22 -0
- package/dist/index-pq95qkbf.js +0 -0
- package/dist/index-t0z5p5w6.js +318 -0
- package/dist/{index-31k1ns1s.js → index-vwp69871.js} +13 -11
- package/dist/index-wc4x00bn.js +103 -0
- package/dist/{index-aewy3x5j.js → index-xcetq6j3.js} +10 -8
- package/dist/{index-7z69kyrh.js → index-y01f4223.js} +24 -40
- package/dist/{index-dmfn9m4x.js → index-ywd0y6m1.js} +20 -341
- package/dist/index.js +46 -407
- package/dist/live.js +6 -3
- package/dist/node.js +17 -14
- package/dist/observability/index.js +8 -7
- package/dist/primitives.js +4 -2
- package/dist/react.js +1 -1
- package/dist/remote.js +7 -3
- package/dist/server/index.js +32 -45
- package/dist/telegram.js +1 -1
- package/dist/testing.js +90 -1576
- package/dist/tool-invoker.js +11 -9
- package/dist/tools/async-operation-contract.d.ts +93 -0
- package/dist/tools/async-operation-contract.d.ts.map +1 -0
- package/dist/tools/async-operation.d.ts +2 -47
- package/dist/tools/async-operation.d.ts.map +1 -1
- package/dist/tools/view-file-contract.d.ts +98 -0
- package/dist/tools/view-file-contract.d.ts.map +1 -0
- package/dist/tools/view-file.d.ts +4 -83
- package/dist/tools/view-file.d.ts.map +1 -1
- package/dist/tools-contract.d.ts +29 -0
- package/dist/tools-contract.d.ts.map +1 -0
- package/dist/tools-contract.js +24 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +61 -140
- package/llms-full.txt +86 -3
- package/package.json +9 -6
- package/dist/index-anyqnqcv.js +0 -79
- package/dist/index-ksp6e2ye.js +0 -24
- package/dist/index-vj3vvpaa.js +0 -307
- package/dist/index-wfq8zerm.js +0 -92
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApplicationIdSchema
|
|
3
|
+
} from "./index-3gye9wzb.js";
|
|
4
|
+
import {
|
|
5
|
+
createBoundedChannel
|
|
6
|
+
} from "./index-7gnkny4z.js";
|
|
7
|
+
|
|
8
|
+
// src/application/latest-sink.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var SnapshotRevisionSchema = z.number().int().nonnegative();
|
|
11
|
+
var ApplicationSnapshotSinkStatusSchema = z.object({
|
|
12
|
+
accepting: z.boolean(),
|
|
13
|
+
received: z.number().int().nonnegative(),
|
|
14
|
+
accepted: z.number().int().nonnegative(),
|
|
15
|
+
rejected: z.number().int().nonnegative(),
|
|
16
|
+
delivered: z.number().int().nonnegative(),
|
|
17
|
+
coalesced: z.number().int().nonnegative(),
|
|
18
|
+
failed: z.number().int().nonnegative(),
|
|
19
|
+
inFlight: z.boolean(),
|
|
20
|
+
pending: z.boolean(),
|
|
21
|
+
lastAcceptedRevision: SnapshotRevisionSchema.optional(),
|
|
22
|
+
lastDeliveredRevision: SnapshotRevisionSchema.optional()
|
|
23
|
+
}).strict().readonly();
|
|
24
|
+
function createApplicationSnapshotSink(config) {
|
|
25
|
+
let accepting = true;
|
|
26
|
+
let received = 0;
|
|
27
|
+
let accepted = 0;
|
|
28
|
+
let rejected = 0;
|
|
29
|
+
let delivered = 0;
|
|
30
|
+
let coalesced = 0;
|
|
31
|
+
let failed = 0;
|
|
32
|
+
let lastAcceptedRevision;
|
|
33
|
+
let lastDeliveredRevision;
|
|
34
|
+
let inFlight;
|
|
35
|
+
let closePromise;
|
|
36
|
+
let resolveClose;
|
|
37
|
+
const pending = createBoundedChannel({
|
|
38
|
+
policy: "latest",
|
|
39
|
+
maxItems: 1,
|
|
40
|
+
maxBytes: 1,
|
|
41
|
+
sizeOf: () => 1
|
|
42
|
+
});
|
|
43
|
+
const getStatus = () => ApplicationSnapshotSinkStatusSchema.parse({
|
|
44
|
+
accepting,
|
|
45
|
+
received,
|
|
46
|
+
accepted,
|
|
47
|
+
rejected,
|
|
48
|
+
delivered,
|
|
49
|
+
coalesced,
|
|
50
|
+
failed,
|
|
51
|
+
inFlight: inFlight !== undefined,
|
|
52
|
+
pending: pending.getSnapshot().queuedItems > 0,
|
|
53
|
+
...lastAcceptedRevision !== undefined && { lastAcceptedRevision },
|
|
54
|
+
...lastDeliveredRevision !== undefined && { lastDeliveredRevision }
|
|
55
|
+
});
|
|
56
|
+
const reportFailure = (error, snapshot) => {
|
|
57
|
+
if (!config.onSinkError)
|
|
58
|
+
return;
|
|
59
|
+
Promise.resolve().then(() => config.onSinkError?.({ error, snapshot })).catch(() => {
|
|
60
|
+
return;
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const settleCloseIfIdle = () => {
|
|
64
|
+
if (accepting || inFlight || pending.getSnapshot().queuedItems > 0 || !resolveClose)
|
|
65
|
+
return;
|
|
66
|
+
const resolve = resolveClose;
|
|
67
|
+
resolveClose = undefined;
|
|
68
|
+
resolve(getStatus());
|
|
69
|
+
};
|
|
70
|
+
const startWrite = (snapshot) => {
|
|
71
|
+
const write = Promise.resolve().then(() => config.write(snapshot)).then(() => {
|
|
72
|
+
delivered += 1;
|
|
73
|
+
lastDeliveredRevision = snapshot.revision;
|
|
74
|
+
}).catch((error) => {
|
|
75
|
+
failed += 1;
|
|
76
|
+
reportFailure(error, snapshot);
|
|
77
|
+
}).finally(() => {
|
|
78
|
+
if (pending.getSnapshot().queuedItems > 0) {
|
|
79
|
+
pending.next().then((next) => {
|
|
80
|
+
if (next.done) {
|
|
81
|
+
inFlight = undefined;
|
|
82
|
+
settleCloseIfIdle();
|
|
83
|
+
} else {
|
|
84
|
+
startWrite(next.value);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
inFlight = undefined;
|
|
89
|
+
settleCloseIfIdle();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
inFlight = write;
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
publish(snapshot) {
|
|
96
|
+
received += 1;
|
|
97
|
+
const revision = SnapshotRevisionSchema.parse(snapshot.revision);
|
|
98
|
+
if (!accepting || lastAcceptedRevision !== undefined && revision <= lastAcceptedRevision) {
|
|
99
|
+
rejected += 1;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
accepted += 1;
|
|
103
|
+
lastAcceptedRevision = revision;
|
|
104
|
+
if (!inFlight) {
|
|
105
|
+
startWrite(snapshot);
|
|
106
|
+
} else {
|
|
107
|
+
const offered = pending.offer(snapshot);
|
|
108
|
+
if (offered.outcome === "coalesced")
|
|
109
|
+
coalesced += offered.replaced;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
},
|
|
113
|
+
getStatus,
|
|
114
|
+
close() {
|
|
115
|
+
if (closePromise)
|
|
116
|
+
return closePromise;
|
|
117
|
+
accepting = false;
|
|
118
|
+
pending.close({ mode: "drain" });
|
|
119
|
+
closePromise = new Promise((resolve) => {
|
|
120
|
+
resolveClose = resolve;
|
|
121
|
+
settleCloseIfIdle();
|
|
122
|
+
});
|
|
123
|
+
return closePromise;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/application/activity.ts
|
|
129
|
+
import { z as z2 } from "zod";
|
|
130
|
+
var BoundedOperationalIdSchema = z2.string().min(1).max(64).regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]*$/);
|
|
131
|
+
var NonNegativeIntegerSchema = z2.number().int().nonnegative();
|
|
132
|
+
var ActivityIdSchema = BoundedOperationalIdSchema;
|
|
133
|
+
var ActivityStageIdSchema = BoundedOperationalIdSchema;
|
|
134
|
+
var ActivityStageSnapshotSchema = z2.object({
|
|
135
|
+
id: ActivityStageIdSchema,
|
|
136
|
+
active: NonNegativeIntegerSchema,
|
|
137
|
+
queued: NonNegativeIntegerSchema,
|
|
138
|
+
completed: NonNegativeIntegerSchema,
|
|
139
|
+
failed: NonNegativeIntegerSchema
|
|
140
|
+
}).strict().readonly();
|
|
141
|
+
var ActivityTotalsSchema = z2.object({
|
|
142
|
+
active: NonNegativeIntegerSchema,
|
|
143
|
+
queued: NonNegativeIntegerSchema,
|
|
144
|
+
completed: NonNegativeIntegerSchema,
|
|
145
|
+
failed: NonNegativeIntegerSchema
|
|
146
|
+
}).strict().readonly();
|
|
147
|
+
var ActivitySnapshotSchema = z2.object({
|
|
148
|
+
id: ActivityIdSchema,
|
|
149
|
+
epoch: z2.string().uuid(),
|
|
150
|
+
revision: NonNegativeIntegerSchema,
|
|
151
|
+
capturedAt: z2.string().datetime({ offset: true }),
|
|
152
|
+
changedAt: z2.string().datetime({ offset: true }),
|
|
153
|
+
stages: z2.array(ActivityStageSnapshotSchema).min(1).max(64).readonly(),
|
|
154
|
+
totals: ActivityTotalsSchema
|
|
155
|
+
}).strict().readonly();
|
|
156
|
+
var ActivityLiveStateSchema = z2.enum(["active", "queued"]);
|
|
157
|
+
var ActivityTokenBrand = Symbol("stitchkit.application.activity");
|
|
158
|
+
function emptyCounters() {
|
|
159
|
+
return { active: 0, queued: 0, completed: 0, failed: 0 };
|
|
160
|
+
}
|
|
161
|
+
function totalsOf(stages) {
|
|
162
|
+
return stages.reduce((totals, stage) => ({
|
|
163
|
+
active: totals.active + stage.active,
|
|
164
|
+
queued: totals.queued + stage.queued,
|
|
165
|
+
completed: totals.completed + stage.completed,
|
|
166
|
+
failed: totals.failed + stage.failed
|
|
167
|
+
}), emptyCounters());
|
|
168
|
+
}
|
|
169
|
+
function createActivityProjection(config) {
|
|
170
|
+
const id = ActivityIdSchema.parse(config.id);
|
|
171
|
+
const declaredStages = z2.array(ActivityStageIdSchema).min(1).max(64).parse(config.stages);
|
|
172
|
+
const uniqueStages = new Set(declaredStages);
|
|
173
|
+
if (uniqueStages.size !== declaredStages.length) {
|
|
174
|
+
throw new Error("[stitchkit] createActivityProjection: stage ids must be unique");
|
|
175
|
+
}
|
|
176
|
+
const epoch = z2.string().uuid().parse(config.epoch ?? crypto.randomUUID());
|
|
177
|
+
const now = config.now ?? (() => new Date);
|
|
178
|
+
const counters = new Map(declaredStages.map((stage) => [stage, emptyCounters()]));
|
|
179
|
+
const activities = new WeakMap;
|
|
180
|
+
const subscribers = new Set;
|
|
181
|
+
let revision = 0;
|
|
182
|
+
let changedAt = now().toISOString();
|
|
183
|
+
const countersFor = (stage) => {
|
|
184
|
+
const value = counters.get(stage);
|
|
185
|
+
if (!value) {
|
|
186
|
+
throw new Error(`[stitchkit] createActivityProjection: undeclared stage "${stage}"`);
|
|
187
|
+
}
|
|
188
|
+
return value;
|
|
189
|
+
};
|
|
190
|
+
const getSnapshot = () => {
|
|
191
|
+
const stages = declaredStages.map((stage) => ({ id: stage, ...countersFor(stage) }));
|
|
192
|
+
return ActivitySnapshotSchema.parse({
|
|
193
|
+
id,
|
|
194
|
+
epoch,
|
|
195
|
+
revision,
|
|
196
|
+
capturedAt: now().toISOString(),
|
|
197
|
+
changedAt,
|
|
198
|
+
stages,
|
|
199
|
+
totals: totalsOf(stages)
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
const publishChange = () => {
|
|
203
|
+
revision += 1;
|
|
204
|
+
changedAt = now().toISOString();
|
|
205
|
+
const snapshot = getSnapshot();
|
|
206
|
+
for (const subscriber of subscribers)
|
|
207
|
+
subscriber.publish(snapshot);
|
|
208
|
+
};
|
|
209
|
+
const requireActivity = (token) => {
|
|
210
|
+
const activity = activities.get(token);
|
|
211
|
+
if (!activity) {
|
|
212
|
+
throw new Error("[stitchkit] activity token belongs to another projection");
|
|
213
|
+
}
|
|
214
|
+
return activity;
|
|
215
|
+
};
|
|
216
|
+
const leaveLiveState = (activity) => {
|
|
217
|
+
if (activity.state === "active" || activity.state === "queued") {
|
|
218
|
+
countersFor(activity.stage)[activity.state] -= 1;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const settle = (token, terminal) => {
|
|
222
|
+
const activity = requireActivity(token);
|
|
223
|
+
if (activity.state === "completed" || activity.state === "failed")
|
|
224
|
+
return false;
|
|
225
|
+
leaveLiveState(activity);
|
|
226
|
+
countersFor(activity.stage)[terminal] += 1;
|
|
227
|
+
activity.state = terminal;
|
|
228
|
+
publishChange();
|
|
229
|
+
return true;
|
|
230
|
+
};
|
|
231
|
+
return {
|
|
232
|
+
open(stage, rawState = "active") {
|
|
233
|
+
const parsedStage = ActivityStageIdSchema.parse(stage);
|
|
234
|
+
const state = ActivityLiveStateSchema.parse(rawState);
|
|
235
|
+
countersFor(parsedStage)[state] += 1;
|
|
236
|
+
const token = Object.freeze({
|
|
237
|
+
get [ActivityTokenBrand]() {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
activities.set(token, { stage: parsedStage, state });
|
|
242
|
+
publishChange();
|
|
243
|
+
return token;
|
|
244
|
+
},
|
|
245
|
+
transition(token, input) {
|
|
246
|
+
const activity = requireActivity(token);
|
|
247
|
+
if (activity.state === "completed" || activity.state === "failed") {
|
|
248
|
+
throw new Error("[stitchkit] cannot transition a terminal activity");
|
|
249
|
+
}
|
|
250
|
+
const stage = ActivityStageIdSchema.parse(input.stage);
|
|
251
|
+
const state = ActivityLiveStateSchema.parse(input.state);
|
|
252
|
+
countersFor(stage);
|
|
253
|
+
if (activity.stage === stage && activity.state === state)
|
|
254
|
+
return false;
|
|
255
|
+
leaveLiveState(activity);
|
|
256
|
+
countersFor(stage)[state] += 1;
|
|
257
|
+
activity.stage = stage;
|
|
258
|
+
activity.state = state;
|
|
259
|
+
publishChange();
|
|
260
|
+
return true;
|
|
261
|
+
},
|
|
262
|
+
complete: (token) => settle(token, "completed"),
|
|
263
|
+
fail: (token) => settle(token, "failed"),
|
|
264
|
+
getSnapshot,
|
|
265
|
+
subscribe(listener) {
|
|
266
|
+
const sink = createApplicationSnapshotSink({
|
|
267
|
+
write: listener,
|
|
268
|
+
...config.onSubscriberError && { onSinkError: config.onSubscriberError }
|
|
269
|
+
});
|
|
270
|
+
subscribers.add(sink);
|
|
271
|
+
sink.publish(getSnapshot());
|
|
272
|
+
return () => {
|
|
273
|
+
subscribers.delete(sink);
|
|
274
|
+
sink.close();
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/application/schedule.ts
|
|
281
|
+
import { z as z3 } from "zod";
|
|
282
|
+
var NonNegativeSafeIntegerSchema = z3.number().int().nonnegative().refine(Number.isSafeInteger, "Expected a safe integer");
|
|
283
|
+
var PositiveSafeIntegerSchema = NonNegativeSafeIntegerSchema.refine((value) => value > 0, "Expected a positive integer");
|
|
284
|
+
var ManagedScheduleOverlapSchema = z3.discriminatedUnion("mode", [
|
|
285
|
+
z3.object({ mode: z3.literal("skip") }).readonly(),
|
|
286
|
+
z3.object({ mode: z3.literal("queue-one") }).readonly(),
|
|
287
|
+
z3.object({
|
|
288
|
+
mode: z3.literal("parallel"),
|
|
289
|
+
maxConcurrent: PositiveSafeIntegerSchema
|
|
290
|
+
}).readonly()
|
|
291
|
+
]);
|
|
292
|
+
var ManagedScheduleErrorPolicySchema = z3.enum(["continue", "stop-schedule"]);
|
|
293
|
+
var ManagedScheduleDescriptorSchema = z3.object({
|
|
294
|
+
id: ApplicationIdSchema,
|
|
295
|
+
everyMs: PositiveSafeIntegerSchema,
|
|
296
|
+
startAfterMs: NonNegativeSafeIntegerSchema,
|
|
297
|
+
overlap: ManagedScheduleOverlapSchema,
|
|
298
|
+
errorPolicy: ManagedScheduleErrorPolicySchema
|
|
299
|
+
}).readonly();
|
|
300
|
+
var ManagedScheduleStatusSchema = z3.object({
|
|
301
|
+
descriptor: ManagedScheduleDescriptorSchema,
|
|
302
|
+
state: z3.enum(["inactive", "scheduled", "running", "draining", "stopped"]),
|
|
303
|
+
revision: NonNegativeSafeIntegerSchema,
|
|
304
|
+
capturedAt: z3.string().datetime({ offset: true }),
|
|
305
|
+
changedAt: z3.string().datetime({ offset: true }),
|
|
306
|
+
accepting: z3.boolean(),
|
|
307
|
+
active: NonNegativeSafeIntegerSchema,
|
|
308
|
+
queued: z3.boolean(),
|
|
309
|
+
runsStarted: NonNegativeSafeIntegerSchema,
|
|
310
|
+
runsCompleted: NonNegativeSafeIntegerSchema,
|
|
311
|
+
runsFailed: NonNegativeSafeIntegerSchema,
|
|
312
|
+
ticksSkipped: NonNegativeSafeIntegerSchema,
|
|
313
|
+
nextRunAt: z3.string().datetime({ offset: true }).nullable(),
|
|
314
|
+
lastScheduledAt: z3.string().datetime({ offset: true }).nullable(),
|
|
315
|
+
lastStartedAt: z3.string().datetime({ offset: true }).nullable(),
|
|
316
|
+
lastFinishedAt: z3.string().datetime({ offset: true }).nullable()
|
|
317
|
+
}).readonly();
|
|
318
|
+
var systemClock = {
|
|
319
|
+
now: () => performance.now(),
|
|
320
|
+
wallNow: () => new Date,
|
|
321
|
+
schedule(callback, delayMs) {
|
|
322
|
+
const timer = setTimeout(callback, delayMs);
|
|
323
|
+
return { cancel: () => clearTimeout(timer) };
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
var DEFAULT_OVERLAP = { mode: "skip" };
|
|
327
|
+
function createManagedSchedule(config) {
|
|
328
|
+
const descriptor = ManagedScheduleDescriptorSchema.parse({
|
|
329
|
+
id: config.id,
|
|
330
|
+
everyMs: config.everyMs,
|
|
331
|
+
startAfterMs: config.startAfterMs ?? config.everyMs,
|
|
332
|
+
overlap: config.overlap ?? DEFAULT_OVERLAP,
|
|
333
|
+
errorPolicy: config.errorPolicy ?? "continue"
|
|
334
|
+
});
|
|
335
|
+
const dependsOn = config.dependsOn?.map((id) => ApplicationIdSchema.parse(id));
|
|
336
|
+
const clock = config.clock ?? systemClock;
|
|
337
|
+
let revision = 0;
|
|
338
|
+
let accepting = false;
|
|
339
|
+
let activated = false;
|
|
340
|
+
let stopped = false;
|
|
341
|
+
let timer = null;
|
|
342
|
+
let activationContext = null;
|
|
343
|
+
let nextRunAt = null;
|
|
344
|
+
let queuedAt = null;
|
|
345
|
+
let runsStarted = 0;
|
|
346
|
+
let runsCompleted = 0;
|
|
347
|
+
let runsFailed = 0;
|
|
348
|
+
let ticksSkipped = 0;
|
|
349
|
+
let lastScheduledAt = null;
|
|
350
|
+
let lastStartedAt = null;
|
|
351
|
+
let lastFinishedAt = null;
|
|
352
|
+
let changedAt = clock.wallNow().toISOString();
|
|
353
|
+
const active = new Set;
|
|
354
|
+
const changed = () => {
|
|
355
|
+
revision += 1;
|
|
356
|
+
changedAt = clock.wallNow().toISOString();
|
|
357
|
+
};
|
|
358
|
+
const cancelFuture = () => {
|
|
359
|
+
timer?.cancel();
|
|
360
|
+
timer = null;
|
|
361
|
+
nextRunAt = null;
|
|
362
|
+
queuedAt = null;
|
|
363
|
+
};
|
|
364
|
+
const stopAdmission = () => {
|
|
365
|
+
if (!accepting && stopped)
|
|
366
|
+
return;
|
|
367
|
+
accepting = false;
|
|
368
|
+
stopped = true;
|
|
369
|
+
cancelFuture();
|
|
370
|
+
changed();
|
|
371
|
+
};
|
|
372
|
+
const reportError = (error, context) => {
|
|
373
|
+
if (!config.onError)
|
|
374
|
+
return;
|
|
375
|
+
Promise.resolve().then(() => config.onError?.(error, context)).catch(() => {});
|
|
376
|
+
};
|
|
377
|
+
const state = () => {
|
|
378
|
+
if (!activated)
|
|
379
|
+
return stopped ? "stopped" : "inactive";
|
|
380
|
+
if (!accepting)
|
|
381
|
+
return active.size > 0 ? "draining" : "stopped";
|
|
382
|
+
return active.size > 0 ? "running" : "scheduled";
|
|
383
|
+
};
|
|
384
|
+
const wallAt = (monotonicAt, anchor) => {
|
|
385
|
+
if (monotonicAt === null)
|
|
386
|
+
return null;
|
|
387
|
+
return new Date(anchor.wallNow + monotonicAt - anchor.monotonicNow).toISOString();
|
|
388
|
+
};
|
|
389
|
+
const status = () => {
|
|
390
|
+
const captured = clock.wallNow();
|
|
391
|
+
const anchor = { monotonicNow: clock.now(), wallNow: captured.getTime() };
|
|
392
|
+
return ManagedScheduleStatusSchema.parse({
|
|
393
|
+
descriptor,
|
|
394
|
+
state: state(),
|
|
395
|
+
revision,
|
|
396
|
+
capturedAt: captured.toISOString(),
|
|
397
|
+
changedAt,
|
|
398
|
+
accepting,
|
|
399
|
+
active: active.size,
|
|
400
|
+
queued: queuedAt !== null,
|
|
401
|
+
runsStarted,
|
|
402
|
+
runsCompleted,
|
|
403
|
+
runsFailed,
|
|
404
|
+
ticksSkipped,
|
|
405
|
+
nextRunAt: wallAt(nextRunAt, anchor),
|
|
406
|
+
lastScheduledAt,
|
|
407
|
+
lastStartedAt,
|
|
408
|
+
lastFinishedAt
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
let startExecution = () => {
|
|
412
|
+
return;
|
|
413
|
+
};
|
|
414
|
+
const settleExecution = () => {
|
|
415
|
+
if (!accepting || queuedAt === null || active.size !== 0)
|
|
416
|
+
return;
|
|
417
|
+
const successorAt = queuedAt;
|
|
418
|
+
queuedAt = null;
|
|
419
|
+
changed();
|
|
420
|
+
startExecution(successorAt);
|
|
421
|
+
};
|
|
422
|
+
startExecution = (scheduledAt) => {
|
|
423
|
+
const resourceContext = activationContext;
|
|
424
|
+
if (!accepting || !resourceContext)
|
|
425
|
+
return;
|
|
426
|
+
const startedAt = clock.now();
|
|
427
|
+
const wallStartedAt = clock.wallNow().getTime();
|
|
428
|
+
const runContext = {
|
|
429
|
+
applicationId: resourceContext.applicationId,
|
|
430
|
+
signal: resourceContext.signal,
|
|
431
|
+
scheduledAt,
|
|
432
|
+
startedAt,
|
|
433
|
+
now: () => clock.now()
|
|
434
|
+
};
|
|
435
|
+
runsStarted += 1;
|
|
436
|
+
lastScheduledAt = new Date(wallStartedAt + scheduledAt - startedAt).toISOString();
|
|
437
|
+
lastStartedAt = new Date(wallStartedAt).toISOString();
|
|
438
|
+
changed();
|
|
439
|
+
let tracked;
|
|
440
|
+
tracked = Promise.resolve().then(() => config.run(runContext)).then(() => {
|
|
441
|
+
runsCompleted += 1;
|
|
442
|
+
lastFinishedAt = clock.wallNow().toISOString();
|
|
443
|
+
if (descriptor.errorPolicy === "continue" && accepting) {
|
|
444
|
+
resourceContext.reportHealth("healthy");
|
|
445
|
+
}
|
|
446
|
+
}, (error) => {
|
|
447
|
+
runsFailed += 1;
|
|
448
|
+
lastFinishedAt = clock.wallNow().toISOString();
|
|
449
|
+
reportError(error, runContext);
|
|
450
|
+
if (descriptor.errorPolicy === "stop-schedule") {
|
|
451
|
+
resourceContext.reportHealth("unhealthy");
|
|
452
|
+
stopAdmission();
|
|
453
|
+
} else {
|
|
454
|
+
resourceContext.reportHealth("degraded");
|
|
455
|
+
}
|
|
456
|
+
}).finally(() => {
|
|
457
|
+
active.delete(tracked);
|
|
458
|
+
changed();
|
|
459
|
+
settleExecution();
|
|
460
|
+
});
|
|
461
|
+
active.add(tracked);
|
|
462
|
+
};
|
|
463
|
+
const dispatchTick = (scheduledAt) => {
|
|
464
|
+
if (!accepting)
|
|
465
|
+
return;
|
|
466
|
+
if (descriptor.overlap.mode === "skip") {
|
|
467
|
+
if (active.size > 0) {
|
|
468
|
+
ticksSkipped += 1;
|
|
469
|
+
changed();
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
startExecution(scheduledAt);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (descriptor.overlap.mode === "queue-one") {
|
|
476
|
+
if (active.size > 0) {
|
|
477
|
+
queuedAt = scheduledAt;
|
|
478
|
+
changed();
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
startExecution(scheduledAt);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (active.size >= descriptor.overlap.maxConcurrent) {
|
|
485
|
+
ticksSkipped += 1;
|
|
486
|
+
changed();
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
startExecution(scheduledAt);
|
|
490
|
+
};
|
|
491
|
+
const arm = () => {
|
|
492
|
+
if (!accepting || nextRunAt === null)
|
|
493
|
+
return;
|
|
494
|
+
const delayMs = Math.max(0, nextRunAt - clock.now());
|
|
495
|
+
timer = clock.schedule(() => {
|
|
496
|
+
timer = null;
|
|
497
|
+
if (!accepting || nextRunAt === null)
|
|
498
|
+
return;
|
|
499
|
+
const scheduledAt = nextRunAt;
|
|
500
|
+
const observedAt = clock.now();
|
|
501
|
+
const elapsedIntervals = Math.max(1, Math.floor((observedAt - scheduledAt) / descriptor.everyMs) + 1);
|
|
502
|
+
if (elapsedIntervals > 1) {
|
|
503
|
+
ticksSkipped += elapsedIntervals - 1;
|
|
504
|
+
changed();
|
|
505
|
+
}
|
|
506
|
+
nextRunAt = scheduledAt + elapsedIntervals * descriptor.everyMs;
|
|
507
|
+
arm();
|
|
508
|
+
dispatchTick(scheduledAt);
|
|
509
|
+
}, delayMs);
|
|
510
|
+
};
|
|
511
|
+
const waitForActive = async (context, deadlineAt) => {
|
|
512
|
+
if (active.size === 0 || context.signal.aborted)
|
|
513
|
+
return;
|
|
514
|
+
await new Promise((resolve) => {
|
|
515
|
+
let settled = false;
|
|
516
|
+
let deadlineTimer = null;
|
|
517
|
+
const finish = () => {
|
|
518
|
+
if (settled)
|
|
519
|
+
return;
|
|
520
|
+
settled = true;
|
|
521
|
+
deadlineTimer?.cancel();
|
|
522
|
+
context.signal.removeEventListener("abort", finish);
|
|
523
|
+
resolve();
|
|
524
|
+
};
|
|
525
|
+
context.signal.addEventListener("abort", finish, { once: true });
|
|
526
|
+
if (deadlineAt !== undefined) {
|
|
527
|
+
deadlineTimer = clock.schedule(finish, Math.max(0, deadlineAt - context.now()));
|
|
528
|
+
}
|
|
529
|
+
Promise.allSettled([...active]).then(finish);
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
const drain = async (context) => {
|
|
533
|
+
stopAdmission();
|
|
534
|
+
await waitForActive(context, context.deadlineAt);
|
|
535
|
+
};
|
|
536
|
+
return {
|
|
537
|
+
id: descriptor.id,
|
|
538
|
+
...dependsOn && { dependsOn },
|
|
539
|
+
...config.required !== undefined && { required: config.required },
|
|
540
|
+
get status() {
|
|
541
|
+
return status();
|
|
542
|
+
},
|
|
543
|
+
start() {
|
|
544
|
+
if (active.size > 0) {
|
|
545
|
+
throw new Error(`[stitchkit] schedule "${descriptor.id}" still has executions from its previous generation`);
|
|
546
|
+
}
|
|
547
|
+
cancelFuture();
|
|
548
|
+
stopped = false;
|
|
549
|
+
accepting = false;
|
|
550
|
+
activated = false;
|
|
551
|
+
activationContext = null;
|
|
552
|
+
queuedAt = null;
|
|
553
|
+
changed();
|
|
554
|
+
},
|
|
555
|
+
activate(context) {
|
|
556
|
+
if (activated || stopped)
|
|
557
|
+
return;
|
|
558
|
+
activated = true;
|
|
559
|
+
accepting = true;
|
|
560
|
+
activationContext = context;
|
|
561
|
+
nextRunAt = clock.now() + descriptor.startAfterMs;
|
|
562
|
+
context.reportHealth("healthy");
|
|
563
|
+
changed();
|
|
564
|
+
arm();
|
|
565
|
+
},
|
|
566
|
+
stopAdmission() {
|
|
567
|
+
stopAdmission();
|
|
568
|
+
},
|
|
569
|
+
drain,
|
|
570
|
+
close() {
|
|
571
|
+
stopAdmission();
|
|
572
|
+
},
|
|
573
|
+
async force(context) {
|
|
574
|
+
stopAdmission();
|
|
575
|
+
await waitForActive(context, context.forceDeadlineAt);
|
|
576
|
+
if (active.size > 0) {
|
|
577
|
+
throw new Error(`[stitchkit] schedule "${descriptor.id}" still has active executions`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export { ApplicationSnapshotSinkStatusSchema, createApplicationSnapshotSink, ActivityIdSchema, ActivityStageIdSchema, ActivityStageSnapshotSchema, ActivitySnapshotSchema, ActivityLiveStateSchema, ActivityTokenBrand, createActivityProjection, ManagedScheduleOverlapSchema, ManagedScheduleErrorPolicySchema, ManagedScheduleDescriptorSchema, ManagedScheduleStatusSchema, createManagedSchedule };
|
|
@@ -1,108 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
objectShapeKeys
|
|
3
|
-
} from "./index-22by16v6.js";
|
|
4
1
|
import {
|
|
5
2
|
getRequestContext,
|
|
6
3
|
runWithRequestContext
|
|
7
|
-
} from "./index-
|
|
4
|
+
} from "./index-dwf1f2ap.js";
|
|
5
|
+
import {
|
|
6
|
+
objectShapeKeys
|
|
7
|
+
} from "./index-mgtxfe6b.js";
|
|
8
|
+
import {
|
|
9
|
+
coerceJsonArgs
|
|
10
|
+
} from "./index-7zbps32p.js";
|
|
8
11
|
import {
|
|
9
12
|
formatZodError,
|
|
10
13
|
normalizeError,
|
|
11
14
|
validateDeclaredOutput
|
|
12
|
-
} from "./index-
|
|
13
|
-
import {
|
|
14
|
-
isUnsafeKey,
|
|
15
|
-
safeJsonParse
|
|
16
|
-
} from "./index-vj3vvpaa.js";
|
|
17
|
-
import {
|
|
18
|
-
isRecord
|
|
19
|
-
} from "./index-qyrqwr4c.js";
|
|
15
|
+
} from "./index-fxz0v7vg.js";
|
|
20
16
|
import {
|
|
21
17
|
AppError,
|
|
22
18
|
STITCH_ERROR_STATUS,
|
|
23
19
|
isStitchErrorCode
|
|
24
20
|
} from "./index-0w9abg87.js";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) {
|
|
33
|
-
return needsJsonCoercion(schema.unwrap());
|
|
34
|
-
}
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
function acceptsRawString(schema) {
|
|
38
|
-
const type = schema._zod.def.type;
|
|
39
|
-
if (type === "string" || type === "template_literal")
|
|
40
|
-
return true;
|
|
41
|
-
if (schema instanceof z.ZodLiteral) {
|
|
42
|
-
return schema.def.values.some((value) => typeof value === "string");
|
|
43
|
-
}
|
|
44
|
-
if (schema instanceof z.ZodEnum) {
|
|
45
|
-
return schema.options.some((value) => typeof value === "string");
|
|
46
|
-
}
|
|
47
|
-
if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) {
|
|
48
|
-
return acceptsRawString(schema.unwrap());
|
|
49
|
-
}
|
|
50
|
-
if (schema instanceof z.ZodUnion) {
|
|
51
|
-
return schema.def.options.some((option) => acceptsRawString(option));
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
function matchingVariant(union, value) {
|
|
56
|
-
const disc = union.def.discriminator;
|
|
57
|
-
const tag = value[disc];
|
|
58
|
-
for (const option of union.def.options) {
|
|
59
|
-
if (!(option instanceof z.ZodObject))
|
|
60
|
-
continue;
|
|
61
|
-
const field = option.shape[disc];
|
|
62
|
-
if (field instanceof z.ZodLiteral && field.def.values.some((v) => v === tag))
|
|
63
|
-
return option;
|
|
64
|
-
if (field instanceof z.ZodEnum && field.options.some((v) => v === tag))
|
|
65
|
-
return option;
|
|
66
|
-
}
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
function coerceValue(value, schema) {
|
|
70
|
-
if (!schema)
|
|
71
|
-
return value;
|
|
72
|
-
if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) {
|
|
73
|
-
return coerceValue(value, schema.unwrap());
|
|
74
|
-
}
|
|
75
|
-
let current = value;
|
|
76
|
-
if (typeof current === "string" && needsJsonCoercion(schema)) {
|
|
77
|
-
if (acceptsRawString(schema))
|
|
78
|
-
return current;
|
|
79
|
-
try {
|
|
80
|
-
current = safeJsonParse(current);
|
|
81
|
-
} catch {
|
|
82
|
-
return value;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (schema instanceof z.ZodObject && isRecord(current)) {
|
|
86
|
-
const shape = schema.shape;
|
|
87
|
-
const out = {};
|
|
88
|
-
for (const [key, item] of Object.entries(current)) {
|
|
89
|
-
out[key] = coerceValue(item, shape[key]);
|
|
90
|
-
}
|
|
91
|
-
return out;
|
|
92
|
-
}
|
|
93
|
-
if (schema instanceof z.ZodArray && Array.isArray(current)) {
|
|
94
|
-
return current.map((item) => coerceValue(item, schema.element));
|
|
95
|
-
}
|
|
96
|
-
if (schema instanceof z.ZodDiscriminatedUnion && isRecord(current)) {
|
|
97
|
-
const variant = matchingVariant(schema, current);
|
|
98
|
-
return variant ? coerceValue(current, variant) : current;
|
|
99
|
-
}
|
|
100
|
-
return current;
|
|
101
|
-
}
|
|
102
|
-
function coerceJsonArgs(args, schema) {
|
|
103
|
-
const coerced = coerceValue(args, schema);
|
|
104
|
-
return isRecord(coerced) ? coerced : args;
|
|
105
|
-
}
|
|
21
|
+
import {
|
|
22
|
+
isUnsafeKey
|
|
23
|
+
} from "./index-kzfs85xp.js";
|
|
24
|
+
import {
|
|
25
|
+
isRecord
|
|
26
|
+
} from "./index-77fekveh.js";
|
|
106
27
|
|
|
107
28
|
// src/tools/execute.ts
|
|
108
29
|
class ToolExecutionControlError extends Error {
|
|
@@ -337,4 +258,4 @@ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycl
|
|
|
337
258
|
}
|
|
338
259
|
}
|
|
339
260
|
|
|
340
|
-
export {
|
|
261
|
+
export { ToolExecutionControlError, isToolExecutionControlError, toolResultFromError, toolErrorFromResult, executeToolMethod };
|