@assemblyline-agents/runtime 0.1.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.
Files changed (331) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/agent-harness.d.ts +108 -0
  4. package/dist/agent-harness.d.ts.map +1 -0
  5. package/dist/agent-harness.js +2 -0
  6. package/dist/agent-harness.js.map +1 -0
  7. package/dist/attachments-legacy.d.ts +17 -0
  8. package/dist/attachments-legacy.d.ts.map +1 -0
  9. package/dist/attachments-legacy.js +273 -0
  10. package/dist/attachments-legacy.js.map +1 -0
  11. package/dist/attachments.d.ts +49 -0
  12. package/dist/attachments.d.ts.map +1 -0
  13. package/dist/attachments.js +832 -0
  14. package/dist/attachments.js.map +1 -0
  15. package/dist/builtin-tool-executors.d.ts +96 -0
  16. package/dist/builtin-tool-executors.d.ts.map +1 -0
  17. package/dist/builtin-tool-executors.js +501 -0
  18. package/dist/builtin-tool-executors.js.map +1 -0
  19. package/dist/builtin-tools.d.ts +30 -0
  20. package/dist/builtin-tools.d.ts.map +1 -0
  21. package/dist/builtin-tools.js +690 -0
  22. package/dist/builtin-tools.js.map +1 -0
  23. package/dist/capability-catalog.d.ts +27 -0
  24. package/dist/capability-catalog.d.ts.map +1 -0
  25. package/dist/capability-catalog.js +193 -0
  26. package/dist/capability-catalog.js.map +1 -0
  27. package/dist/channel-http-util.d.ts +34 -0
  28. package/dist/channel-http-util.d.ts.map +1 -0
  29. package/dist/channel-http-util.js +93 -0
  30. package/dist/channel-http-util.js.map +1 -0
  31. package/dist/channel-ingress.d.ts +56 -0
  32. package/dist/channel-ingress.d.ts.map +1 -0
  33. package/dist/channel-ingress.js +273 -0
  34. package/dist/channel-ingress.js.map +1 -0
  35. package/dist/channel.d.ts +146 -0
  36. package/dist/channel.d.ts.map +1 -0
  37. package/dist/channel.js +2 -0
  38. package/dist/channel.js.map +1 -0
  39. package/dist/checkpoints.d.ts +34 -0
  40. package/dist/checkpoints.d.ts.map +1 -0
  41. package/dist/checkpoints.js +86 -0
  42. package/dist/checkpoints.js.map +1 -0
  43. package/dist/code-mode.d.ts +20 -0
  44. package/dist/code-mode.d.ts.map +1 -0
  45. package/dist/code-mode.js +658 -0
  46. package/dist/code-mode.js.map +1 -0
  47. package/dist/computer-relay-protocol.d.ts +36 -0
  48. package/dist/computer-relay-protocol.d.ts.map +1 -0
  49. package/dist/computer-relay-protocol.js +127 -0
  50. package/dist/computer-relay-protocol.js.map +1 -0
  51. package/dist/concurrency.d.ts +68 -0
  52. package/dist/concurrency.d.ts.map +1 -0
  53. package/dist/concurrency.js +193 -0
  54. package/dist/concurrency.js.map +1 -0
  55. package/dist/connection-auth-util.d.ts +56 -0
  56. package/dist/connection-auth-util.d.ts.map +1 -0
  57. package/dist/connection-auth-util.js +154 -0
  58. package/dist/connection-auth-util.js.map +1 -0
  59. package/dist/connection-clients.d.ts +50 -0
  60. package/dist/connection-clients.d.ts.map +1 -0
  61. package/dist/connection-clients.js +402 -0
  62. package/dist/connection-clients.js.map +1 -0
  63. package/dist/connection-stores.d.ts +108 -0
  64. package/dist/connection-stores.d.ts.map +1 -0
  65. package/dist/connection-stores.js +127 -0
  66. package/dist/connection-stores.js.map +1 -0
  67. package/dist/connection-util.d.ts +27 -0
  68. package/dist/connection-util.d.ts.map +1 -0
  69. package/dist/connection-util.js +118 -0
  70. package/dist/connection-util.js.map +1 -0
  71. package/dist/connections.d.ts +152 -0
  72. package/dist/connections.d.ts.map +1 -0
  73. package/dist/connections.js +838 -0
  74. package/dist/connections.js.map +1 -0
  75. package/dist/content-capture.d.ts +32 -0
  76. package/dist/content-capture.d.ts.map +1 -0
  77. package/dist/content-capture.js +77 -0
  78. package/dist/content-capture.js.map +1 -0
  79. package/dist/context-policy-util.d.ts +45 -0
  80. package/dist/context-policy-util.d.ts.map +1 -0
  81. package/dist/context-policy-util.js +120 -0
  82. package/dist/context-policy-util.js.map +1 -0
  83. package/dist/conversation-context.d.ts +55 -0
  84. package/dist/conversation-context.d.ts.map +1 -0
  85. package/dist/conversation-context.js +179 -0
  86. package/dist/conversation-context.js.map +1 -0
  87. package/dist/conversation-transcript.d.ts +49 -0
  88. package/dist/conversation-transcript.d.ts.map +1 -0
  89. package/dist/conversation-transcript.js +77 -0
  90. package/dist/conversation-transcript.js.map +1 -0
  91. package/dist/conversation-turn-dispatch.d.ts +46 -0
  92. package/dist/conversation-turn-dispatch.d.ts.map +1 -0
  93. package/dist/conversation-turn-dispatch.js +201 -0
  94. package/dist/conversation-turn-dispatch.js.map +1 -0
  95. package/dist/delivery-queue.d.ts +89 -0
  96. package/dist/delivery-queue.d.ts.map +1 -0
  97. package/dist/delivery-queue.js +244 -0
  98. package/dist/delivery-queue.js.map +1 -0
  99. package/dist/delivery-send.d.ts +44 -0
  100. package/dist/delivery-send.d.ts.map +1 -0
  101. package/dist/delivery-send.js +494 -0
  102. package/dist/delivery-send.js.map +1 -0
  103. package/dist/env-config.d.ts +6 -0
  104. package/dist/env-config.d.ts.map +1 -0
  105. package/dist/env-config.js +27 -0
  106. package/dist/env-config.js.map +1 -0
  107. package/dist/eval-run-options.d.ts +37 -0
  108. package/dist/eval-run-options.d.ts.map +1 -0
  109. package/dist/eval-run-options.js +106 -0
  110. package/dist/eval-run-options.js.map +1 -0
  111. package/dist/harness-continuation.d.ts +54 -0
  112. package/dist/harness-continuation.d.ts.map +1 -0
  113. package/dist/harness-continuation.js +58 -0
  114. package/dist/harness-continuation.js.map +1 -0
  115. package/dist/harness-loop.d.ts +110 -0
  116. package/dist/harness-loop.d.ts.map +1 -0
  117. package/dist/harness-loop.js +575 -0
  118. package/dist/harness-loop.js.map +1 -0
  119. package/dist/hook-dispatch.d.ts +19 -0
  120. package/dist/hook-dispatch.d.ts.map +1 -0
  121. package/dist/hook-dispatch.js +37 -0
  122. package/dist/hook-dispatch.js.map +1 -0
  123. package/dist/http.d.ts +26 -0
  124. package/dist/http.d.ts.map +1 -0
  125. package/dist/http.js +114 -0
  126. package/dist/http.js.map +1 -0
  127. package/dist/in-memory-conversation-turn-store.d.ts +29 -0
  128. package/dist/in-memory-conversation-turn-store.d.ts.map +1 -0
  129. package/dist/in-memory-conversation-turn-store.js +166 -0
  130. package/dist/in-memory-conversation-turn-store.js.map +1 -0
  131. package/dist/in-memory-run-store.d.ts +39 -0
  132. package/dist/in-memory-run-store.d.ts.map +1 -0
  133. package/dist/in-memory-run-store.js +332 -0
  134. package/dist/in-memory-run-store.js.map +1 -0
  135. package/dist/in-memory-sandbox-session-store.d.ts +33 -0
  136. package/dist/in-memory-sandbox-session-store.d.ts.map +1 -0
  137. package/dist/in-memory-sandbox-session-store.js +186 -0
  138. package/dist/in-memory-sandbox-session-store.js.map +1 -0
  139. package/dist/in-memory-small-stores.d.ts +117 -0
  140. package/dist/in-memory-small-stores.d.ts.map +1 -0
  141. package/dist/in-memory-small-stores.js +340 -0
  142. package/dist/in-memory-small-stores.js.map +1 -0
  143. package/dist/in-memory-usage-store.d.ts +15 -0
  144. package/dist/in-memory-usage-store.d.ts.map +1 -0
  145. package/dist/in-memory-usage-store.js +49 -0
  146. package/dist/in-memory-usage-store.js.map +1 -0
  147. package/dist/index.d.ts +467 -0
  148. package/dist/index.d.ts.map +1 -0
  149. package/dist/index.js +2046 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/json-util.d.ts +19 -0
  152. package/dist/json-util.d.ts.map +1 -0
  153. package/dist/json-util.js +59 -0
  154. package/dist/json-util.js.map +1 -0
  155. package/dist/local-sandbox.d.ts +16 -0
  156. package/dist/local-sandbox.d.ts.map +1 -0
  157. package/dist/local-sandbox.js +327 -0
  158. package/dist/local-sandbox.js.map +1 -0
  159. package/dist/logging.d.ts +16 -0
  160. package/dist/logging.d.ts.map +1 -0
  161. package/dist/logging.js +41 -0
  162. package/dist/logging.js.map +1 -0
  163. package/dist/mcp-client.d.ts +27 -0
  164. package/dist/mcp-client.d.ts.map +1 -0
  165. package/dist/mcp-client.js +169 -0
  166. package/dist/mcp-client.js.map +1 -0
  167. package/dist/model-harnesses.d.ts +4 -0
  168. package/dist/model-harnesses.d.ts.map +1 -0
  169. package/dist/model-harnesses.js +6 -0
  170. package/dist/model-harnesses.js.map +1 -0
  171. package/dist/model-media.d.ts +36 -0
  172. package/dist/model-media.d.ts.map +1 -0
  173. package/dist/model-media.js +234 -0
  174. package/dist/model-media.js.map +1 -0
  175. package/dist/operator-controls.d.ts +31 -0
  176. package/dist/operator-controls.d.ts.map +1 -0
  177. package/dist/operator-controls.js +71 -0
  178. package/dist/operator-controls.js.map +1 -0
  179. package/dist/pi-agent-harness.d.ts +40 -0
  180. package/dist/pi-agent-harness.d.ts.map +1 -0
  181. package/dist/pi-agent-harness.js +222 -0
  182. package/dist/pi-agent-harness.js.map +1 -0
  183. package/dist/pi-harness.d.ts +42 -0
  184. package/dist/pi-harness.d.ts.map +1 -0
  185. package/dist/pi-harness.js +142 -0
  186. package/dist/pi-harness.js.map +1 -0
  187. package/dist/relay-mcp-client.d.ts +17 -0
  188. package/dist/relay-mcp-client.d.ts.map +1 -0
  189. package/dist/relay-mcp-client.js +119 -0
  190. package/dist/relay-mcp-client.js.map +1 -0
  191. package/dist/replay-resume.d.ts +107 -0
  192. package/dist/replay-resume.d.ts.map +1 -0
  193. package/dist/replay-resume.js +495 -0
  194. package/dist/replay-resume.js.map +1 -0
  195. package/dist/resource-projection-util.d.ts +58 -0
  196. package/dist/resource-projection-util.d.ts.map +1 -0
  197. package/dist/resource-projection-util.js +298 -0
  198. package/dist/resource-projection-util.js.map +1 -0
  199. package/dist/resource-projection.d.ts +45 -0
  200. package/dist/resource-projection.d.ts.map +1 -0
  201. package/dist/resource-projection.js +481 -0
  202. package/dist/resource-projection.js.map +1 -0
  203. package/dist/run-heartbeat.d.ts +34 -0
  204. package/dist/run-heartbeat.d.ts.map +1 -0
  205. package/dist/run-heartbeat.js +62 -0
  206. package/dist/run-heartbeat.js.map +1 -0
  207. package/dist/run-outcome.d.ts +47 -0
  208. package/dist/run-outcome.d.ts.map +1 -0
  209. package/dist/run-outcome.js +92 -0
  210. package/dist/run-outcome.js.map +1 -0
  211. package/dist/run-recovery.d.ts +117 -0
  212. package/dist/run-recovery.d.ts.map +1 -0
  213. package/dist/run-recovery.js +466 -0
  214. package/dist/run-recovery.js.map +1 -0
  215. package/dist/run-resolver.d.ts +35 -0
  216. package/dist/run-resolver.d.ts.map +1 -0
  217. package/dist/run-resolver.js +84 -0
  218. package/dist/run-resolver.js.map +1 -0
  219. package/dist/run-stream.d.ts +37 -0
  220. package/dist/run-stream.d.ts.map +1 -0
  221. package/dist/run-stream.js +78 -0
  222. package/dist/run-stream.js.map +1 -0
  223. package/dist/runs-query.d.ts +29 -0
  224. package/dist/runs-query.d.ts.map +1 -0
  225. package/dist/runs-query.js +142 -0
  226. package/dist/runs-query.js.map +1 -0
  227. package/dist/runtime-bundle.d.ts +3 -0
  228. package/dist/runtime-bundle.d.ts.map +1 -0
  229. package/dist/runtime-bundle.js +18 -0
  230. package/dist/runtime-bundle.js.map +1 -0
  231. package/dist/runtime-types.d.ts +397 -0
  232. package/dist/runtime-types.d.ts.map +1 -0
  233. package/dist/runtime-types.js +2 -0
  234. package/dist/runtime-types.js.map +1 -0
  235. package/dist/runtime-util.d.ts +45 -0
  236. package/dist/runtime-util.d.ts.map +1 -0
  237. package/dist/runtime-util.js +116 -0
  238. package/dist/runtime-util.js.map +1 -0
  239. package/dist/sandbox-cli-client.d.ts +20 -0
  240. package/dist/sandbox-cli-client.d.ts.map +1 -0
  241. package/dist/sandbox-cli-client.js +97 -0
  242. package/dist/sandbox-cli-client.js.map +1 -0
  243. package/dist/sandbox-fs.d.ts +56 -0
  244. package/dist/sandbox-fs.d.ts.map +1 -0
  245. package/dist/sandbox-fs.js +276 -0
  246. package/dist/sandbox-fs.js.map +1 -0
  247. package/dist/sandbox-session-key.d.ts +8 -0
  248. package/dist/sandbox-session-key.d.ts.map +1 -0
  249. package/dist/sandbox-session-key.js +32 -0
  250. package/dist/sandbox-session-key.js.map +1 -0
  251. package/dist/sandbox-snapshot-policy.d.ts +27 -0
  252. package/dist/sandbox-snapshot-policy.d.ts.map +1 -0
  253. package/dist/sandbox-snapshot-policy.js +94 -0
  254. package/dist/sandbox-snapshot-policy.js.map +1 -0
  255. package/dist/sandbox-sync-worker.d.ts +63 -0
  256. package/dist/sandbox-sync-worker.d.ts.map +1 -0
  257. package/dist/sandbox-sync-worker.js +448 -0
  258. package/dist/sandbox-sync-worker.js.map +1 -0
  259. package/dist/schedule-execution.d.ts +59 -0
  260. package/dist/schedule-execution.d.ts.map +1 -0
  261. package/dist/schedule-execution.js +951 -0
  262. package/dist/schedule-execution.js.map +1 -0
  263. package/dist/scheduler.d.ts +19 -0
  264. package/dist/scheduler.d.ts.map +1 -0
  265. package/dist/scheduler.js +38 -0
  266. package/dist/scheduler.js.map +1 -0
  267. package/dist/security.d.ts +20 -0
  268. package/dist/security.d.ts.map +1 -0
  269. package/dist/security.js +145 -0
  270. package/dist/security.js.map +1 -0
  271. package/dist/self-improvement.d.ts +245 -0
  272. package/dist/self-improvement.d.ts.map +1 -0
  273. package/dist/self-improvement.js +554 -0
  274. package/dist/self-improvement.js.map +1 -0
  275. package/dist/source-loader.d.ts +19 -0
  276. package/dist/source-loader.d.ts.map +1 -0
  277. package/dist/source-loader.js +160 -0
  278. package/dist/source-loader.js.map +1 -0
  279. package/dist/state-store-helpers.d.ts +28 -0
  280. package/dist/state-store-helpers.d.ts.map +1 -0
  281. package/dist/state-store-helpers.js +164 -0
  282. package/dist/state-store-helpers.js.map +1 -0
  283. package/dist/state-stores.d.ts +25 -0
  284. package/dist/state-stores.d.ts.map +1 -0
  285. package/dist/state-stores.js +157 -0
  286. package/dist/state-stores.js.map +1 -0
  287. package/dist/state.d.ts +736 -0
  288. package/dist/state.d.ts.map +1 -0
  289. package/dist/state.js +46 -0
  290. package/dist/state.js.map +1 -0
  291. package/dist/storage.d.ts +188 -0
  292. package/dist/storage.d.ts.map +1 -0
  293. package/dist/storage.js +752 -0
  294. package/dist/storage.js.map +1 -0
  295. package/dist/subagent-execution.d.ts +80 -0
  296. package/dist/subagent-execution.d.ts.map +1 -0
  297. package/dist/subagent-execution.js +135 -0
  298. package/dist/subagent-execution.js.map +1 -0
  299. package/dist/telemetry.d.ts +49 -0
  300. package/dist/telemetry.d.ts.map +1 -0
  301. package/dist/telemetry.js +60 -0
  302. package/dist/telemetry.js.map +1 -0
  303. package/dist/tool-apis.d.ts +22 -0
  304. package/dist/tool-apis.d.ts.map +1 -0
  305. package/dist/tool-apis.js +344 -0
  306. package/dist/tool-apis.js.map +1 -0
  307. package/dist/tool-execution.d.ts +143 -0
  308. package/dist/tool-execution.d.ts.map +1 -0
  309. package/dist/tool-execution.js +573 -0
  310. package/dist/tool-execution.js.map +1 -0
  311. package/dist/trusted-attachments.d.ts +20 -0
  312. package/dist/trusted-attachments.d.ts.map +1 -0
  313. package/dist/trusted-attachments.js +276 -0
  314. package/dist/trusted-attachments.js.map +1 -0
  315. package/dist/usage-accounting.d.ts +37 -0
  316. package/dist/usage-accounting.d.ts.map +1 -0
  317. package/dist/usage-accounting.js +181 -0
  318. package/dist/usage-accounting.js.map +1 -0
  319. package/dist/usage-budget.d.ts +29 -0
  320. package/dist/usage-budget.d.ts.map +1 -0
  321. package/dist/usage-budget.js +145 -0
  322. package/dist/usage-budget.js.map +1 -0
  323. package/dist/usage-reconciliation.d.ts +76 -0
  324. package/dist/usage-reconciliation.d.ts.map +1 -0
  325. package/dist/usage-reconciliation.js +463 -0
  326. package/dist/usage-reconciliation.js.map +1 -0
  327. package/dist/usage-records.d.ts +24 -0
  328. package/dist/usage-records.d.ts.map +1 -0
  329. package/dist/usage-records.js +445 -0
  330. package/dist/usage-records.js.map +1 -0
  331. package/package.json +51 -0
