@minpeter/pss-runtime 0.1.0-next.2 → 0.1.0-next.4

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 (145) hide show
  1. package/README.md +172 -85
  2. package/dist/agent-host-session-store.js +2 -4
  3. package/dist/agent-host-session-store.js.map +1 -1
  4. package/dist/agent-loop.js +9 -8
  5. package/dist/agent-loop.js.map +1 -1
  6. package/dist/agent-namespace.js +3 -7
  7. package/dist/agent-namespace.js.map +1 -1
  8. package/dist/agent-options.d.ts +4 -19
  9. package/dist/agent-options.js +2 -8
  10. package/dist/agent-options.js.map +1 -1
  11. package/dist/agent-resume.js +2 -82
  12. package/dist/agent-resume.js.map +1 -1
  13. package/dist/agent-session-entry.d.ts +1 -1
  14. package/dist/agent.d.ts +4 -4
  15. package/dist/agent.js +19 -89
  16. package/dist/agent.js.map +1 -1
  17. package/dist/cloudflare/cloudflare-agent-context.d.ts +40 -0
  18. package/dist/cloudflare/cloudflare-agent-context.js +37 -0
  19. package/dist/cloudflare/cloudflare-agent-context.js.map +1 -0
  20. package/dist/cloudflare/cloudflare-alarm-budget.d.ts +18 -0
  21. package/dist/cloudflare/cloudflare-alarm-budget.js +77 -0
  22. package/dist/cloudflare/cloudflare-alarm-budget.js.map +1 -0
  23. package/dist/cloudflare/cloudflare-alarm-drainer.d.ts +45 -0
  24. package/dist/cloudflare/cloudflare-alarm-drainer.js +103 -0
  25. package/dist/cloudflare/cloudflare-alarm-drainer.js.map +1 -0
  26. package/dist/cloudflare/cloudflare-alarm-run-drain.d.ts +13 -0
  27. package/dist/cloudflare/cloudflare-alarm-run-drain.js +81 -0
  28. package/dist/cloudflare/cloudflare-alarm-run-drain.js.map +1 -0
  29. package/dist/cloudflare/cloudflare-alarm-work.js +110 -0
  30. package/dist/cloudflare/cloudflare-alarm-work.js.map +1 -0
  31. package/dist/cloudflare/cloudflare-checkpoint-store.js +39 -0
  32. package/dist/cloudflare/cloudflare-checkpoint-store.js.map +1 -0
  33. package/dist/cloudflare/cloudflare-durable-object-fetch.d.ts +21 -0
  34. package/dist/cloudflare/cloudflare-durable-object-fetch.js +11 -0
  35. package/dist/cloudflare/cloudflare-durable-object-fetch.js.map +1 -0
  36. package/dist/cloudflare/cloudflare-event-store.js +33 -0
  37. package/dist/cloudflare/cloudflare-event-store.js.map +1 -0
  38. package/dist/cloudflare/cloudflare-execution-session-store.js +40 -0
  39. package/dist/cloudflare/cloudflare-execution-session-store.js.map +1 -0
  40. package/dist/cloudflare/cloudflare-execution-store.js +35 -0
  41. package/dist/cloudflare/cloudflare-execution-store.js.map +1 -0
  42. package/dist/cloudflare/cloudflare-host.d.ts +61 -0
  43. package/dist/cloudflare/cloudflare-host.js +113 -0
  44. package/dist/cloudflare/cloudflare-host.js.map +1 -0
  45. package/dist/cloudflare/cloudflare-notification-store.js +59 -0
  46. package/dist/cloudflare/cloudflare-notification-store.js.map +1 -0
  47. package/dist/cloudflare/cloudflare-run-store.js +81 -0
  48. package/dist/cloudflare/cloudflare-run-store.js.map +1 -0
  49. package/dist/cloudflare/cloudflare-store-utils.js +43 -0
  50. package/dist/cloudflare/cloudflare-store-utils.js.map +1 -0
  51. package/dist/cloudflare/durable-object-storage.d.ts +20 -0
  52. package/dist/cloudflare/durable-object-storage.js +76 -0
  53. package/dist/cloudflare/durable-object-storage.js.map +1 -0
  54. package/dist/cloudflare/index.d.ts +7 -0
  55. package/dist/cloudflare/index.js +6 -0
  56. package/dist/execution/capabilities.d.ts +40 -0
  57. package/dist/execution/host.d.ts +9 -0
  58. package/dist/execution/host.js +49 -1
  59. package/dist/execution/host.js.map +1 -1
  60. package/dist/execution/index.d.ts +3 -1
  61. package/dist/execution/index.js +2 -1
  62. package/dist/execution/memory.js +1 -1
  63. package/dist/execution/memory.js.map +1 -1
  64. package/dist/execution/types.d.ts +5 -10
  65. package/dist/index.d.ts +9 -5
  66. package/dist/index.js +6 -2
  67. package/dist/llm-tool-execution.js.map +1 -1
  68. package/dist/llm.d.ts +1 -21
  69. package/dist/llm.js +12 -14
  70. package/dist/llm.js.map +1 -1
  71. package/dist/plugins.d.ts +27 -5
  72. package/dist/plugins.js +35 -6
  73. package/dist/plugins.js.map +1 -1
  74. package/dist/session/delegate-input.d.ts +9 -0
  75. package/dist/session/delegate-input.js +16 -0
  76. package/dist/session/delegate-input.js.map +1 -0
  77. package/dist/session/events.d.ts +43 -25
  78. package/dist/session/events.js +41 -0
  79. package/dist/session/events.js.map +1 -0
  80. package/dist/session/input-meta-types.d.ts +10 -0
  81. package/dist/session/input-meta.d.ts +13 -0
  82. package/dist/session/input-meta.js +45 -0
  83. package/dist/session/input-meta.js.map +1 -0
  84. package/dist/session/input.d.ts +4 -0
  85. package/dist/session/mapping.js +4 -2
  86. package/dist/session/mapping.js.map +1 -1
  87. package/dist/session/runtime-input-emit.js +41 -0
  88. package/dist/session/runtime-input-emit.js.map +1 -0
  89. package/dist/session/runtime-input.js +5 -1
  90. package/dist/session/runtime-input.js.map +1 -1
  91. package/dist/session/session-events.js +20 -6
  92. package/dist/session/session-events.js.map +1 -1
  93. package/dist/session/session-notification.js +3 -2
  94. package/dist/session/session-notification.js.map +1 -1
  95. package/dist/session/session-runtime-drain.js +3 -9
  96. package/dist/session/session-runtime-drain.js.map +1 -1
  97. package/dist/session/session-turn-processor.js +10 -20
  98. package/dist/session/session-turn-processor.js.map +1 -1
  99. package/dist/session/session.js +15 -8
  100. package/dist/session/session.js.map +1 -1
  101. package/package.json +6 -1
  102. package/dist/agent-child-runs.js +0 -16
  103. package/dist/agent-child-runs.js.map +0 -1
  104. package/dist/agent-host-capabilities.js +0 -9
  105. package/dist/agent-host-capabilities.js.map +0 -1
  106. package/dist/agent-validation.js +0 -35
  107. package/dist/agent-validation.js.map +0 -1
  108. package/dist/child-session-cleanups.js +0 -61
  109. package/dist/child-session-cleanups.js.map +0 -1
  110. package/dist/execution/run.js +0 -55
  111. package/dist/execution/run.js.map +0 -1
  112. package/dist/subagent-background-child-run-state.js +0 -51
  113. package/dist/subagent-background-child-run-state.js.map +0 -1
  114. package/dist/subagent-background-child-run.js +0 -103
  115. package/dist/subagent-background-child-run.js.map +0 -1
  116. package/dist/subagent-background-in-process.js +0 -98
  117. package/dist/subagent-background-in-process.js.map +0 -1
  118. package/dist/subagent-background-notification-inbox.js +0 -106
  119. package/dist/subagent-background-notification-inbox.js.map +0 -1
  120. package/dist/subagent-background-notify.js +0 -136
  121. package/dist/subagent-background-notify.js.map +0 -1
  122. package/dist/subagent-background-resume-group.js +0 -99
  123. package/dist/subagent-background-resume-group.js.map +0 -1
  124. package/dist/subagent-background-runner.js +0 -115
  125. package/dist/subagent-background-runner.js.map +0 -1
  126. package/dist/subagent-background-schedule.js +0 -43
  127. package/dist/subagent-background-schedule.js.map +0 -1
  128. package/dist/subagent-child-run.js +0 -68
  129. package/dist/subagent-child-run.js.map +0 -1
  130. package/dist/subagent-job-cancel.js +0 -84
  131. package/dist/subagent-job-cancel.js.map +0 -1
  132. package/dist/subagent-job-observer.js +0 -19
  133. package/dist/subagent-job-observer.js.map +0 -1
  134. package/dist/subagent-job-output.js +0 -87
  135. package/dist/subagent-job-output.js.map +0 -1
  136. package/dist/subagent-job-state.js +0 -66
  137. package/dist/subagent-job-state.js.map +0 -1
  138. package/dist/subagent-jobs.js +0 -96
  139. package/dist/subagent-jobs.js.map +0 -1
  140. package/dist/subagent-prompt-schema.js +0 -114
  141. package/dist/subagent-prompt-schema.js.map +0 -1
  142. package/dist/subagent-run.js +0 -111
  143. package/dist/subagent-run.js.map +0 -1
  144. package/dist/subagents.js +0 -125
  145. package/dist/subagents.js.map +0 -1
@@ -1,20 +1,9 @@
1
- import { readDurableBackgroundChildRunState } from "./subagent-background-child-run-state.js";
2
1
  import { ownsAgentNamespace } from "./agent-namespace.js";