@@ -0,0 +1,951 @@
1
+ import { isTriggerHandlerDefinition, normalizeRoutineRunRecord, normalizeTriggerPrepareResult, triggerPrepareContext } from "./channel-http-util.js";
2
+ import { RunCapacityError } from "./concurrency.js";
3
+ import { dueTimeForSchedule, dynamicScheduleMessage, stringValue, timestamp } from "./runtime-util.js";
4
+ import { buildDefaultContextBundle } from "./sandbox-fs.js";
5
+ import { isJsonObject, safeJson } from "./json-util.js";
6
+ import { failRun } from "./run-outcome.js";
7
+ import { isRuntimeSettingsStore } from "./state.js";
8
+ import { memoryBodyText, memoryDocumentSummary, positiveLimit } from "./storage.js";
9
+ export async function registerManifestSchedulesImpl(host) {
10
+ const records = [];
11
+ for (const schedule of manifestScheduleRegistrations(host)) {
12
+ records.push(await host.state.registerSchedule({
13
+ id: schedule.schedule,
14
+ name: `schedule:${schedule.schedule}`,
15
+ cron: schedule.cron,
16
+ ...(schedule.timezone ? { timezone: schedule.timezone } : {}),
17
+ metadata: {
18
+ agentRevision: host.manifest.agentRevision,
19
+ message: schedule.message ?? compiledSchedule(host, schedule.schedule)?.message ?? null,
20
+ trigger: schedule.trigger ? safeJson(schedule.trigger) : null
21
+ }
22
+ }));
23
+ }
24
+ return records;
25
+ }
26
+ export async function runDueSchedulesImpl(host, options = {}) {
27
+ host.boot();
28
+ if (!(await host.agentEnabled()))
29
+ return [];
30
+ await registerManifestSchedulesImpl(host);
31
+ const now = options.now ?? host.now();
32
+ const lookbackMs = options.lookbackMs ?? host.schedulerTickMs;
33
+ const results = [];
34
+ for (const schedule of manifestScheduleRegistrations(host)) {
35
+ const dueAt = dueTimeForSchedule(schedule, now, lookbackMs);
36
+ if (!dueAt)
37
+ continue;
38
+ const dueAtIso = dueAt.toISOString();
39
+ const idempotencyKey = `${schedule.idempotencyKey}:${dueAtIso}`;
40
+ // Message schedules run through the bounded semaphore; claim capacity
41
+ // BEFORE reserving the idempotency key so a saturated runtime skips the
42
+ // tick without burning the key (the next sweep retries). Triggered
43
+ // schedules use an existingRun and bypass admission (enter()).
44
+ let admission;
45
+ if (!schedule.trigger) {
46
+ const admitted = host.admitRunOrReject();
47
+ if (admitted instanceof RunCapacityError) {
48
+ results.push({ schedule: schedule.schedule, dueAt: dueAtIso, idempotencyKey, status: "skipped", error: "run capacity saturated" });
49
+ continue;
50
+ }
51
+ admission = admitted;
52
+ }
53
+ const reserved = await host.state.reserveIdempotencyKey("schedule", idempotencyKey, host.manifest.agentRevision).catch((error) => {
54
+ admission?.release();
55
+ throw error;
56
+ });
57
+ if (!reserved) {
58
+ admission?.release();
59
+ results.push({ schedule: schedule.schedule, dueAt: dueAtIso, idempotencyKey, status: "skipped" });
60
+ continue;
61
+ }
62
+ // Durable claim evidence, written immediately after the key burn: a crash
63
+ // before the run exists leaves a "preparing" record instead of a silently
64
+ // lost occurrence. (The residual window is the single adjacent statement.)
65
+ await host.state.recordScheduleRun({
66
+ scheduleId: schedule.schedule,
67
+ runAt: dueAtIso,
68
+ idempotencyKey,
69
+ status: "preparing"
70
+ }).catch((error) => {
71
+ admission?.release();
72
+ throw error;
73
+ });
74
+ const job = manifestScheduleExecution(host, schedule, dueAtIso, idempotencyKey);
75
+ try {
76
+ results.push(await runScheduleExecution(host, job, admission));
77
+ }
78
+ catch (error) {
79
+ const message = error instanceof Error ? error.message : String(error);
80
+ await host.state.recordScheduleRun({
81
+ scheduleId: schedule.schedule,
82
+ runAt: dueAtIso,
83
+ idempotencyKey,
84
+ status: "failed"
85
+ });
86
+ results.push({ schedule: schedule.schedule, dueAt: dueAtIso, idempotencyKey, status: "failed", error: message });
87
+ }
88
+ }
89
+ results.push(...(await runDueDynamicSchedules(host, now)));
90
+ return results;
91
+ }
92
+ export async function dispatchAutomationEventImpl(host, event) {
93
+ host.boot();
94
+ if (!(await host.agentEnabled()))
95
+ return [];
96
+ if (!event.source.trim() || !event.event.trim() || !event.eventId.trim()) {
97
+ throw new Error("Automation events require non-empty source, event, and eventId values.");
98
+ }
99
+ if (event.occurredAt && Number.isNaN(new Date(event.occurredAt).getTime())) {
100
+ throw new Error("Automation event occurredAt must be a valid ISO timestamp.");
101
+ }
102
+ const results = [];
103
+ for (const automation of host.manifest.automationRegistrations ?? []) {
104
+ if (automation.trigger.type !== "event")
105
+ continue;
106
+ if (automation.trigger.source !== event.source || automation.trigger.event !== event.event)
107
+ continue;
108
+ if (automation.trigger.filter && !jsonSubsetMatches(automation.trigger.filter, event.payload))
109
+ continue;
110
+ const idempotencyKey = `${automation.idempotencyKey}:${event.eventId}`;
111
+ let admission;
112
+ if (!automation.lifecycle) {
113
+ const admitted = host.admitRunOrReject();
114
+ if (admitted instanceof RunCapacityError) {
115
+ results.push({
116
+ automation: automation.automation,
117
+ eventId: event.eventId,
118
+ idempotencyKey,
119
+ status: "skipped",
120
+ error: "run capacity saturated"
121
+ });
122
+ continue;
123
+ }
124
+ admission = admitted;
125
+ }
126
+ const reserved = await host.state.reserveIdempotencyKey(`automation:${automation.automation}:event`, idempotencyKey, host.manifest.agentRevision).catch((error) => {
127
+ admission?.release();
128
+ throw error;
129
+ });
130
+ if (!reserved) {
131
+ admission?.release();
132
+ results.push({
133
+ automation: automation.automation,
134
+ eventId: event.eventId,
135
+ idempotencyKey,
136
+ status: "skipped"
137
+ });
138
+ continue;
139
+ }
140
+ const execution = eventAutomationExecution(host, automation, event, idempotencyKey);
141
+ try {
142
+ const result = await runScheduleExecution(host, execution, admission);
143
+ results.push({
144
+ automation: automation.automation,
145
+ eventId: event.eventId,
146
+ idempotencyKey,
147
+ status: result.status,
148
+ ...(result.runId ? { runId: result.runId } : {}),
149
+ ...(result.error ? { error: result.error } : {})
150
+ });
151
+ }
152
+ catch (error) {
153
+ results.push({
154
+ automation: automation.automation,
155
+ eventId: event.eventId,
156
+ idempotencyKey,
157
+ status: "failed",
158
+ error: error instanceof Error ? error.message : String(error)
159
+ });
160
+ }
161
+ }
162
+ return results;
163
+ }
164
+ function eventAutomationExecution(host, automation, event, idempotencyKey) {
165
+ const eventAt = event.occurredAt ?? timestamp();
166
+ const compiled = host.manifest.automations?.find((candidate) => candidate.name === automation.automation);
167
+ const trigger = automation.lifecycle
168
+ ? {
169
+ handler: automation.lifecycle.handler,
170
+ ...(automation.target ? { target: automation.target } : {}),
171
+ ...(automation.metadata ? { metadata: automation.metadata } : {})
172
+ }
173
+ : undefined;
174
+ return {
175
+ source: "manifest",
176
+ scheduleId: automation.automation,
177
+ resultSchedule: automation.automation,
178
+ dueAtIso: eventAt,
179
+ idempotencyKey,
180
+ message: automation.message ?? `Handle ${event.event} from ${event.source}.`,
181
+ channel: "automation",
182
+ ...(trigger ? { trigger } : {}),
183
+ ...(automation.target ? { target: automation.target } : {}),
184
+ automationEvent: event,
185
+ metadata: {
186
+ automation: automation.automation,
187
+ event: safeJson(event),
188
+ ...(automation.metadata ?? {})
189
+ },
190
+ definition: safeJson(compiled ?? automation),
191
+ ...(event.userId ? { userId: event.userId } : {}),
192
+ ...(event.conversationId ? { conversationId: event.conversationId } : {}),
193
+ ...(event.projectId ? { projectId: event.projectId } : {}),
194
+ ...(event.delivery ? { delivery: event.delivery } : {}),
195
+ turnMetadata: {
196
+ automation: automation.automation,
197
+ source: event.source,
198
+ event: event.event,
199
+ payload: event.payload,
200
+ ...(event.metadata ?? {})
201
+ }
202
+ };
203
+ }
204
+ function jsonSubsetMatches(expected, actual) {
205
+ return Object.entries(expected).every(([key, expectedValue]) => {
206
+ if (!Object.prototype.hasOwnProperty.call(actual, key))
207
+ return false;
208
+ const actualValue = actual[key];
209
+ if (isJsonObject(expectedValue)) {
210
+ return isJsonObject(actualValue) && jsonSubsetMatches(expectedValue, actualValue);
211
+ }
212
+ return JSON.stringify(expectedValue) === JSON.stringify(actualValue);
213
+ });
214
+ }
215
+ function manifestScheduleExecution(host, schedule, dueAtIso, idempotencyKey) {
216
+ return {
217
+ source: "manifest",
218
+ scheduleId: schedule.schedule,
219
+ resultSchedule: schedule.schedule,
220
+ dueAtIso,
221
+ idempotencyKey,
222
+ message: scheduleMessage(host, schedule.schedule),
223
+ channel: "schedule",
224
+ ...(schedule.trigger ? { trigger: schedule.trigger } : {}),
225
+ ...(schedule.target ? { target: schedule.target } : {}),
226
+ metadata: {
227
+ schedule: schedule.schedule,
228
+ dueAt: dueAtIso,
229
+ idempotencyKey
230
+ },
231
+ definition: safeJson(compiledSchedule(host, schedule.schedule) ?? schedule)
232
+ };
233
+ }
234
+ async function runScheduleExecution(host, schedule, admission) {
235
+ return schedule.trigger ? runTriggeredSchedule(host, schedule) : runMessageSchedule(host, schedule, admission);
236
+ }
237
+ async function runMessageSchedule(host, schedule, admission) {
238
+ const overrides = admission ? { admission } : {};
239
+ if (schedule.target)
240
+ overrides.target = schedule.target;
241
+ const result = await host.run(scheduleRunOptions(host, schedule, schedule.message, schedule.metadata, overrides));
242
+ await host.state.recordScheduleRun({
243
+ scheduleId: schedule.resultSchedule,
244
+ runId: result.run.id,
245
+ runAt: schedule.dueAtIso,
246
+ idempotencyKey: schedule.idempotencyKey,
247
+ status: result.run.status
248
+ });
249
+ return {
250
+ schedule: schedule.resultSchedule,
251
+ dueAt: schedule.dueAtIso,
252
+ idempotencyKey: schedule.idempotencyKey,
253
+ status: result.run.status === "failed" ? "failed" : "completed",
254
+ runId: result.run.id
255
+ };
256
+ }
257
+ function scheduleRunOptions(host, schedule, message, metadata, overrides = {}) {
258
+ const options = {
259
+ message,
260
+ channel: schedule.channel,
261
+ eventId: schedule.idempotencyKey,
262
+ metadata,
263
+ ...overrides
264
+ };
265
+ if (schedule.userId)
266
+ options.userId = schedule.userId;
267
+ if (schedule.conversationId)
268
+ options.conversationId = schedule.conversationId;
269
+ if (schedule.projectId)
270
+ options.projectId = schedule.projectId;
271
+ if (schedule.delivery)
272
+ options.delivery = schedule.delivery;
273
+ if (schedule.conversationId) {
274
+ options.turn = {
275
+ eventId: schedule.idempotencyKey,
276
+ channel: schedule.channel,
277
+ conversationId: schedule.conversationId,
278
+ message,
279
+ ...(schedule.userId ? { userId: schedule.userId } : {}),
280
+ ...(schedule.delivery ? { delivery: schedule.delivery } : {}),
281
+ ...(schedule.turnMetadata ? { metadata: schedule.turnMetadata } : {})
282
+ };
283
+ }
284
+ return options;
285
+ }
286
+ async function runTriggeredSchedule(host, schedule) {
287
+ const trigger = schedule.trigger;
288
+ if (!trigger)
289
+ throw new Error(`Schedule ${schedule.resultSchedule} has no trigger definition.`);
290
+ const handler = automationHandlers(host).find((candidate) => candidate.name === trigger.handler);
291
+ if (!handler)
292
+ throw new Error(`Trigger handler not found: ${trigger.handler}`);
293
+ const invocation = {
294
+ kind: schedule.automationEvent ? "event" : "schedule",
295
+ source: schedule.source,
296
+ ...(schedule.automationEvent
297
+ ? { automation: schedule.resultSchedule, event: schedule.automationEvent }
298
+ : { schedule: schedule.resultSchedule, dueAt: schedule.dueAtIso }),
299
+ handler: handler.name,
300
+ idempotencyKey: schedule.idempotencyKey
301
+ };
302
+ if (trigger.metadata)
303
+ invocation.metadata = trigger.metadata;
304
+ let run = await host.state.createRun({
305
+ agentRevision: host.manifest.agentRevision,
306
+ status: "created",
307
+ input: {
308
+ message: schedule.message,
309
+ model: host.manifest.agent.model,
310
+ channel: schedule.channel,
311
+ eventId: schedule.idempotencyKey,
312
+ conversationId: schedule.conversationId ?? null,
313
+ userId: schedule.userId ?? null,
314
+ projectId: schedule.projectId ?? null,
315
+ delivery: schedule.delivery ?? null,
316
+ metadata: {
317
+ ...schedule.metadata,
318
+ trigger: safeJson(invocation)
319
+ }
320
+ }
321
+ });
322
+ await host.state.recordScheduleRun({
323
+ scheduleId: schedule.resultSchedule,
324
+ runId: run.id,
325
+ runAt: schedule.dueAtIso,
326
+ idempotencyKey: schedule.idempotencyKey,
327
+ status: "preparing"
328
+ });
329
+ const definition = await loadTriggerHandler(host, handler);
330
+ const prepareStartedAt = timestamp();
331
+ let prepareResult = {};
332
+ let prepareContext = { runId: run.id };
333
+ try {
334
+ await host.state.appendEvent(run.id, "trigger.prepare_started", {
335
+ handler: handler.name,
336
+ schedule: schedule.resultSchedule,
337
+ source: schedule.source,
338
+ dueAt: schedule.dueAtIso,
339
+ idempotencyKey: schedule.idempotencyKey
340
+ });
341
+ const prepared = await definition.prepare?.(createTriggerHandlerContext(host, run, schedule, invocation, {}));
342
+ prepareResult = normalizeTriggerPrepareResult(prepared);
343
+ prepareContext = triggerPrepareContext(run.id, prepareResult);
344
+ await host.state.appendEvent(run.id, "trigger.prepare_completed", {
345
+ handler: handler.name,
346
+ target: safeJson(prepareResult.target ?? trigger.target ?? null),
347
+ promptContext: safeJson(prepareResult.promptContext ?? {})
348
+ });
349
+ await host.emitSpan("ai.assembly-line.trigger.prepare", prepareStartedAt, host.runSpanAttributes(run, {
350
+ triggerHandler: handler.name,
351
+ schedule: schedule.resultSchedule,
352
+ scheduleSource: schedule.source,
353
+ status: "completed"
354
+ }), {
355
+ parentSpanId: host.turnSpanId(run.id),
356
+ status: "ok"
357
+ });
358
+ }
359
+ catch (error) {
360
+ const message = error instanceof Error ? error.message : String(error);
361
+ await host.state.appendEvent(run.id, "trigger.prepare_failed", { handler: handler.name, error: message });
362
+ run = await failRun({ state: host.state }, run.id, { reason: "trigger.prepare_failed", error: message });
363
+ await host.state.recordScheduleRun({
364
+ scheduleId: schedule.resultSchedule,
365
+ runId: run.id,
366
+ runAt: schedule.dueAtIso,
367
+ idempotencyKey: schedule.idempotencyKey,
368
+ status: "failed"
369
+ });
370
+ await host.emitSpan("ai.assembly-line.trigger.prepare", prepareStartedAt, host.runSpanAttributes(run, {
371
+ triggerHandler: handler.name,
372
+ schedule: schedule.resultSchedule,
373
+ scheduleSource: schedule.source,
374
+ status: "failed",
375
+ error: message
376
+ }), {
377
+ parentSpanId: host.turnSpanId(run.id),
378
+ status: "error"
379
+ });
380
+ return { schedule: schedule.resultSchedule, dueAt: schedule.dueAtIso, idempotencyKey: schedule.idempotencyKey, status: "failed", runId: run.id, error: message };
381
+ }
382
+ const target = prepareResult.target ?? trigger.target ?? schedule.target;
383
+ const promptContext = {
384
+ triggerKind: invocation.kind,
385
+ triggerSource: invocation.source ?? "manifest",
386
+ triggerKey: invocation.idempotencyKey,
387
+ ...(schedule.automationEvent
388
+ ? {
389
+ automation: schedule.resultSchedule,
390
+ event: safeJson(schedule.automationEvent)
391
+ }
392
+ : {
393
+ schedule: schedule.resultSchedule,
394
+ dueAt: schedule.dueAtIso
395
+ }),
396
+ runId: run.id,
397
+ ...(prepareResult.promptContext ?? {})
398
+ };
399
+ const metadata = {
400
+ ...schedule.metadata,
401
+ trigger: safeJson(invocation),
402
+ promptContext,
403
+ ...(prepareResult.metadata ?? {})
404
+ };
405
+ const message = prepareResult.message ?? prepareResult.prompt ?? schedule.message ?? `Run scheduled trigger ${handler.name}.`;
406
+ let runResult;
407
+ let finalizeResult;
408
+ try {
409
+ await host.state.recordScheduleRun({
410
+ scheduleId: schedule.resultSchedule,
411
+ runId: run.id,
412
+ runAt: schedule.dueAtIso,
413
+ idempotencyKey: schedule.idempotencyKey,
414
+ status: "running"
415
+ });
416
+ const runOptions = scheduleRunOptions(host, schedule, message, metadata, {
417
+ existingRun: run,
418
+ promptContext
419
+ });
420
+ if (target)
421
+ runOptions.target = target;
422
+ runResult = await host.run(runOptions);
423
+ run = runResult.run;
424
+ const failureMessage = run.status === "failed" ? await host.latestRunFailureMessage(run.id) : undefined;
425
+ finalizeResult = {
426
+ ok: run.status !== "failed",
427
+ runId: run.id,
428
+ status: run.status,
429
+ summary: runResult.response ?? "",
430
+ response: runResult.response ?? "",
431
+ metadata: {
432
+ eventCount: runResult.events.length,
433
+ toolCallCount: runResult.toolCalls.length
434
+ }
435
+ };
436
+ if (failureMessage)
437
+ finalizeResult.error = failureMessage;
438
+ }
439
+ catch (error) {
440
+ const messageText = error instanceof Error ? error.message : String(error);
441
+ await host.state.appendEvent(run.id, "trigger.model_failed", { handler: handler.name, error: messageText });
442
+ run = await failRun({ state: host.state }, run.id, { reason: "trigger.model_failed", error: messageText });
443
+ finalizeResult = {
444
+ ok: false,
445
+ runId: run.id,
446
+ status: "failed",
447
+ summary: messageText,
448
+ error: messageText
449
+ };
450
+ }
451
+ const finalizeStartedAt = timestamp();
452
+ try {
453
+ await host.state.appendEvent(run.id, "trigger.finalize_started", {
454
+ handler: handler.name,
455
+ ok: finalizeResult.ok,
456
+ status: finalizeResult.status ?? null
457
+ });
458
+ await definition.finalize?.(createTriggerHandlerContext(host, run, schedule, invocation, prepareContext), finalizeResult);
459
+ await host.state.appendEvent(run.id, "trigger.finalize_completed", {
460
+ handler: handler.name,
461
+ ok: finalizeResult.ok,
462
+ status: finalizeResult.status ?? null
463
+ });
464
+ await host.emitSpan("ai.assembly-line.trigger.finalize", finalizeStartedAt, host.runSpanAttributes(run, {
465
+ triggerHandler: handler.name,
466
+ schedule: schedule.resultSchedule,
467
+ scheduleSource: schedule.source,
468
+ status: "completed",
469
+ resultOk: finalizeResult.ok
470
+ }), {
471
+ parentSpanId: host.turnSpanId(run.id),
472
+ status: "ok"
473
+ });
474
+ }
475
+ catch (error) {
476
+ const messageText = error instanceof Error ? error.message : String(error);
477
+ await host.state.appendEvent(run.id, "trigger.finalize_failed", { handler: handler.name, error: messageText });
478
+ run = await failRun({ state: host.state }, run.id, { reason: "trigger.finalize_failed", error: messageText });
479
+ await host.emitSpan("ai.assembly-line.trigger.finalize", finalizeStartedAt, host.runSpanAttributes(run, {
480
+ triggerHandler: handler.name,
481
+ schedule: schedule.resultSchedule,
482
+ scheduleSource: schedule.source,
483
+ status: "failed",
484
+ error: messageText
485
+ }), {
486
+ parentSpanId: host.turnSpanId(run.id),
487
+ status: "error"
488
+ });
489
+ finalizeResult = {
490
+ ...finalizeResult,
491
+ ok: false,
492
+ status: "failed",
493
+ error: messageText,
494
+ summary: messageText
495
+ };
496
+ }
497
+ const finalRun = await host.state.getRun(run.id) ?? run;
498
+ await host.state.recordScheduleRun({
499
+ scheduleId: schedule.resultSchedule,
500
+ runId: finalRun.id,
501
+ runAt: schedule.dueAtIso,
502
+ idempotencyKey: schedule.idempotencyKey,
503
+ status: finalRun.status
504
+ });
505
+ return {
506
+ schedule: schedule.resultSchedule,
507
+ dueAt: schedule.dueAtIso,
508
+ idempotencyKey: schedule.idempotencyKey,
509
+ status: finalRun.status === "failed" || !finalizeResult.ok ? "failed" : "completed",
510
+ runId: finalRun.id,
511
+ ...(finalizeResult.error ? { error: finalizeResult.error } : {})
512
+ };
513
+ }
514
+ async function loadTriggerHandler(host, handler) {
515
+ const module = await host.sourceLoader.load(handler.source);
516
+ const candidates = [module.default, module[handler.name], ...Object.values(module)];
517
+ const definition = candidates.find(isTriggerHandlerDefinition);
518
+ if (!definition)
519
+ throw new Error(`Trigger handler ${handler.name} did not export a trigger handler definition.`);
520
+ return definition;
521
+ }
522
+ export function normalizeScheduleTriggerDefinitionImpl(host, value) {
523
+ if (!isJsonObject(value))
524
+ throw new Error("Schedule trigger must be an object.");
525
+ const handler = stringValue(value.handler);
526
+ if (!handler)
527
+ throw new Error("Schedule trigger requires handler.");
528
+ if (!automationHandlers(host).some((candidate) => candidate.name === handler)) {
529
+ throw new Error(`Unknown trigger handler: ${handler}`);
530
+ }
531
+ const trigger = { handler };
532
+ if (value.target !== undefined && value.target !== null) {
533
+ trigger.target = normalizeTriggerTarget(value.target);
534
+ }
535
+ if (value.metadata !== undefined) {
536
+ if (!isJsonObject(value.metadata))
537
+ throw new Error("Schedule trigger metadata must be an object.");
538
+ trigger.metadata = value.metadata;
539
+ }
540
+ return trigger;
541
+ }
542
+ function normalizeTriggerTarget(value) {
543
+ if (!isJsonObject(value))
544
+ throw new Error("Schedule trigger target must be an object.");
545
+ const type = stringValue(value.type);
546
+ if (type === "skill") {
547
+ const name = stringValue(value.name);
548
+ if (!name)
549
+ throw new Error("Skill trigger targets require name.");
550
+ return { type, name, ...(isJsonObject(value.metadata) ? { metadata: value.metadata } : {}) };
551
+ }
552
+ if (type === "agent") {
553
+ const name = stringValue(value.name);
554
+ const model = stringValue(value.model);
555
+ const target = { type };
556
+ if (name)
557
+ target.name = name;
558
+ if (model)
559
+ target.model = model;
560
+ if (isJsonObject(value.metadata))
561
+ target.metadata = value.metadata;
562
+ return target;
563
+ }
564
+ if (type === "playbook") {
565
+ const name = stringValue(value.name);
566
+ if (!name)
567
+ throw new Error("Playbook trigger targets require name.");
568
+ return { type, name, ...(isJsonObject(value.metadata) ? { metadata: value.metadata } : {}) };
569
+ }
570
+ throw new Error(`Unsupported schedule trigger target type: ${type || "missing"}`);
571
+ }
572
+ function createTriggerHandlerContext(host, run, schedule, trigger, prepare) {
573
+ const sandboxHandle = host.createSandboxHandle(() => run, () => undefined, () => buildDefaultContextBundle(host.manifest, {
574
+ message: typeof run.input.message === "string" ? run.input.message : schedule.message,
575
+ channel: schedule.channel
576
+ }));
577
+ return {
578
+ runId: run.id,
579
+ agentRevision: host.manifest.agentRevision,
580
+ trigger,
581
+ state: createTriggerStateApi(host, run),
582
+ memory: host.createMemoryToolApi(run),
583
+ resources: createTriggerResourceApi(host, run, sandboxHandle),
584
+ blob: {
585
+ put: async (key, value, contentTypeOrOptions) => host.blob.put(key, value, contentTypeOrOptions),
586
+ get: async (key) => host.blob.get(key)
587
+ },
588
+ schedule: {
589
+ definition: schedule.definition,
590
+ run: {
591
+ scheduleId: schedule.resultSchedule,
592
+ runId: run.id,
593
+ runAt: trigger.dueAt ?? trigger.event?.occurredAt ?? schedule.dueAtIso,
594
+ idempotencyKey: trigger.idempotencyKey
595
+ }
596
+ },
597
+ env: host.env,
598
+ fetch: host.fetch,
599
+ prepare,
600
+ emit: async (eventType, data = {}) => {
601
+ await host.state.appendEvent(run.id, eventType, data);
602
+ },
603
+ idempotencyKey: (scope) => `${trigger.idempotencyKey}:${scope}`,
604
+ step: (key, fn, options) => host.durableStep(run.id, key, fn, options)
605
+ };
606
+ }
607
+ function createTriggerStateApi(host, run) {
608
+ const runtime = host;
609
+ return {
610
+ async upsertRoutineRun(input) {
611
+ const current = await runtime.state.getRun(run.id) ?? run;
612
+ const metadata = isJsonObject(current.input.metadata) ? current.input.metadata : {};
613
+ const existing = isJsonObject(metadata.routineRun) ? metadata.routineRun : {};
614
+ const record = normalizeRoutineRunRecord({
615
+ existing,
616
+ runId: run.id,
617
+ kind: input.kind,
618
+ triggerKey: input.triggerKey,
619
+ status: input.status ?? (stringValue(existing.status) || current.status),
620
+ metadata: input.metadata ?? (isJsonObject(existing.metadata) ? existing.metadata : {})
621
+ });
622
+ await runtime.state.updateRun(run.id, {
623
+ input: {
624
+ ...current.input,
625
+ metadata: {
626
+ ...metadata,
627
+ routineRun: safeJson(record)
628
+ }
629
+ }
630
+ });
631
+ await runtime.state.appendEvent(run.id, "routine.run_upserted", safeJson(record));
632
+ return record;
633
+ },
634
+ async completeRoutineRun(input) {
635
+ const current = await runtime.state.getRun(run.id) ?? run;
636
+ const metadata = isJsonObject(current.input.metadata) ? current.input.metadata : {};
637
+ const existing = isJsonObject(metadata.routineRun) ? metadata.routineRun : {};
638
+ const completeInput = {
639
+ existing,
640
+ runId: input.runId || run.id,
641
+ kind: stringValue(existing.kind) || "routine",
642
+ triggerKey: stringValue(existing.triggerKey) || "",
643
+ status: input.status,
644
+ metadata: input.metadata ?? (isJsonObject(existing.metadata) ? existing.metadata : {})
645
+ };
646
+ if (input.summary)
647
+ completeInput.summary = input.summary;
648
+ const record = normalizeRoutineRunRecord(completeInput);
649
+ await runtime.state.updateRun(run.id, {
650
+ input: {
651
+ ...current.input,
652
+ metadata: {
653
+ ...metadata,
654
+ routineRun: safeJson(record)
655
+ }
656
+ }
657
+ });
658
+ await runtime.state.appendEvent(run.id, "routine.run_completed", safeJson(record));
659
+ return record;
660
+ }
661
+ };
662
+ }
663
+ function createTriggerResourceApi(host, run, sandboxHandle) {
664
+ const base = host.createResourceToolApi(run, sandboxHandle);
665
+ return {
666
+ ...base,
667
+ collect: async (input = {}) => collectTriggerResources(host, run, input)
668
+ };
669
+ }
670
+ async function collectTriggerResources(host, run, input = {}) {
671
+ const requested = new Set(input.sources ?? ["memory", "history", "connections"]);
672
+ const limit = positiveLimit(input.limit, 50);
673
+ const resources = [];
674
+ const sections = [];
675
+ if (requested.has("memory")) {
676
+ const documents = await host.memoryStore.list(host.memoryScopeForRun(run), { limit });
677
+ resources.push(...documents.map((document) => memoryDocumentSummary(document)));
678
+ if (documents.length > 0) {
679
+ sections.push([
680
+ "# Memory",
681
+ ...documents.map((document) => [
682
+ `## ${document.path}`,
683
+ memoryBodyText(document)
684
+ ].join("\n"))
685
+ ].join("\n\n"));
686
+ }
687
+ }
688
+ if (requested.has("history")) {
689
+ const conversationId = typeof run.input.conversationId === "string" ? run.input.conversationId : undefined;
690
+ const messages = conversationId ? await host.state.listRecentMessages(conversationId, limit) : [];
691
+ resources.push(...messages.map((message) => ({
692
+ kind: "history",
693
+ role: message.role,
694
+ createdAt: message.createdAt,
695
+ runId: message.runId ?? null
696
+ })));
697
+ if (messages.length > 0) {
698
+ sections.push([
699
+ "# History",
700
+ ...messages.map((message) => {
701
+ const text = typeof message.content.text === "string" ? message.content.text : JSON.stringify(message.content);
702
+ return `- ${message.role}: ${text}`;
703
+ })
704
+ ].join("\n"));
705
+ }
706
+ }
707
+ if (requested.has("connections")) {
708
+ const connections = host.mergedConnections().slice(0, limit);
709
+ resources.push(...connections.map((connection) => ({
710
+ kind: "connection",
711
+ name: connection.name,
712
+ protocol: connection.protocol,
713
+ provider: connection.provider,
714
+ required: connection.required
715
+ })));
716
+ if (connections.length > 0) {
717
+ sections.push([
718
+ "# Connections",
719
+ ...connections.map((connection) => `- ${connection.name} (${connection.protocol}, ${connection.provider})`)
720
+ ].join("\n"));
721
+ }
722
+ }
723
+ if (requested.has("skills")) {
724
+ const skills = (await host.skillStore.list(host.skillScope())).filter((skill) => !skill.pending).slice(0, limit);
725
+ resources.push(...skills.map((skill) => ({
726
+ kind: "skill",
727
+ name: skill.name,
728
+ origin: skill.origin,
729
+ updatedAt: skill.updatedAt
730
+ })));
731
+ if (skills.length > 0) {
732
+ sections.push([
733
+ "# Skills",
734
+ ...skills.map((skill) => `- ${skill.name} (${skill.origin})`)
735
+ ].join("\n"));
736
+ }
737
+ }
738
+ await host.state.appendEvent(run.id, "trigger.resources_collected", {
739
+ sources: [...requested],
740
+ count: resources.length,
741
+ since: input.since ?? null
742
+ });
743
+ return {
744
+ markdown: sections.join("\n\n").trim(),
745
+ resources
746
+ };
747
+ }
748
+ /**
749
+ * Dispatch application-managed dynamic schedules: atomically lease due rows
750
+ * and start one durable run per row. At-least-once; tasks should be idempotent.
751
+ */
752
+ async function runDueDynamicSchedules(host, now) {
753
+ if (!host.schedulesConfig.dynamic)
754
+ return [];
755
+ const results = [];
756
+ const due = await host.scheduleStore.claimDue({ now, limit: 25, leaseForMs: 5 * 60_000 });
757
+ for (const job of due) {
758
+ const dueAtIso = job.nextRunAt;
759
+ const idempotencyKey = `dynamic:${job.id}:${dueAtIso}`;
760
+ const leaseToken = job.leaseToken ?? "";
761
+ try {
762
+ // openeve_schedule_runs rows reference openeve_schedules; dynamic jobs
763
+ // live in the schedule store, so upsert a parent row before recording runs.
764
+ await host.state.registerSchedule({
765
+ id: `dynamic:${job.id}`,
766
+ name: `dynamic:${job.id}`,
767
+ cron: job.cron ?? (job.everyMinutes ? `@every ${job.everyMinutes}m` : `@at ${dueAtIso}`),
768
+ ...(job.timezone ? { timezone: job.timezone } : {}),
769
+ metadata: { source: "dynamic", scope: job.scope }
770
+ });
771
+ const schedule = dynamicScheduleExecution(host, job, dueAtIso, idempotencyKey);
772
+ const result = await runScheduleExecution(host, schedule);
773
+ await host.scheduleStore.complete(job.id, leaseToken, { ranAt: dueAtIso });
774
+ if (result.runId) {
775
+ await host.state.appendEvent(result.runId, "schedule.dynamic_dispatched", {
776
+ dynamicScheduleId: job.id,
777
+ dueAt: dueAtIso,
778
+ trigger: job.trigger ? safeJson(job.trigger) : null
779
+ });
780
+ }
781
+ results.push(result);
782
+ }
783
+ catch (error) {
784
+ const message = error instanceof Error ? error.message : String(error);
785
+ try {
786
+ await host.state.recordScheduleRun({
787
+ scheduleId: `dynamic:${job.id}`,
788
+ runAt: dueAtIso,
789
+ idempotencyKey,
790
+ status: "failed"
791
+ });
792
+ }
793
+ catch (recordError) {
794
+ host.logger.warn("dynamic schedule failure bookkeeping failed", {
795
+ dynamicScheduleId: job.id,
796
+ error: recordError instanceof Error ? recordError.message : String(recordError)
797
+ });
798
+ }
799
+ // Escalating backoff on the failure streak (5min base, 2x, capped 6h);
800
+ // the store disables the schedule atomically once the streak hits the
801
+ // cap so a poison schedule cannot burn a model run every cycle forever.
802
+ const failureStreak = (job.consecutiveFailures ?? 0) + 1;
803
+ const retryDelayMs = Math.min(300_000 * 2 ** (failureStreak - 1), 6 * 3_600_000);
804
+ const disabled = failureStreak >= host.scheduleMaxConsecutiveFailures;
805
+ await host.scheduleStore.release(job.id, leaseToken, new Date(now.getTime() + retryDelayMs), {
806
+ maxConsecutiveFailures: host.scheduleMaxConsecutiveFailures
807
+ });
808
+ if (disabled) {
809
+ host.logger.warn("dynamic schedule disabled after consecutive failures", {
810
+ dynamicScheduleId: job.id,
811
+ scope: job.scope,
812
+ consecutiveFailures: failureStreak,
813
+ error: message
814
+ });
815
+ if (isRuntimeSettingsStore(host.state)) {
816
+ await host.state.appendRuntimeControlEvent(job.scope, "schedule.disabled_after_failures", {
817
+ dynamicScheduleId: job.id,
818
+ consecutiveFailures: failureStreak,
819
+ error: message
820
+ }).catch(() => undefined);
821
+ }
822
+ }
823
+ results.push({ schedule: `dynamic:${job.id}`, dueAt: dueAtIso, idempotencyKey, status: "failed", error: message });
824
+ }
825
+ }
826
+ return results;
827
+ }
828
+ function dynamicScheduleExecution(host, job, dueAtIso, idempotencyKey) {
829
+ const target = isJsonObject(job.target) ? job.target : {};
830
+ const targetConversation = typeof target.conversationId === "string" ? target.conversationId : undefined;
831
+ const targetProject = typeof target.projectId === "string" ? target.projectId : undefined;
832
+ const conversationId = job.conversationId ?? targetConversation;
833
+ const projectId = job.projectId ?? targetProject;
834
+ const delivery = isJsonObject(job.target) ? job.target : undefined;
835
+ const message = dynamicScheduleMessage(job);
836
+ const trigger = job.trigger ? normalizeScheduleTriggerDefinitionImpl(host, job.trigger) : undefined;
837
+ const metadata = {
838
+ ...(job.metadata ?? {}),
839
+ dynamicScheduleId: job.id,
840
+ scope: job.scope,
841
+ source: "dynamic",
842
+ schedule: `dynamic:${job.id}`,
843
+ dueAt: dueAtIso,
844
+ idempotencyKey
845
+ };
846
+ if (job.target)
847
+ metadata.target = safeJson(job.target);
848
+ const definition = { ...job };
849
+ if (trigger)
850
+ definition.trigger = trigger;
851
+ return {
852
+ source: "dynamic",
853
+ scheduleId: job.id,
854
+ resultSchedule: `dynamic:${job.id}`,
855
+ dueAtIso,
856
+ idempotencyKey,
857
+ message,
858
+ channel: job.channel,
859
+ ...(trigger ? { trigger } : {}),
860
+ metadata,
861
+ definition: safeJson(definition),
862
+ ...(job.userId ? { userId: job.userId } : {}),
863
+ ...(conversationId ? { conversationId } : {}),
864
+ ...(projectId ? { projectId } : {}),
865
+ ...(delivery ? { delivery } : {})
866
+ };
867
+ }
868
+ export async function startSchedulerPollingLoopImpl(host) {
869
+ if (!hasScheduledWork(host))
870
+ return undefined;
871
+ await registerManifestSchedulesImpl(host);
872
+ let inFlight = false;
873
+ const tick = async () => {
874
+ if (inFlight)
875
+ return [];
876
+ inFlight = true;
877
+ try {
878
+ return await runDueSchedulesImpl(host, { now: host.now(), lookbackMs: host.schedulerTickMs });
879
+ }
880
+ catch (error) {
881
+ // The interval invokes tick as a floating promise; a throw here would
882
+ // become an unhandled rejection and take down the whole process.
883
+ host.logger.error("scheduler tick failed", {
884
+ error: error instanceof Error ? error.message : String(error)
885
+ });
886
+ return [];
887
+ }
888
+ finally {
889
+ inFlight = false;
890
+ }
891
+ };
892
+ const timer = setInterval(() => {
893
+ void tick();
894
+ }, host.schedulerTickMs);
895
+ timer.unref?.();
896
+ void tick();
897
+ return {
898
+ stop() {
899
+ clearInterval(timer);
900
+ },
901
+ tick
902
+ };
903
+ }
904
+ function hasScheduledWork(host) {
905
+ if (host.schedulesConfig.dynamic)
906
+ return true;
907
+ return manifestScheduleRegistrations(host).length > 0;
908
+ }
909
+ function compiledSchedule(host, name) {
910
+ return host.manifest.automations?.find((automation) => automation.name === name)
911
+ ?? host.manifest.schedules.find((schedule) => schedule.name === name);
912
+ }
913
+ function scheduleMessage(host, name) {
914
+ const registration = manifestScheduleRegistrations(host).find((schedule) => schedule.schedule === name);
915
+ const compiled = compiledSchedule(host, name);
916
+ return registration?.message ?? compiled?.message ?? compiled?.description ?? `Run schedule ${name}.`;
917
+ }
918
+ function automationHandlers(host) {
919
+ return host.manifest.automationHandlers?.length
920
+ ? host.manifest.automationHandlers
921
+ : host.manifest.triggerHandlers ?? [];
922
+ }
923
+ function manifestScheduleRegistrations(host) {
924
+ if (Array.isArray(host.manifest.automationRegistrations)) {
925
+ return host.manifest.automationRegistrations.flatMap((automation) => {
926
+ if (automation.trigger.type !== "schedule")
927
+ return [];
928
+ const registration = {
929
+ schedule: automation.automation,
930
+ cron: automation.trigger.cron,
931
+ idempotencyKey: automation.idempotencyKey
932
+ };
933
+ if (automation.trigger.timezone)
934
+ registration.timezone = automation.trigger.timezone;
935
+ if (automation.message)
936
+ registration.message = automation.message;
937
+ if (automation.target)
938
+ registration.target = automation.target;
939
+ if (automation.lifecycle) {
940
+ registration.trigger = {
941
+ handler: automation.lifecycle.handler,
942
+ ...(automation.target ? { target: automation.target } : {}),
943
+ ...(automation.metadata ? { metadata: automation.metadata } : {})
944
+ };
945
+ }
946
+ return [registration];
947
+ });
948
+ }
949
+ return host.manifest.scheduleRegistrations ?? [];
950
+ }
951
+ //# sourceMappingURL=schedule-execution.js.map