3
- import { StoredAgentRun } from "./execution/run.js";
4
- import { BufferedAgentRun } from "./session/run.js";
5
- import { buildDurableResumeGroups } from "./subagent-background-resume-group.js";
6
- import { runBackgroundJob } from "./subagent-background-runner.js";
7
2
  //#region src/agent-resume.ts
8
- const defaultResumeLeaseMs = 3e5;
9
- async function resumeAgentRun({ host, ownerNamespace, resumeNotification, runId, subagents }) {
3
+ async function resumeAgentRun({ host, ownerNamespace, resumeNotification, runId }) {
10
4
  const run = await host.store.runs.get(runId);
11
5
  if (!run) return null;
12
6
  if (!canAccessRun(run, ownerNamespace)) return null;
13
- if (run.kind === "background-subagent") return await resumeBackgroundSubagentRun({
14
- host,
15
- run,
16
- subagents
17
- });
18
7
  if (run.kind === "notification" && run.dedupeKey) {
19
8
  const idempotencyKey = run.dedupeKey;
20
9
  const claimed = await claimRun(host, run);
@@ -59,84 +48,15 @@ async function completeNotificationRun(host, runId) {
59
48
  status: "completed"
60
49
  });
61
50
  }
62
- async function resumeBackgroundSubagentRun({ host, run, subagents }) {
63
- const claimed = await claimRun(host, run);
64
- if (!claimed) return null;
65
- const state = readDurableBackgroundChildRunState(await host.store.checkpoints.latest(run.runId));
66
- if (!state) throw new AgentResumeError(run.runId, "missing background run state");
67
- const subagent = subagents.find((candidate) => candidate.name === state.subagent);
68
- if (!subagent) throw new AgentResumeError(run.runId, `missing subagent ${JSON.stringify(state.subagent)}`);
69
- const childSession = subagent.session(claimed.sessionKey);
70
- const job = {
71
- abort: () => childSession.interrupt(),
72
- childRunId: claimed.runId,
73
- childRunLeaseId: claimed.lease?.leaseId,
74
- cleanup: () => Promise.resolve(),
75
- dedupeKey: claimed.dedupeKey,
76
- delegateToolCallId: state.delegateToolCallId,
77
- description: state.description,
78
- executionHost: host,
79
- groupId: state.groupId,
80
- id: claimed.publicTaskId ?? claimed.runId,
81
- ownerNamespace: claimed.ownerNamespace,
82
- parentRunId: claimed.parentRunId,
83
- parentSessionKey: state.parentSessionKey,
84
- promise: Promise.resolve(),
85
- sessionKey: claimed.sessionKey,
86
- settled: false,
87
- status: "running",
88
- subagent: state.subagent
89
- };
90
- const jobs = new Map([[job.id, job]]);
91
- job.promise = runBackgroundJob({
92
- childSession,
93
- groups: await buildDurableResumeGroups({
94
- currentJob: job,
95
- host,
96
- run: claimed,
97
- state,
98
- jobs
99
- }),
100
- jobs,
101
- job,
102
- parentSession: durableParentSession(host, run.runId),
103
- prompt: state.prompt
104
- }).finally(() => {
105
- job.settled = true;
106
- });
107
- await job.promise;
108
- return new StoredAgentRun({
109
- eventStore: host.store.events,
110
- runId: run.runId
111
- });
112
- }
113
51
  async function claimRun(host, run) {
114
52
  const claim = await host.store.runs.claim(run.runId, {
115
53
  attempt: (run.lease?.attempt ?? 0) + 1,
116
54
  leaseId: crypto.randomUUID(),
117
- leaseMs: defaultResumeLeaseMs,
55
+ leaseMs: 3e5,
118
56
  nowMs: Date.now()
119
57
  });
120
58
  return claim.ok ? claim.record : null;
121
59
  }
122
- function durableParentSession(host, runId) {
123
- return {
124
- emitObserverEvent: (event) => host.store.events.append(runId, event).then(),
125
- enqueueRuntimeInput: () => void 0,
126
- notify: () => Promise.resolve(emptyRun())
127
- };
128
- }
129
- function emptyRun() {
130
- const run = new BufferedAgentRun();
131
- run.close();
132
- return run;
133
- }
134
- var AgentResumeError = class extends Error {
135
- constructor(runId, reason) {
136
- super(`Cannot resume agent run ${runId}: ${reason}`);
137
- this.name = "AgentResumeError";
138
- }
139
- };
140
60
  //#endregion
141
61
  export { resumeAgentRun };
142
62
 
@@ -1 +1 @@
1
- {"version":3,"file":"agent-resume.js","names":[],"sources":["../src/agent-resume.ts"],"sourcesContent":["import { ownsAgentNamespace } from \"./agent-namespace\";\nimport { StoredAgentRun } from \"./execution/run\";\nimport type {\n ExecutionHost,\n NotificationRecord,\n RunRecord,\n} from \"./execution/types\";\nimport { type AgentRun, BufferedAgentRun } from \"./session/run\";\nimport { readDurableBackgroundChildRunState } from \"./subagent-background-child-run-state\";\nimport { buildDurableResumeGroups } from \"./subagent-background-resume-group\";\nimport { runBackgroundJob } from \"./subagent-background-runner\";\nimport type { RuntimeInputSink, Subagent, SubagentJob } from \"./subagent-types\";\n\nconst defaultResumeLeaseMs = 300_000;\n\ninterface ResumeAgentRunInput {\n readonly host: ExecutionHost;\n readonly ownerNamespace: string;\n resumeNotification(notification: NotificationRecord): Promise<AgentRun>;\n readonly runId: string;\n readonly subagents: readonly Subagent[];\n}\n\nexport async function resumeAgentRun({\n host,\n ownerNamespace,\n resumeNotification,\n runId,\n subagents,\n}: ResumeAgentRunInput): Promise<AgentRun | null> {\n const run = await host.store.runs.get(runId);\n if (!run) {\n return null;\n }\n if (!canAccessRun(run, ownerNamespace)) {\n return null;\n }\n\n if (run.kind === \"background-subagent\") {\n return await resumeBackgroundSubagentRun({ host, run, subagents });\n }\n\n if (run.kind === \"notification\" && run.dedupeKey) {\n const idempotencyKey = run.dedupeKey;\n const claimed = await claimRun(host, run);\n if (!claimed) {\n return null;\n }\n\n const notification = await claimNotificationForRun({\n host,\n idempotencyKey,\n ownerNamespace,\n });\n if (!notification) {\n return null;\n }\n\n try {\n const notificationRun = await resumeNotification(notification);\n await completeNotificationRun(host, claimed.runId);\n return notificationRun;\n } catch (error) {\n await host.store.notifications.releaseByIdempotencyKey(idempotencyKey);\n throw error;\n }\n }\n\n return null;\n}\n\nasync function claimNotificationForRun({\n host,\n idempotencyKey,\n ownerNamespace,\n}: {\n readonly host: ExecutionHost;\n readonly idempotencyKey: string;\n readonly ownerNamespace: string;\n}): Promise<NotificationRecord | null> {\n const current =\n await host.store.notifications.getByIdempotencyKey(idempotencyKey);\n if (!ownsAgentNamespace(current?.ownerNamespace, ownerNamespace)) {\n return null;\n }\n\n const claim =\n await host.store.notifications.claimByIdempotencyKey(idempotencyKey);\n if (claim.ok) {\n if (ownsAgentNamespace(claim.record.ownerNamespace, ownerNamespace)) {\n return claim.record;\n }\n await host.store.notifications.releaseByIdempotencyKey(idempotencyKey);\n return null;\n }\n\n if (\n claim.reason === \"already-claimed\" &&\n ownsAgentNamespace(claim.record?.ownerNamespace, ownerNamespace)\n ) {\n return claim.record ?? null;\n }\n\n return null;\n}\n\nfunction canAccessRun(run: RunRecord, ownerNamespace: string): boolean {\n if (run.ownerNamespace) {\n return ownsAgentNamespace(run.ownerNamespace, ownerNamespace);\n }\n\n return (\n run.sessionKey.startsWith(`parent:${ownerNamespace}:`) ||\n run.parentRunId?.startsWith(`${ownerNamespace}:session:`) === true\n );\n}\n\nexport async function completeNotificationRun(\n host: ExecutionHost,\n runId: string\n): Promise<void> {\n const run = await host.store.runs.get(runId);\n if (run?.kind !== \"notification\" || run.status === \"completed\") {\n return;\n }\n\n await host.store.runs.update({ ...run, status: \"completed\" });\n}\n\nasync function resumeBackgroundSubagentRun({\n host,\n run,\n subagents,\n}: {\n readonly host: ExecutionHost;\n readonly run: RunRecord;\n readonly subagents: readonly Subagent[];\n}): Promise<AgentRun | null> {\n const claimed = await claimRun(host, run);\n if (!claimed) {\n return null;\n }\n\n const checkpoint = await host.store.checkpoints.latest(run.runId);\n const state = readDurableBackgroundChildRunState(checkpoint);\n if (!state) {\n throw new AgentResumeError(run.runId, \"missing background run state\");\n }\n\n const subagent = subagents.find(\n (candidate) => candidate.name === state.subagent\n );\n if (!subagent) {\n throw new AgentResumeError(\n run.runId,\n `missing subagent ${JSON.stringify(state.subagent)}`\n );\n }\n\n const childSession = subagent.session(claimed.sessionKey);\n const job: SubagentJob = {\n abort: () => childSession.interrupt(),\n childRunId: claimed.runId,\n childRunLeaseId: claimed.lease?.leaseId,\n cleanup: () => Promise.resolve(),\n dedupeKey: claimed.dedupeKey,\n delegateToolCallId: state.delegateToolCallId,\n description: state.description,\n executionHost: host,\n groupId: state.groupId,\n id: claimed.publicTaskId ?? claimed.runId,\n ownerNamespace: claimed.ownerNamespace,\n parentRunId: claimed.parentRunId,\n parentSessionKey: state.parentSessionKey,\n promise: Promise.resolve(),\n sessionKey: claimed.sessionKey,\n settled: false,\n status: \"running\",\n subagent: state.subagent,\n };\n const jobs = new Map([[job.id, job]]);\n const groups = await buildDurableResumeGroups({\n currentJob: job,\n host,\n run: claimed,\n state,\n jobs,\n });\n const parentSession = durableParentSession(host, run.runId);\n\n job.promise = runBackgroundJob({\n childSession,\n groups,\n jobs,\n job,\n parentSession,\n prompt: state.prompt,\n }).finally(() => {\n job.settled = true;\n });\n await job.promise;\n\n return new StoredAgentRun({\n eventStore: host.store.events,\n runId: run.runId,\n });\n}\n\nasync function claimRun(\n host: ExecutionHost,\n run: RunRecord\n): Promise<RunRecord | null> {\n const claim = await host.store.runs.claim(run.runId, {\n attempt: (run.lease?.attempt ?? 0) + 1,\n leaseId: crypto.randomUUID(),\n leaseMs: defaultResumeLeaseMs,\n nowMs: Date.now(),\n });\n return claim.ok ? claim.record : null;\n}\n\nfunction durableParentSession(\n host: ExecutionHost,\n runId: string\n): RuntimeInputSink {\n return {\n emitObserverEvent: (event) => host.store.events.append(runId, event).then(),\n enqueueRuntimeInput: () => undefined,\n notify: () => Promise.resolve(emptyRun()),\n };\n}\n\nfunction emptyRun(): AgentRun {\n const run = new BufferedAgentRun();\n run.close();\n return run;\n}\n\nclass AgentResumeError extends Error {\n constructor(runId: string, reason: string) {\n super(`Cannot resume agent run ${runId}: ${reason}`);\n this.name = \"AgentResumeError\";\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-resume.js","names":[],"sources":["../src/agent-resume.ts"],"sourcesContent":["import { ownsAgentNamespace } from \"./agent-namespace\";\nimport type {\n ExecutionHost,\n NotificationRecord,\n RunRecord,\n} from \"./execution/types\";\nimport type { AgentRun } from \"./session/run\";\n\ninterface ResumeAgentRunInput {\n readonly host: ExecutionHost;\n readonly ownerNamespace: string;\n resumeNotification(notification: NotificationRecord): Promise<AgentRun>;\n readonly runId: string;\n}\n\nexport async function resumeAgentRun({\n host,\n ownerNamespace,\n resumeNotification,\n runId,\n}: ResumeAgentRunInput): Promise<AgentRun | null> {\n const run = await host.store.runs.get(runId);\n if (!run) {\n return null;\n }\n if (!canAccessRun(run, ownerNamespace)) {\n return null;\n }\n\n if (run.kind === \"notification\" && run.dedupeKey) {\n const idempotencyKey = run.dedupeKey;\n const claimed = await claimRun(host, run);\n if (!claimed) {\n return null;\n }\n\n const notification = await claimNotificationForRun({\n host,\n idempotencyKey,\n ownerNamespace,\n });\n if (!notification) {\n return null;\n }\n\n try {\n const notificationRun = await resumeNotification(notification);\n await completeNotificationRun(host, claimed.runId);\n return notificationRun;\n } catch (error) {\n await host.store.notifications.releaseByIdempotencyKey(idempotencyKey);\n throw error;\n }\n }\n\n return null;\n}\n\nasync function claimNotificationForRun({\n host,\n idempotencyKey,\n ownerNamespace,\n}: {\n readonly host: ExecutionHost;\n readonly idempotencyKey: string;\n readonly ownerNamespace: string;\n}): Promise<NotificationRecord | null> {\n const current =\n await host.store.notifications.getByIdempotencyKey(idempotencyKey);\n if (!ownsAgentNamespace(current?.ownerNamespace, ownerNamespace)) {\n return null;\n }\n\n const claim =\n await host.store.notifications.claimByIdempotencyKey(idempotencyKey);\n if (claim.ok) {\n if (ownsAgentNamespace(claim.record.ownerNamespace, ownerNamespace)) {\n return claim.record;\n }\n await host.store.notifications.releaseByIdempotencyKey(idempotencyKey);\n return null;\n }\n\n if (\n claim.reason === \"already-claimed\" &&\n ownsAgentNamespace(claim.record?.ownerNamespace, ownerNamespace)\n ) {\n return claim.record ?? null;\n }\n\n return null;\n}\n\nfunction canAccessRun(run: RunRecord, ownerNamespace: string): boolean {\n if (run.ownerNamespace) {\n return ownsAgentNamespace(run.ownerNamespace, ownerNamespace);\n }\n\n return (\n run.sessionKey.startsWith(`parent:${ownerNamespace}:`) ||\n run.parentRunId?.startsWith(`${ownerNamespace}:session:`) === true\n );\n}\n\nexport async function completeNotificationRun(\n host: ExecutionHost,\n runId: string\n): Promise<void> {\n const run = await host.store.runs.get(runId);\n if (run?.kind !== \"notification\" || run.status === \"completed\") {\n return;\n }\n\n await host.store.runs.update({ ...run, status: \"completed\" });\n}\n\nasync function claimRun(\n host: ExecutionHost,\n run: RunRecord\n): Promise<RunRecord | null> {\n const claim = await host.store.runs.claim(run.runId, {\n attempt: (run.lease?.attempt ?? 0) + 1,\n leaseId: crypto.randomUUID(),\n leaseMs: 300_000,\n nowMs: Date.now(),\n });\n return claim.ok ? claim.record : null;\n}\n"],"mappings":";;AAeA,eAAsB,eAAe,EACnC,MACA,gBACA,oBACA,SACgD;CAChD,MAAM,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,KAAK;CAC3C,IAAI,CAAC,KACH,OAAO;CAET,IAAI,CAAC,aAAa,KAAK,cAAc,GACnC,OAAO;CAGT,IAAI,IAAI,SAAS,kBAAkB,IAAI,WAAW;EAChD,MAAM,iBAAiB,IAAI;EAC3B,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG;EACxC,IAAI,CAAC,SACH,OAAO;EAGT,MAAM,eAAe,MAAM,wBAAwB;GACjD;GACA;GACA;EACF,CAAC;EACD,IAAI,CAAC,cACH,OAAO;EAGT,IAAI;GACF,MAAM,kBAAkB,MAAM,mBAAmB,YAAY;GAC7D,MAAM,wBAAwB,MAAM,QAAQ,KAAK;GACjD,OAAO;EACT,SAAS,OAAO;GACd,MAAM,KAAK,MAAM,cAAc,wBAAwB,cAAc;GACrE,MAAM;EACR;CACF;CAEA,OAAO;AACT;AAEA,eAAe,wBAAwB,EACrC,MACA,gBACA,kBAKqC;CAGrC,IAAI,CAAC,oBAAmB,MADhB,KAAK,MAAM,cAAc,oBAAoB,cAAc,IAClC,gBAAgB,cAAc,GAC7D,OAAO;CAGT,MAAM,QACJ,MAAM,KAAK,MAAM,cAAc,sBAAsB,cAAc;CACrE,IAAI,MAAM,IAAI;EACZ,IAAI,mBAAmB,MAAM,OAAO,gBAAgB,cAAc,GAChE,OAAO,MAAM;EAEf,MAAM,KAAK,MAAM,cAAc,wBAAwB,cAAc;EACrE,OAAO;CACT;CAEA,IACE,MAAM,WAAW,qBACjB,mBAAmB,MAAM,QAAQ,gBAAgB,cAAc,GAE/D,OAAO,MAAM,UAAU;CAGzB,OAAO;AACT;AAEA,SAAS,aAAa,KAAgB,gBAAiC;CACrE,IAAI,IAAI,gBACN,OAAO,mBAAmB,IAAI,gBAAgB,cAAc;CAG9D,OACE,IAAI,WAAW,WAAW,UAAU,eAAe,EAAE,KACrD,IAAI,aAAa,WAAW,GAAG,eAAe,UAAU,MAAM;AAElE;AAEA,eAAsB,wBACpB,MACA,OACe;CACf,MAAM,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,KAAK;CAC3C,IAAI,KAAK,SAAS,kBAAkB,IAAI,WAAW,aACjD;CAGF,MAAM,KAAK,MAAM,KAAK,OAAO;EAAE,GAAG;EAAK,QAAQ;CAAY,CAAC;AAC9D;AAEA,eAAe,SACb,MACA,KAC2B;CAC3B,MAAM,QAAQ,MAAM,KAAK,MAAM,KAAK,MAAM,IAAI,OAAO;EACnD,UAAU,IAAI,OAAO,WAAW,KAAK;EACrC,SAAS,OAAO,WAAW;EAC3B,SAAS;EACT,OAAO,KAAK,IAAI;CAClB,CAAC;CACD,OAAO,MAAM,KAAK,MAAM,SAAS;AACnC"}
@@ -3,8 +3,8 @@ import { AgentRun } from "./session/run.js";
3
3
  //#region src/agent-session-entry.d.ts
4
4
  interface SessionHandle {
5
5
  delete(): Promise<void>;
6
+ dispose(): Promise<void>;
6
7
  interrupt(): void;
7
- kill(): Promise<void>;
8
8
  send(input: AgentInput): Promise<AgentRun>;
9
9
  steer(input: AgentInput): Promise<AgentRun>;
10
10
  }
package/dist/agent.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import { AgentInput } from "./session/input.js";
2
2
  import { AgentHost } from "./execution/types.js";
3
- import { AgentOptions } from "./agent-options.js";
3
+ import { AgentConstructionOptions, AgentOptions } from "./agent-options.js";
4
4
  import { AgentRun } from "./session/run.js";
5
5
  import { SessionHandle } from "./agent-session-entry.js";
6
6
 
7
7
  //#region src/agent.d.ts
8
8
  declare class Agent {
9
9
  #private;
10
- readonly description?: string;
11
- readonly name?: string;
12
- constructor(options: AgentOptions);
10
+ readonly host: AgentHost;
11
+ readonly namespace?: string;
12
+ constructor(options: AgentConstructionOptions);
13
13
  send(input: AgentInput): Promise<AgentRun>;
14
14
  resume(runId: string): Promise<AgentRun | null>;
15
15
  session(key: string): SessionHandle;
package/dist/agent.js CHANGED
@@ -1,53 +1,34 @@
1
1
  import { executionHost } from "./execution/host.js";
2
- import { cancelDurableChildRuns } from "./agent-child-runs.js";
3
- import { supportsBackgroundSubagents } from "./agent-host-capabilities.js";
4
2
  import { sessionStoreForHost } from "./agent-host-session-store.js";
5
- import { parentSessionNamespace, stableAgentNamespace } from "./agent-namespace.js";
6
- import { assertAgentOptions, hasRuntimeModel } from "./agent-options.js";
3
+ import { stableAgentNamespace } from "./agent-namespace.js";
4
+ import { assertAgentOptions } from "./agent-options.js";
7
5
  import { resumeAgentRun } from "./agent-resume.js";
8
- import { assertSubagents } from "./agent-validation.js";
9
- import { ChildSessionCleanups } from "./child-session-cleanups.js";
10
6
  import { createInMemoryExecutionHost } from "./execution/memory.js";
11
- import { createLlm } from "./llm.js";
12
7
  import { AgentSession } from "./session/session.js";
13
- import { createSubagentTools } from "./subagents.js";
14
8
  //#region src/agent.ts
15
- var Agent = class Agent {
16
- #baseTools;
17
- #llm;
9
+ var Agent = class {
18
10
  #modelOptions;
19
- #childSessionCleanups = new ChildSessionCleanups();
20
- #sessionGenerations = /* @__PURE__ */ new Map();
21
11
  #sessions = /* @__PURE__ */ new Map();
22
12
  #sessionNamespace;
23
13
  #store;
24
14
  #host;
25
15
  #plugins;
26
- #subagents;
27
- description;
28
- name;
16
+ host;
17
+ namespace;
29
18
  constructor(options) {
30
19
  assertAgentOptions(options);
31
- this.description = options.description;
32
- this.name = options.name;
33
- this.#sessionNamespace = stableAgentNamespace({
34
- name: options.name,
35
- namespace: options.namespace
36
- });
20
+ this.namespace = options.namespace;
21
+ this.#sessionNamespace = stableAgentNamespace({ namespace: options.namespace });
37
22
  this.#host = options.host ?? createInMemoryExecutionHost();
23
+ this.host = this.#host;
38
24
  this.#store = sessionStoreForHost(this.#host);
39
25
  this.#plugins = options.plugins ?? [];
40
- assertSubagents(options, Agent, hasRuntimeModel(options));
41
- this.#subagents = hasRuntimeModel(options) ? [] : options.subagents ?? [];
42
- if (hasRuntimeModel(options)) this.#llm = options.model;
43
- else {
44
- this.#baseTools = options.tools;
45
- this.#modelOptions = {
46
- instructions: options.instructions,
47
- model: options.model,
48
- toolChoice: options.toolChoice
49
- };
50
- }
26
+ this.#modelOptions = {
27
+ instructions: options.instructions,
28
+ model: options.model,
29
+ toolChoice: options.toolChoice,
30
+ tools: options.tools
31
+ };
51
32
  }
52
33
  send(input) {
53
34
  return this.session("default").send(input);
@@ -59,8 +40,7 @@ var Agent = class Agent {
59
40
  host,
60
41
  ownerNamespace: this.#sessionNamespace,
61
42
  resumeNotification: (notification) => this.#resumeNotification(notification),
62
- runId,
63
- subagents: this.#subagents
43
+ runId
64
44
  });
65
45
  }
66
46
  session(key) {
@@ -70,16 +50,7 @@ var Agent = class Agent {
70
50
  const existing = this.#sessions.get(key);
71
51
  if (existing) return existing;
72
52
  let session;
73
- const getSession = () => {
74
- if (!session) throw new Error("Agent session is not initialized.");
75
- return session;
76
- };
77
- const parentAgentNamespace = parentSessionNamespace({
78
- generation: this.#sessionGenerations.get(key) ?? 0,
79
- sessionKey: key,
80
- sessionNamespace: this.#sessionNamespace
81
- });
82
- session = new AgentSession(this.#llm ?? createLlm(this.#createLlmOptionsForSession(key, parentAgentNamespace, (input, placement) => getSession().enqueueRuntimeInput(input, placement), (event) => getSession().emitObserverEvent(event), (input, options) => getSession().notify(input, options), () => getSession().currentTurnId(), () => parentAgentNamespace)), {
53
+ session = new AgentSession(this.#modelOptions, {
83
54
  key,
84
55
  store: this.#store
85
56
  }, this.#plugins, { executionHost: executionHost(this.#host) });
@@ -88,18 +59,15 @@ var Agent = class Agent {
88
59
  publicHandle: {
89
60
  delete: async () => {
90
61
  session.kill();
91
- await this.#cancelDurableChildRunsBeforeLocalCleanup(key, parentAgentNamespace);
92
62
  this.#evictSessionHandle(key);
93
63
  await session.delete();
94
- await this.#childSessionCleanups.delete(key);
95
64
  },
96
- interrupt: () => session.interrupt(),
97
- kill: async () => {
65
+ dispose: () => {
98
66
  session.kill();
99
- await this.#cancelDurableChildRunsBeforeLocalCleanup(key, parentAgentNamespace);
100
67
  this.#evictSessionHandle(key);
101
- await this.#childSessionCleanups.delete(key);
68
+ return Promise.resolve();
102
69
  },
70
+ interrupt: () => session.interrupt(),
103
71
  send: (input) => session.send(input),
104
72
  steer: (input) => session.steer(input)
105
73
  }
@@ -107,50 +75,12 @@ var Agent = class Agent {
107
75
  this.#sessions.set(key, entry);
108
76
  return entry;
109
77
  }
110
- async #cancelDurableChildRunsBeforeLocalCleanup(key, parentAgentNamespace) {
111
- try {
112
- await cancelDurableChildRuns(this.#host, parentAgentNamespace);
113
- } catch (error) {
114
- this.#evictSessionHandle(key);
115
- throw error;
116
- }
117
- }
118
78
  #evictSessionHandle(key) {
119
79
  this.#sessions.delete(key);
120
- this.#sessionGenerations.set(key, (this.#sessionGenerations.get(key) ?? 0) + 1);
121
80
  }
122
81
  #resumeNotification(notification) {
123
82
  return this.#sessionEntry(notification.sessionKey).notify(notification.input, { observerEvents: notification.observerEvents });
124
83
  }
125
- #createLlmOptionsForSession(key, parentAgentNamespace, enqueueRuntimeInput, emitObserverEvent, notify, currentBackgroundGroupId, currentRunId) {
126
- const modelOptions = this.#modelOptions;
127
- if (!modelOptions) throw new Error("Agent: missing model options.");
128
- const hostExecution = executionHost(this.#host);
129
- const tools = this.#subagents.length === 0 ? this.#baseTools : {
130
- ...this.#baseTools,
131
- ...createSubagentTools({
132
- backgroundSubagents: supportsBackgroundSubagents(this.#host, hostExecution),
133
- executionHost: hostExecution,
134
- parentAgentNamespace,
135
- parentSession: {
136
- currentBackgroundGroupId,
137
- currentRunId,
138
- emitObserverEvent,
139
- enqueueRuntimeInput,
140
- notify
141
- },
142
- parentSessionKey: key,
143
- registerChildSession: (sessionKey, cleanup) => this.#childSessionCleanups.register(sessionKey, cleanup),
144
- subagents: this.#subagents
145
- })
146
- };
147
- return {
148
- instructions: modelOptions.instructions,
149
- model: modelOptions.model,
150
- toolChoice: modelOptions.toolChoice,
151
- tools
152
- };
153
- }
154
84
  };
155
85
  //#endregion
156
86
  export { Agent };
package/dist/agent.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","names":["#baseTools","#llm","#modelOptions","#childSessionCleanups","#sessionGenerations","#sessions","#sessionNamespace","#store","#host","#plugins","#subagents","#resumeNotification","#sessionEntry","#createLlmOptionsForSession","#cancelDurableChildRunsBeforeLocalCleanup","#evictSessionHandle"],"sources":["../src/agent.ts"],"sourcesContent":["import type { ToolSet } from \"ai\";\nimport { cancelDurableChildRuns } from \"./agent-child-runs\";\nimport { supportsBackgroundSubagents } from \"./agent-host-capabilities\";\nimport { sessionStoreForHost } from \"./agent-host-session-store\";\nimport {\n parentSessionNamespace,\n stableAgentNamespace,\n} from \"./agent-namespace\";\nimport {\n type AgentModelOptions,\n type AgentOptions,\n assertAgentOptions,\n hasRuntimeModel,\n} from \"./agent-options\";\nimport { resumeAgentRun } from \"./agent-resume\";\nimport type { AgentSessionEntry, SessionHandle } from \"./agent-session-entry\";\nimport { assertSubagents } from \"./agent-validation\";\nimport { ChildSessionCleanups } from \"./child-session-cleanups\";\nimport { executionHost } from \"./execution/host\";\nimport { createInMemoryExecutionHost } from \"./execution/memory\";\nimport type { AgentHost, NotificationRecord } from \"./execution/types\";\nimport { createLlm, type RuntimeLlm } from \"./llm\";\nimport type { AgentPlugin } from \"./plugins\";\nimport type { UserInput } from \"./session/events\";\nimport type { AgentRun } from \"./session/run\";\nimport {\n type AgentInput,\n AgentSession,\n type NotifyOptions,\n} from \"./session/session\";\nimport type { SessionStore } from \"./session/store/types\";\nimport { createSubagentTools } from \"./subagents\";\n\nexport type { AgentOptions } from \"./agent-options\";\nexport type { SessionHandle } from \"./agent-session-entry\";\nexport type { AgentHost } from \"./execution/types\";\n\nexport class Agent {\n readonly #baseTools?: ToolSet;\n readonly #llm?: RuntimeLlm;\n readonly #modelOptions?: AgentModelOptions;\n readonly #childSessionCleanups = new ChildSessionCleanups();\n readonly #sessionGenerations = new Map<string, number>();\n readonly #sessions = new Map<string, AgentSessionEntry>();\n readonly #sessionNamespace: string;\n readonly #store: SessionStore;\n readonly #host: AgentHost;\n readonly #plugins: readonly AgentPlugin[];\n readonly #subagents: readonly Agent[];\n readonly description?: string;\n readonly name?: string;\n\n constructor(options: AgentOptions) {\n assertAgentOptions(options);\n\n this.description = options.description;\n this.name = options.name;\n this.#sessionNamespace = stableAgentNamespace({\n name: options.name,\n namespace: options.namespace,\n });\n this.#host = options.host ?? createInMemoryExecutionHost();\n this.#store = sessionStoreForHost(this.#host);\n this.#plugins = options.plugins ?? [];\n assertSubagents(options, Agent, hasRuntimeModel(options));\n this.#subagents = hasRuntimeModel(options) ? [] : (options.subagents ?? []);\n if (hasRuntimeModel(options)) {\n this.#llm = options.model;\n } else {\n this.#baseTools = options.tools;\n this.#modelOptions = {\n instructions: options.instructions,\n model: options.model,\n toolChoice: options.toolChoice,\n };\n }\n }\n\n send(input: AgentInput): Promise<AgentRun> {\n return this.session(\"default\").send(input);\n }\n\n async resume(runId: string): Promise<AgentRun | null> {\n const host = executionHost(this.#host);\n if (!host) {\n throw new Error(\"Agent host does not support durable run resume.\");\n }\n\n return await resumeAgentRun({\n host,\n ownerNamespace: this.#sessionNamespace,\n resumeNotification: (notification) =>\n this.#resumeNotification(notification),\n runId,\n subagents: this.#subagents,\n });\n }\n\n session(key: string): SessionHandle {\n return this.#sessionEntry(key).publicHandle;\n }\n\n #sessionEntry(key: string): AgentSessionEntry {\n const existing = this.#sessions.get(key);\n if (existing) {\n return existing;\n }\n\n let session: AgentSession | undefined;\n const getSession = () => {\n if (!session) {\n throw new Error(\"Agent session is not initialized.\");\n }\n return session;\n };\n const parentAgentNamespace = parentSessionNamespace({\n generation: this.#sessionGenerations.get(key) ?? 0,\n sessionKey: key,\n sessionNamespace: this.#sessionNamespace,\n });\n const llm =\n this.#llm ??\n createLlm(\n this.#createLlmOptionsForSession(\n key,\n parentAgentNamespace,\n (input: UserInput, placement?: \"turn-start\") =>\n getSession().enqueueRuntimeInput(input, placement),\n (event) => getSession().emitObserverEvent(event),\n (input: UserInput, options?: NotifyOptions) =>\n getSession().notify(input, options),\n () => getSession().currentTurnId(),\n () => parentAgentNamespace\n )\n );\n session = new AgentSession(\n llm,\n { key, store: this.#store },\n this.#plugins,\n {\n executionHost: executionHost(this.#host),\n }\n );\n const publicHandle: SessionHandle = {\n delete: async () => {\n session.kill();\n await this.#cancelDurableChildRunsBeforeLocalCleanup(\n key,\n parentAgentNamespace\n );\n this.#evictSessionHandle(key);\n await session.delete();\n await this.#childSessionCleanups.delete(key);\n },\n interrupt: () => session.interrupt(),\n kill: async () => {\n session.kill();\n await this.#cancelDurableChildRunsBeforeLocalCleanup(\n key,\n parentAgentNamespace\n );\n this.#evictSessionHandle(key);\n await this.#childSessionCleanups.delete(key);\n },\n send: (input) => session.send(input),\n steer: (input) => session.steer(input),\n };\n const entry: AgentSessionEntry = {\n notify: (input, options) => session.notify(input, options),\n publicHandle,\n };\n this.#sessions.set(key, entry);\n return entry;\n }\n\n async #cancelDurableChildRunsBeforeLocalCleanup(\n key: string,\n parentAgentNamespace: string\n ): Promise<void> {\n try {\n await cancelDurableChildRuns(this.#host, parentAgentNamespace);\n } catch (error) {\n this.#evictSessionHandle(key);\n throw error;\n }\n }\n\n #evictSessionHandle(key: string): void {\n this.#sessions.delete(key);\n this.#sessionGenerations.set(\n key,\n (this.#sessionGenerations.get(key) ?? 0) + 1\n );\n }\n\n #resumeNotification(notification: NotificationRecord): Promise<AgentRun> {\n return this.#sessionEntry(notification.sessionKey).notify(\n notification.input,\n { observerEvents: notification.observerEvents }\n );\n }\n\n #createLlmOptionsForSession(\n key: string,\n parentAgentNamespace: string,\n enqueueRuntimeInput: AgentSession[\"enqueueRuntimeInput\"],\n emitObserverEvent: AgentSession[\"emitObserverEvent\"],\n notify: (input: UserInput, options?: NotifyOptions) => Promise<AgentRun>,\n currentBackgroundGroupId: () => string | undefined,\n currentRunId: () => string | undefined\n ): Parameters<typeof createLlm>[0] {\n const modelOptions = this.#modelOptions;\n if (!modelOptions) {\n throw new Error(\"Agent: missing model options.\");\n }\n const hostExecution = executionHost(this.#host);\n const tools =\n this.#subagents.length === 0\n ? this.#baseTools\n : {\n ...this.#baseTools,\n ...createSubagentTools({\n backgroundSubagents: supportsBackgroundSubagents(\n this.#host,\n hostExecution\n ),\n executionHost: hostExecution,\n parentAgentNamespace,\n parentSession: {\n currentBackgroundGroupId,\n currentRunId,\n emitObserverEvent,\n enqueueRuntimeInput,\n notify,\n },\n parentSessionKey: key,\n registerChildSession: (sessionKey, cleanup) =>\n this.#childSessionCleanups.register(sessionKey, cleanup),\n subagents: this.#subagents,\n }),\n };\n\n return {\n instructions: modelOptions.instructions,\n model: modelOptions.model,\n toolChoice: modelOptions.toolChoice,\n tools,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent.js","names":["#modelOptions","#sessions","#sessionNamespace","#store","#host","#plugins","#resumeNotification","#sessionEntry","#evictSessionHandle"],"sources":["../src/agent.ts"],"sourcesContent":["import { sessionStoreForHost } from \"./agent-host-session-store\";\nimport { stableAgentNamespace } from \"./agent-namespace\";\nimport {\n type AgentConstructionOptions,\n type AgentModelOptions,\n assertAgentOptions,\n} from \"./agent-options\";\nimport { resumeAgentRun } from \"./agent-resume\";\nimport type { AgentSessionEntry, SessionHandle } from \"./agent-session-entry\";\nimport { executionHost } from \"./execution/host\";\nimport { createInMemoryExecutionHost } from \"./execution/memory\";\nimport type { AgentHost, NotificationRecord } from \"./execution/types\";\nimport type { AgentPlugin } from \"./plugins\";\nimport type { AgentRun } from \"./session/run\";\nimport { type AgentInput, AgentSession } from \"./session/session\";\nimport type { SessionStore } from \"./session/store/types\";\n\nexport type { AgentOptions } from \"./agent-options\";\nexport type { SessionHandle } from \"./agent-session-entry\";\nexport type { AgentHost } from \"./execution/types\";\n\nexport class Agent {\n readonly #modelOptions: AgentModelOptions;\n readonly #sessions = new Map<string, AgentSessionEntry>();\n readonly #sessionNamespace: string;\n readonly #store: SessionStore;\n readonly #host: AgentHost;\n readonly #plugins: readonly AgentPlugin[];\n readonly host: AgentHost;\n readonly namespace?: string;\n constructor(options: AgentConstructionOptions) {\n assertAgentOptions(options);\n\n this.namespace = options.namespace;\n this.#sessionNamespace = stableAgentNamespace({\n namespace: options.namespace,\n });\n this.#host = options.host ?? createInMemoryExecutionHost();\n this.host = this.#host;\n this.#store = sessionStoreForHost(this.#host);\n this.#plugins = options.plugins ?? [];\n this.#modelOptions = {\n instructions: options.instructions,\n model: options.model,\n toolChoice: options.toolChoice,\n tools: options.tools,\n };\n }\n\n send(input: AgentInput): Promise<AgentRun> {\n return this.session(\"default\").send(input);\n }\n\n async resume(runId: string): Promise<AgentRun | null> {\n const host = executionHost(this.#host);\n if (!host) {\n throw new Error(\"Agent host does not support durable run resume.\");\n }\n\n return await resumeAgentRun({\n host,\n ownerNamespace: this.#sessionNamespace,\n resumeNotification: (notification) =>\n this.#resumeNotification(notification),\n runId,\n });\n }\n\n session(key: string): SessionHandle {\n return this.#sessionEntry(key).publicHandle;\n }\n\n #sessionEntry(key: string): AgentSessionEntry {\n const existing = this.#sessions.get(key);\n if (existing) {\n return existing;\n }\n\n let session: AgentSession | undefined;\n session = new AgentSession(\n this.#modelOptions,\n { key, store: this.#store },\n this.#plugins,\n {\n executionHost: executionHost(this.#host),\n }\n );\n const publicHandle: SessionHandle = {\n delete: async () => {\n session.kill();\n this.#evictSessionHandle(key);\n await session.delete();\n },\n dispose: () => {\n session.kill();\n this.#evictSessionHandle(key);\n return Promise.resolve();\n },\n interrupt: () => session.interrupt(),\n send: (input) => session.send(input),\n steer: (input) => session.steer(input),\n };\n const entry: AgentSessionEntry = {\n notify: (input, options) => session.notify(input, options),\n publicHandle,\n };\n this.#sessions.set(key, entry);\n return entry;\n }\n\n #evictSessionHandle(key: string): void {\n this.#sessions.delete(key);\n }\n\n #resumeNotification(notification: NotificationRecord): Promise<AgentRun> {\n return this.#sessionEntry(notification.sessionKey).notify(\n notification.input,\n { observerEvents: notification.observerEvents }\n );\n }\n}\n"],"mappings":";;;;;;;;AAqBA,IAAa,QAAb,MAAmB;CACjB;CACA,4BAAqB,IAAI,IAA+B;CACxD;CACA;CACA;CACA;CACA;CACA;CACA,YAAY,SAAmC;EAC7C,mBAAmB,OAAO;EAE1B,KAAK,YAAY,QAAQ;EACzB,KAAKE,oBAAoB,qBAAqB,EAC5C,WAAW,QAAQ,UACrB,CAAC;EACD,KAAKE,QAAQ,QAAQ,QAAQ,4BAA4B;EACzD,KAAK,OAAO,KAAKA;EACjB,KAAKD,SAAS,oBAAoB,KAAKC,KAAK;EAC5C,KAAKC,WAAW,QAAQ,WAAW,CAAC;EACpC,KAAKL,gBAAgB;GACnB,cAAc,QAAQ;GACtB,OAAO,QAAQ;GACf,YAAY,QAAQ;GACpB,OAAO,QAAQ;EACjB;CACF;CAEA,KAAK,OAAsC;EACzC,OAAO,KAAK,QAAQ,SAAS,EAAE,KAAK,KAAK;CAC3C;CAEA,MAAM,OAAO,OAAyC;EACpD,MAAM,OAAO,cAAc,KAAKI,KAAK;EACrC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iDAAiD;EAGnE,OAAO,MAAM,eAAe;GAC1B;GACA,gBAAgB,KAAKF;GACrB,qBAAqB,iBACnB,KAAKI,oBAAoB,YAAY;GACvC;EACF,CAAC;CACH;CAEA,QAAQ,KAA4B;EAClC,OAAO,KAAKC,cAAc,GAAG,EAAE;CACjC;CAEA,cAAc,KAAgC;EAC5C,MAAM,WAAW,KAAKN,UAAU,IAAI,GAAG;EACvC,IAAI,UACF,OAAO;EAGT,IAAI;EACJ,UAAU,IAAI,aACZ,KAAKD,eACL;GAAE;GAAK,OAAO,KAAKG;EAAO,GAC1B,KAAKE,UACL,EACE,eAAe,cAAc,KAAKD,KAAK,EACzC,CACF;EAgBA,MAAM,QAA2B;GAC/B,SAAS,OAAO,YAAY,QAAQ,OAAO,OAAO,OAAO;GACzD,cAAA;IAhBA,QAAQ,YAAY;KAClB,QAAQ,KAAK;KACb,KAAKI,oBAAoB,GAAG;KAC5B,MAAM,QAAQ,OAAO;IACvB;IACA,eAAe;KACb,QAAQ,KAAK;KACb,KAAKA,oBAAoB,GAAG;KAC5B,OAAO,QAAQ,QAAQ;IACzB;IACA,iBAAiB,QAAQ,UAAU;IACnC,OAAO,UAAU,QAAQ,KAAK,KAAK;IACnC,QAAQ,UAAU,QAAQ,MAAM,KAAK;GAI1B;EACb;EACA,KAAKP,UAAU,IAAI,KAAK,KAAK;EAC7B,OAAO;CACT;CAEA,oBAAoB,KAAmB;EACrC,KAAKA,UAAU,OAAO,GAAG;CAC3B;CAEA,oBAAoB,cAAqD;EACvE,OAAO,KAAKM,cAAc,aAAa,UAAU,EAAE,OACjD,aAAa,OACb,EAAE,gBAAgB,aAAa,eAAe,CAChD;CACF;AACF"}
@@ -0,0 +1,40 @@
1
+ import { ExecutionHost } from "../execution/types.js";
2
+ import { CloudflareAlarmDrainBudget } from "./cloudflare-alarm-budget.js";
3
+ import { CloudflareDurableObjectStorage } from "./cloudflare-host.js";
4
+ import { CloudflareAlarmAgent, CloudflareAlarmDrainSummary } from "./cloudflare-alarm-drainer.js";
5
+
6
+ //#region src/cloudflare/cloudflare-agent-context.d.ts
7
+ type MaybePromise<T> = Promise<T> | T;
8
+ interface CloudflareAgentContextFactoryOptions<Env> {
9
+ readonly env: Env;
10
+ readonly host: ExecutionHost;
11
+ readonly prefix: string;
12
+ readonly storage: CloudflareDurableObjectStorage;
13
+ }
14
+ interface CloudflareAgentContextPrefixOptions<Env> {
15
+ readonly env: Env;
16
+ readonly storage: CloudflareDurableObjectStorage;
17
+ }
18
+ interface CloudflareAgentContextOptions<Env, Agent extends CloudflareAlarmAgent> {
19
+ readonly createAgent: (options: CloudflareAgentContextFactoryOptions<Env>) => Agent;
20
+ readonly defaultPrefix?: string;
21
+ readonly env: Env;
22
+ readonly readPrefix?: (options: CloudflareAgentContextPrefixOptions<Env>) => MaybePromise<string | undefined>;
23
+ readonly storage: CloudflareDurableObjectStorage;
24
+ }
25
+ interface CloudflareAgentContext<Agent extends CloudflareAlarmAgent> {
26
+ agent(prefix?: string): Agent;
27
+ drainAlarm(budget?: CloudflareAlarmDrainBudget): Promise<CloudflareAlarmDrainSummary>;
28
+ host(prefix?: string): ExecutionHost;
29
+ readonly storage: CloudflareDurableObjectStorage;
30
+ }
31
+ declare function createCloudflareAgentContext<Env, Agent extends CloudflareAlarmAgent>({
32
+ createAgent,
33
+ defaultPrefix,
34
+ env,
35
+ readPrefix,
36
+ storage
37
+ }: CloudflareAgentContextOptions<Env, Agent>): CloudflareAgentContext<Agent>;
38
+ //#endregion
39
+ export { CloudflareAgentContext, CloudflareAgentContextFactoryOptions, CloudflareAgentContextOptions, CloudflareAgentContextPrefixOptions, createCloudflareAgentContext };
40
+ //# sourceMappingURL=cloudflare-agent-context.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { createCloudflareDurableObjectHost } from "./cloudflare-host.js";
2
+ import { drainCloudflareAlarm } from "./cloudflare-alarm-drainer.js";
3
+ //#region src/cloudflare/cloudflare-agent-context.ts
4
+ const defaultContextPrefix = "pss-runtime";
5
+ function createCloudflareAgentContext({ createAgent, defaultPrefix = defaultContextPrefix, env, readPrefix, storage }) {
6
+ const createHost = (prefix = defaultPrefix) => createCloudflareDurableObjectHost({
7
+ prefix,
8
+ storage
9
+ });
10
+ const createContextAgent = (prefix = defaultPrefix) => createAgent({
11
+ env,
12
+ host: createHost(prefix),
13
+ prefix,
14
+ storage
15
+ });
16
+ return {
17
+ agent: createContextAgent,
18
+ drainAlarm: async (budget) => {
19
+ const prefix = await readPrefix?.({
20
+ env,
21
+ storage
22
+ }) ?? defaultPrefix;
23
+ return await drainCloudflareAlarm({
24
+ agent: createContextAgent(prefix),
25
+ ...budget,
26
+ prefix,
27
+ storage
28
+ });
29
+ },
30
+ host: createHost,
31
+ storage
32
+ };
33
+ }
34
+ //#endregion
35
+ export { createCloudflareAgentContext };
36
+
37
+ //# sourceMappingURL=cloudflare-agent-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-agent-context.js","names":[],"sources":["../../src/cloudflare/cloudflare-agent-context.ts"],"sourcesContent":["import type { ExecutionHost } from \"../execution\";\nimport type { CloudflareAlarmDrainBudget } from \"./cloudflare-alarm-budget\";\nimport type {\n CloudflareAlarmAgent,\n CloudflareAlarmDrainSummary,\n} from \"./cloudflare-alarm-drainer\";\nimport { drainCloudflareAlarm } from \"./cloudflare-alarm-drainer\";\nimport {\n type CloudflareDurableObjectStorage,\n createCloudflareDurableObjectHost,\n} from \"./cloudflare-host\";\n\nconst defaultContextPrefix = \"pss-runtime\";\n\ntype MaybePromise<T> = Promise<T> | T;\n\nexport interface CloudflareAgentContextFactoryOptions<Env> {\n readonly env: Env;\n readonly host: ExecutionHost;\n readonly prefix: string;\n readonly storage: CloudflareDurableObjectStorage;\n}\n\nexport interface CloudflareAgentContextPrefixOptions<Env> {\n readonly env: Env;\n readonly storage: CloudflareDurableObjectStorage;\n}\n\nexport interface CloudflareAgentContextOptions<\n Env,\n Agent extends CloudflareAlarmAgent,\n> {\n readonly createAgent: (\n options: CloudflareAgentContextFactoryOptions<Env>\n ) => Agent;\n readonly defaultPrefix?: string;\n readonly env: Env;\n readonly readPrefix?: (\n options: CloudflareAgentContextPrefixOptions<Env>\n ) => MaybePromise<string | undefined>;\n readonly storage: CloudflareDurableObjectStorage;\n}\n\nexport interface CloudflareAgentContext<Agent extends CloudflareAlarmAgent> {\n agent(prefix?: string): Agent;\n drainAlarm(\n budget?: CloudflareAlarmDrainBudget\n ): Promise<CloudflareAlarmDrainSummary>;\n host(prefix?: string): ExecutionHost;\n readonly storage: CloudflareDurableObjectStorage;\n}\n\nexport function createCloudflareAgentContext<\n Env,\n Agent extends CloudflareAlarmAgent,\n>({\n createAgent,\n defaultPrefix = defaultContextPrefix,\n env,\n readPrefix,\n storage,\n}: CloudflareAgentContextOptions<Env, Agent>): CloudflareAgentContext<Agent> {\n const createHost = (prefix = defaultPrefix) =>\n createCloudflareDurableObjectHost({ prefix, storage });\n const createContextAgent = (prefix = defaultPrefix) =>\n createAgent({\n env,\n host: createHost(prefix),\n prefix,\n storage,\n });\n\n return {\n agent: createContextAgent,\n drainAlarm: async (budget) => {\n const prefix = (await readPrefix?.({ env, storage })) ?? defaultPrefix;\n return await drainCloudflareAlarm({\n agent: createContextAgent(prefix),\n ...budget,\n prefix,\n storage,\n });\n },\n host: createHost,\n storage,\n };\n}\n"],"mappings":";;;AAYA,MAAM,uBAAuB;AAwC7B,SAAgB,6BAGd,EACA,aACA,gBAAgB,sBAChB,KACA,YACA,WAC2E;CAC3E,MAAM,cAAc,SAAS,kBAC3B,kCAAkC;EAAE;EAAQ;CAAQ,CAAC;CACvD,MAAM,sBAAsB,SAAS,kBACnC,YAAY;EACV;EACA,MAAM,WAAW,MAAM;EACvB;EACA;CACF,CAAC;CAEH,OAAO;EACL,OAAO;EACP,YAAY,OAAO,WAAW;GAC5B,MAAM,SAAU,MAAM,aAAa;IAAE;IAAK;GAAQ,CAAC,KAAM;GACzD,OAAO,MAAM,qBAAqB;IAChC,OAAO,mBAAmB,MAAM;IAChC,GAAG;IACH;IACA;GACF,CAAC;EACH;EACA,MAAM;EACN;CACF;AACF"}
@@ -0,0 +1,18 @@
1
+ //#region src/cloudflare/cloudflare-alarm-budget.d.ts
2
+ type CloudflareAlarmContinuationReason = "deadline" | "event-budget" | "failure" | "run-budget" | "session-prompt-budget";
3
+ interface CloudflareAlarmDrainBudget {
4
+ readonly continuationRunAfterMs?: number;
5
+ readonly deadlineMs?: number;
6
+ readonly failureRunAfterMs?: number;
7
+ readonly maxEvents?: number;
8
+ readonly maxRuns?: number;
9
+ readonly maxSessionPrompts?: number;
10
+ readonly throwOnFailure?: boolean;
11
+ }
12
+ interface FailedScheduledWork {
13
+ readonly error: string;
14
+ readonly id: string;
15
+ }
16
+ //#endregion
17
+ export { CloudflareAlarmContinuationReason, CloudflareAlarmDrainBudget, FailedScheduledWork };
18
+ //# sourceMappingURL=cloudflare-alarm-budget.d.ts.map
@@ -0,0 +1,77 @@
1
+ //#region src/cloudflare/cloudflare-alarm-budget.ts
2
+ const defaultAlarmDrainBudget = {
3
+ continuationRunAfterMs: 0,
4
+ deadlineMs: 3e4,
5
+ failureRunAfterMs: 1e3,
6
+ maxEvents: 1e3,
7
+ maxRuns: 25,
8
+ maxSessionPrompts: 25,
9
+ throwOnFailure: false
10
+ };
11
+ function createAlarmDrainState() {
12
+ return {
13
+ consumedSessionPrompts: [],
14
+ droppedEvents: 0,
15
+ events: [],
16
+ failedRuns: [],
17
+ failedSessionPrompts: [],
18
+ reasons: /* @__PURE__ */ new Set(),
19
+ resumedRuns: [],
20
+ runAttempts: 0,
21
+ sessionPromptAttempts: 0
22
+ };
23
+ }
24
+ function normalizeAlarmDrainBudget(budget = {}) {
25
+ return {
26
+ continuationRunAfterMs: nonNegativeInteger(budget.continuationRunAfterMs ?? defaultAlarmDrainBudget.continuationRunAfterMs),
27
+ deadlineMs: nonNegativeInteger(budget.deadlineMs ?? defaultAlarmDrainBudget.deadlineMs),
28
+ failureRunAfterMs: nonNegativeInteger(budget.failureRunAfterMs ?? defaultAlarmDrainBudget.failureRunAfterMs),
29
+ maxEvents: nonNegativeInteger(budget.maxEvents ?? defaultAlarmDrainBudget.maxEvents),
30
+ maxRuns: nonNegativeInteger(budget.maxRuns ?? defaultAlarmDrainBudget.maxRuns),
31
+ maxSessionPrompts: nonNegativeInteger(budget.maxSessionPrompts ?? defaultAlarmDrainBudget.maxSessionPrompts),
32
+ startedAt: Date.now(),
33
+ throwOnFailure: budget.throwOnFailure ?? defaultAlarmDrainBudget.throwOnFailure
34
+ };
35
+ }
36
+ function eventSlotsRemaining(state, budget) {
37
+ return Math.max(0, budget.maxEvents - state.events.length);
38
+ }
39
+ function shouldStopForDeadline(budget) {
40
+ return Date.now() - budget.startedAt >= budget.deadlineMs;
41
+ }
42
+ function shouldStopRuns(state, budget) {
43
+ if (shouldStopForDeadline(budget)) {
44
+ state.reasons.add("deadline");
45
+ return true;
46
+ }
47
+ if (shouldStopForEventBudget(state, budget)) return true;
48
+ if (state.runAttempts >= budget.maxRuns) {
49
+ state.reasons.add("run-budget");
50
+ return true;
51
+ }
52
+ return false;
53
+ }
54
+ function shouldStopSessionPrompts(state, budget) {
55
+ if (shouldStopForDeadline(budget)) {
56
+ state.reasons.add("deadline");
57
+ return true;
58
+ }
59
+ if (shouldStopForEventBudget(state, budget)) return true;
60
+ if (state.sessionPromptAttempts >= budget.maxSessionPrompts) {
61
+ state.reasons.add("session-prompt-budget");
62
+ return true;
63
+ }
64
+ return false;
65
+ }
66
+ function shouldStopForEventBudget(state, budget) {
67
+ if (state.events.length < budget.maxEvents) return false;
68
+ state.reasons.add("event-budget");
69
+ return true;
70
+ }
71
+ function nonNegativeInteger(value) {
72
+ return Math.max(0, Math.floor(value));
73
+ }
74
+ //#endregion
75
+ export { createAlarmDrainState, eventSlotsRemaining, normalizeAlarmDrainBudget, shouldStopRuns, shouldStopSessionPrompts };
76
+
77
+ //# sourceMappingURL=cloudflare-alarm-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-alarm-budget.js","names":[],"sources":["../../src/cloudflare/cloudflare-alarm-budget.ts"],"sourcesContent":["import type { AgentEvent } from \"../index\";\n\nexport type CloudflareAlarmContinuationReason =\n | \"deadline\"\n | \"event-budget\"\n | \"failure\"\n | \"run-budget\"\n | \"session-prompt-budget\";\n\nexport interface CloudflareAlarmDrainBudget {\n readonly continuationRunAfterMs?: number;\n readonly deadlineMs?: number;\n readonly failureRunAfterMs?: number;\n readonly maxEvents?: number;\n readonly maxRuns?: number;\n readonly maxSessionPrompts?: number;\n readonly throwOnFailure?: boolean;\n}\n\nexport interface FailedScheduledWork {\n readonly error: string;\n readonly id: string;\n}\n\nexport interface AlarmDrainState {\n readonly consumedSessionPrompts: string[];\n droppedEvents: number;\n readonly events: AgentEvent[];\n readonly failedRuns: FailedScheduledWork[];\n readonly failedSessionPrompts: FailedScheduledWork[];\n readonly reasons: Set<CloudflareAlarmContinuationReason>;\n readonly resumedRuns: string[];\n runAttempts: number;\n sessionPromptAttempts: number;\n}\n\nexport interface NormalizedAlarmDrainBudget {\n readonly continuationRunAfterMs: number;\n readonly deadlineMs: number;\n readonly failureRunAfterMs: number;\n readonly maxEvents: number;\n readonly maxRuns: number;\n readonly maxSessionPrompts: number;\n readonly startedAt: number;\n readonly throwOnFailure: boolean;\n}\n\nconst defaultAlarmDrainBudget = {\n continuationRunAfterMs: 0,\n deadlineMs: 30_000,\n failureRunAfterMs: 1000,\n maxEvents: 1000,\n maxRuns: 25,\n maxSessionPrompts: 25,\n throwOnFailure: false,\n} satisfies Required<CloudflareAlarmDrainBudget>;\n\nexport function createAlarmDrainState(): AlarmDrainState {\n return {\n consumedSessionPrompts: [],\n droppedEvents: 0,\n events: [],\n failedRuns: [],\n failedSessionPrompts: [],\n reasons: new Set<CloudflareAlarmContinuationReason>(),\n resumedRuns: [],\n runAttempts: 0,\n sessionPromptAttempts: 0,\n };\n}\n\nexport function normalizeAlarmDrainBudget(\n budget: CloudflareAlarmDrainBudget = {}\n): NormalizedAlarmDrainBudget {\n return {\n continuationRunAfterMs: nonNegativeInteger(\n budget.continuationRunAfterMs ??\n defaultAlarmDrainBudget.continuationRunAfterMs\n ),\n deadlineMs: nonNegativeInteger(\n budget.deadlineMs ?? defaultAlarmDrainBudget.deadlineMs\n ),\n failureRunAfterMs: nonNegativeInteger(\n budget.failureRunAfterMs ?? defaultAlarmDrainBudget.failureRunAfterMs\n ),\n maxEvents: nonNegativeInteger(\n budget.maxEvents ?? defaultAlarmDrainBudget.maxEvents\n ),\n maxRuns: nonNegativeInteger(\n budget.maxRuns ?? defaultAlarmDrainBudget.maxRuns\n ),\n maxSessionPrompts: nonNegativeInteger(\n budget.maxSessionPrompts ?? defaultAlarmDrainBudget.maxSessionPrompts\n ),\n startedAt: Date.now(),\n throwOnFailure:\n budget.throwOnFailure ?? defaultAlarmDrainBudget.throwOnFailure,\n };\n}\n\nexport function eventSlotsRemaining(\n state: AlarmDrainState,\n budget: NormalizedAlarmDrainBudget\n): number {\n return Math.max(0, budget.maxEvents - state.events.length);\n}\n\nexport function shouldStopForDeadline(\n budget: NormalizedAlarmDrainBudget\n): boolean {\n return Date.now() - budget.startedAt >= budget.deadlineMs;\n}\n\nexport function shouldStopRuns(\n state: AlarmDrainState,\n budget: NormalizedAlarmDrainBudget\n): boolean {\n if (shouldStopForDeadline(budget)) {\n state.reasons.add(\"deadline\");\n return true;\n }\n if (shouldStopForEventBudget(state, budget)) {\n return true;\n }\n if (state.runAttempts >= budget.maxRuns) {\n state.reasons.add(\"run-budget\");\n return true;\n }\n return false;\n}\n\nexport function shouldStopSessionPrompts(\n state: AlarmDrainState,\n budget: NormalizedAlarmDrainBudget\n): boolean {\n if (shouldStopForDeadline(budget)) {\n state.reasons.add(\"deadline\");\n return true;\n }\n if (shouldStopForEventBudget(state, budget)) {\n return true;\n }\n if (state.sessionPromptAttempts >= budget.maxSessionPrompts) {\n state.reasons.add(\"session-prompt-budget\");\n return true;\n }\n return false;\n}\n\nfunction shouldStopForEventBudget(\n state: AlarmDrainState,\n budget: NormalizedAlarmDrainBudget\n): boolean {\n if (state.events.length < budget.maxEvents) {\n return false;\n }\n state.reasons.add(\"event-budget\");\n return true;\n}\n\nfunction nonNegativeInteger(value: number): number {\n return Math.max(0, Math.floor(value));\n}\n"],"mappings":";AA+CA,MAAM,0BAA0B;CAC9B,wBAAwB;CACxB,YAAY;CACZ,mBAAmB;CACnB,WAAW;CACX,SAAS;CACT,mBAAmB;CACnB,gBAAgB;AAClB;AAEA,SAAgB,wBAAyC;CACvD,OAAO;EACL,wBAAwB,CAAC;EACzB,eAAe;EACf,QAAQ,CAAC;EACT,YAAY,CAAC;EACb,sBAAsB,CAAC;EACvB,yBAAS,IAAI,IAAuC;EACpD,aAAa,CAAC;EACd,aAAa;EACb,uBAAuB;CACzB;AACF;AAEA,SAAgB,0BACd,SAAqC,CAAC,GACV;CAC5B,OAAO;EACL,wBAAwB,mBACtB,OAAO,0BACL,wBAAwB,sBAC5B;EACA,YAAY,mBACV,OAAO,cAAc,wBAAwB,UAC/C;EACA,mBAAmB,mBACjB,OAAO,qBAAqB,wBAAwB,iBACtD;EACA,WAAW,mBACT,OAAO,aAAa,wBAAwB,SAC9C;EACA,SAAS,mBACP,OAAO,WAAW,wBAAwB,OAC5C;EACA,mBAAmB,mBACjB,OAAO,qBAAqB,wBAAwB,iBACtD;EACA,WAAW,KAAK,IAAI;EACpB,gBACE,OAAO,kBAAkB,wBAAwB;CACrD;AACF;AAEA,SAAgB,oBACd,OACA,QACQ;CACR,OAAO,KAAK,IAAI,GAAG,OAAO,YAAY,MAAM,OAAO,MAAM;AAC3D;AAEA,SAAgB,sBACd,QACS;CACT,OAAO,KAAK,IAAI,IAAI,OAAO,aAAa,OAAO;AACjD;AAEA,SAAgB,eACd,OACA,QACS;CACT,IAAI,sBAAsB,MAAM,GAAG;EACjC,MAAM,QAAQ,IAAI,UAAU;EAC5B,OAAO;CACT;CACA,IAAI,yBAAyB,OAAO,MAAM,GACxC,OAAO;CAET,IAAI,MAAM,eAAe,OAAO,SAAS;EACvC,MAAM,QAAQ,IAAI,YAAY;EAC9B,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAgB,yBACd,OACA,QACS;CACT,IAAI,sBAAsB,MAAM,GAAG;EACjC,MAAM,QAAQ,IAAI,UAAU;EAC5B,OAAO;CACT;CACA,IAAI,yBAAyB,OAAO,MAAM,GACxC,OAAO;CAET,IAAI,MAAM,yBAAyB,OAAO,mBAAmB;EAC3D,MAAM,QAAQ,IAAI,uBAAuB;EACzC,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAS,yBACP,OACA,QACS;CACT,IAAI,MAAM,OAAO,SAAS,OAAO,WAC/B,OAAO;CAET,MAAM,QAAQ,IAAI,cAAc;CAChC,OAAO;AACT;AAEA,SAAS,mBAAmB,OAAuB;CACjD,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC;AACtC"}
@@ -0,0 +1,45 @@
1
+ import { AgentEvent } from "../session/events.js";
2
+ import { AgentRun } from "../session/run.js";
3
+ import { CloudflareAlarmContinuationReason, CloudflareAlarmDrainBudget, FailedScheduledWork } from "./cloudflare-alarm-budget.js";
4
+ import { CloudflareDurableObjectStorage } from "./cloudflare-host.js";
5
+
6
+ //#region src/cloudflare/cloudflare-alarm-drainer.d.ts
7
+ interface CloudflareAlarmDrainSummary {
8
+ readonly consumedSessionPrompts: readonly string[];
9
+ readonly continuationReasons: readonly CloudflareAlarmContinuationReason[];
10
+ readonly continuationScheduled: boolean;
11
+ readonly droppedEvents: number;
12
+ readonly events: readonly AgentEvent[];
13
+ readonly failedRuns: readonly FailedScheduledWork[];
14
+ readonly failedSessionPrompts: readonly FailedScheduledWork[];
15
+ readonly markers: readonly string[];
16
+ readonly remainingRuns: number;
17
+ readonly remainingSessionPrompts: number;
18
+ readonly resumedRuns: readonly string[];
19
+ }
20
+ interface CloudflareAlarmAgent {
21
+ resume(runId: string): Promise<AgentRun | null>;
22
+ }
23
+ declare class CloudflareAlarmDrainFailureError extends Error {
24
+ readonly summary: CloudflareAlarmDrainSummary;
25
+ constructor(summary: CloudflareAlarmDrainSummary);
26
+ }
27
+ declare function drainCloudflareAlarm({
28
+ agent,
29
+ continuationRunAfterMs,
30
+ deadlineMs,
31
+ failureRunAfterMs,
32
+ maxEvents,
33
+ maxRuns,
34
+ maxSessionPrompts,
35
+ prefix,
36
+ storage,
37
+ throwOnFailure
38
+ }: {
39
+ readonly agent: CloudflareAlarmAgent;
40
+ readonly prefix: string;
41
+ readonly storage: CloudflareDurableObjectStorage;
42
+ } & CloudflareAlarmDrainBudget): Promise<CloudflareAlarmDrainSummary>;
43
+ //#endregion
44
+ export { CloudflareAlarmAgent, CloudflareAlarmDrainFailureError, CloudflareAlarmDrainSummary, drainCloudflareAlarm };
45
+ //# sourceMappingURL=cloudflare-alarm-drainer.d.ts.map