@minpeter/pss-runtime 0.1.0-next.2 → 0.1.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -78
- package/dist/agent-host-session-store.js +2 -4
- package/dist/agent-host-session-store.js.map +1 -1
- package/dist/agent-loop.js +2 -3
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent-namespace.js +3 -7
- package/dist/agent-namespace.js.map +1 -1
- package/dist/agent-options.d.ts +2 -8
- package/dist/agent-options.js +4 -4
- package/dist/agent-options.js.map +1 -1
- package/dist/agent-resume.js +2 -82
- package/dist/agent-resume.js.map +1 -1
- package/dist/agent-session-entry.d.ts +1 -1
- package/dist/agent.d.ts +4 -4
- package/dist/agent.js +16 -70
- package/dist/agent.js.map +1 -1
- package/dist/cloudflare/cloudflare-agent-context.d.ts +40 -0
- package/dist/cloudflare/cloudflare-agent-context.js +37 -0
- package/dist/cloudflare/cloudflare-agent-context.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-budget.d.ts +18 -0
- package/dist/cloudflare/cloudflare-alarm-budget.js +77 -0
- package/dist/cloudflare/cloudflare-alarm-budget.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.d.ts +45 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.js +103 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.d.ts +13 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.js +81 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-work.js +110 -0
- package/dist/cloudflare/cloudflare-alarm-work.js.map +1 -0
- package/dist/cloudflare/cloudflare-checkpoint-store.js +39 -0
- package/dist/cloudflare/cloudflare-checkpoint-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.d.ts +21 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.js +11 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.js.map +1 -0
- package/dist/cloudflare/cloudflare-event-store.js +33 -0
- package/dist/cloudflare/cloudflare-event-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-execution-session-store.js +40 -0
- package/dist/cloudflare/cloudflare-execution-session-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-execution-store.js +35 -0
- package/dist/cloudflare/cloudflare-execution-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-host.d.ts +61 -0
- package/dist/cloudflare/cloudflare-host.js +113 -0
- package/dist/cloudflare/cloudflare-host.js.map +1 -0
- package/dist/cloudflare/cloudflare-notification-store.js +59 -0
- package/dist/cloudflare/cloudflare-notification-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-run-store.js +81 -0
- package/dist/cloudflare/cloudflare-run-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-store-utils.js +43 -0
- package/dist/cloudflare/cloudflare-store-utils.js.map +1 -0
- package/dist/cloudflare/durable-object-storage.d.ts +20 -0
- package/dist/cloudflare/durable-object-storage.js +76 -0
- package/dist/cloudflare/durable-object-storage.js.map +1 -0
- package/dist/cloudflare/index.d.ts +7 -0
- package/dist/cloudflare/index.js +6 -0
- package/dist/execution/capabilities.d.ts +40 -0
- package/dist/execution/host.d.ts +9 -0
- package/dist/execution/host.js +49 -1
- package/dist/execution/host.js.map +1 -1
- package/dist/execution/index.d.ts +3 -1
- package/dist/execution/index.js +2 -1
- package/dist/execution/memory.js +1 -1
- package/dist/execution/memory.js.map +1 -1
- package/dist/execution/types.d.ts +5 -10
- package/dist/index.d.ts +8 -4
- package/dist/index.js +6 -1
- package/dist/plugins.d.ts +25 -3
- package/dist/plugins.js +35 -6
- package/dist/plugins.js.map +1 -1
- package/dist/session/delegate-input.d.ts +9 -0
- package/dist/session/delegate-input.js +16 -0
- package/dist/session/delegate-input.js.map +1 -0
- package/dist/session/events.d.ts +43 -25
- package/dist/session/events.js +41 -0
- package/dist/session/events.js.map +1 -0
- package/dist/session/input-meta-types.d.ts +10 -0
- package/dist/session/input-meta.d.ts +13 -0
- package/dist/session/input-meta.js +45 -0
- package/dist/session/input-meta.js.map +1 -0
- package/dist/session/input.d.ts +4 -0
- package/dist/session/mapping.js +4 -2
- package/dist/session/mapping.js.map +1 -1
- package/dist/session/runtime-input-emit.js +41 -0
- package/dist/session/runtime-input-emit.js.map +1 -0
- package/dist/session/runtime-input.js +5 -1
- package/dist/session/runtime-input.js.map +1 -1
- package/dist/session/session-events.js +20 -6
- package/dist/session/session-events.js.map +1 -1
- package/dist/session/session-notification.js +3 -2
- package/dist/session/session-notification.js.map +1 -1
- package/dist/session/session-runtime-drain.js +3 -9
- package/dist/session/session-runtime-drain.js.map +1 -1
- package/dist/session/session-turn-processor.js +7 -17
- package/dist/session/session-turn-processor.js.map +1 -1
- package/dist/session/session.js +11 -4
- package/dist/session/session.js.map +1 -1
- package/package.json +6 -1
- package/dist/agent-child-runs.js +0 -16
- package/dist/agent-child-runs.js.map +0 -1
- package/dist/agent-host-capabilities.js +0 -9
- package/dist/agent-host-capabilities.js.map +0 -1
- package/dist/agent-validation.js +0 -35
- package/dist/agent-validation.js.map +0 -1
- package/dist/child-session-cleanups.js +0 -61
- package/dist/child-session-cleanups.js.map +0 -1
- package/dist/execution/run.js +0 -55
- package/dist/execution/run.js.map +0 -1
- package/dist/subagent-background-child-run-state.js +0 -51
- package/dist/subagent-background-child-run-state.js.map +0 -1
- package/dist/subagent-background-child-run.js +0 -103
- package/dist/subagent-background-child-run.js.map +0 -1
- package/dist/subagent-background-in-process.js +0 -98
- package/dist/subagent-background-in-process.js.map +0 -1
- package/dist/subagent-background-notification-inbox.js +0 -106
- package/dist/subagent-background-notification-inbox.js.map +0 -1
- package/dist/subagent-background-notify.js +0 -136
- package/dist/subagent-background-notify.js.map +0 -1
- package/dist/subagent-background-resume-group.js +0 -99
- package/dist/subagent-background-resume-group.js.map +0 -1
- package/dist/subagent-background-runner.js +0 -115
- package/dist/subagent-background-runner.js.map +0 -1
- package/dist/subagent-background-schedule.js +0 -43
- package/dist/subagent-background-schedule.js.map +0 -1
- package/dist/subagent-child-run.js +0 -68
- package/dist/subagent-child-run.js.map +0 -1
- package/dist/subagent-job-cancel.js +0 -84
- package/dist/subagent-job-cancel.js.map +0 -1
- package/dist/subagent-job-observer.js +0 -19
- package/dist/subagent-job-observer.js.map +0 -1
- package/dist/subagent-job-output.js +0 -87
- package/dist/subagent-job-output.js.map +0 -1
- package/dist/subagent-job-state.js +0 -66
- package/dist/subagent-job-state.js.map +0 -1
- package/dist/subagent-jobs.js +0 -96
- package/dist/subagent-jobs.js.map +0 -1
- package/dist/subagent-prompt-schema.js +0 -114
- package/dist/subagent-prompt-schema.js.map +0 -1
- package/dist/subagent-run.js +0 -111
- package/dist/subagent-run.js.map +0 -1
- package/dist/subagents.js +0 -125
- package/dist/subagents.js.map +0 -1
package/dist/agent-resume.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-resume.js","names":[],"sources":["../src/agent-resume.ts"],"sourcesContent":["import { ownsAgentNamespace } from \"./agent-namespace\";\nimport
|
|
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
|
|
11
|
-
readonly
|
|
12
|
-
constructor(options:
|
|
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,46 +1,33 @@
|
|
|
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 {
|
|
6
|
-
import { assertAgentOptions, hasRuntimeModel } from "./agent-options.js";
|
|
3
|
+
import { stableAgentNamespace } from "./agent-namespace.js";
|
|
4
|
+
import { assertAgentOptions, hasLanguageModel, hasRuntimeModel } 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
7
|
import { createLlm } from "./llm.js";
|
|
12
8
|
import { AgentSession } from "./session/session.js";
|
|
13
|
-
import { createSubagentTools } from "./subagents.js";
|
|
14
9
|
//#region src/agent.ts
|
|
15
|
-
var Agent = class
|
|
10
|
+
var Agent = class {
|
|
16
11
|
#baseTools;
|
|
17
12
|
#llm;
|
|
18
13
|
#modelOptions;
|
|
19
|
-
#childSessionCleanups = new ChildSessionCleanups();
|
|
20
|
-
#sessionGenerations = /* @__PURE__ */ new Map();
|
|
21
14
|
#sessions = /* @__PURE__ */ new Map();
|
|
22
15
|
#sessionNamespace;
|
|
23
16
|
#store;
|
|
24
17
|
#host;
|
|
25
18
|
#plugins;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
name;
|
|
19
|
+
host;
|
|
20
|
+
namespace;
|
|
29
21
|
constructor(options) {
|
|
30
22
|
assertAgentOptions(options);
|
|
31
|
-
this.
|
|
32
|
-
this
|
|
33
|
-
this.#sessionNamespace = stableAgentNamespace({
|
|
34
|
-
name: options.name,
|
|
35
|
-
namespace: options.namespace
|
|
36
|
-
});
|
|
23
|
+
this.namespace = options.namespace;
|
|
24
|
+
this.#sessionNamespace = stableAgentNamespace({ namespace: options.namespace });
|
|
37
25
|
this.#host = options.host ?? createInMemoryExecutionHost();
|
|
26
|
+
this.host = this.#host;
|
|
38
27
|
this.#store = sessionStoreForHost(this.#host);
|
|
39
28
|
this.#plugins = options.plugins ?? [];
|
|
40
|
-
assertSubagents(options, Agent, hasRuntimeModel(options));
|
|
41
|
-
this.#subagents = hasRuntimeModel(options) ? [] : options.subagents ?? [];
|
|
42
29
|
if (hasRuntimeModel(options)) this.#llm = options.model;
|
|
43
|
-
else {
|
|
30
|
+
else if (hasLanguageModel(options)) {
|
|
44
31
|
this.#baseTools = options.tools;
|
|
45
32
|
this.#modelOptions = {
|
|
46
33
|
instructions: options.instructions,
|
|
@@ -59,8 +46,7 @@ var Agent = class Agent {
|
|
|
59
46
|
host,
|
|
60
47
|
ownerNamespace: this.#sessionNamespace,
|
|
61
48
|
resumeNotification: (notification) => this.#resumeNotification(notification),
|
|
62
|
-
runId
|
|
63
|
-
subagents: this.#subagents
|
|
49
|
+
runId
|
|
64
50
|
});
|
|
65
51
|
}
|
|
66
52
|
session(key) {
|
|
@@ -70,16 +56,7 @@ var Agent = class Agent {
|
|
|
70
56
|
const existing = this.#sessions.get(key);
|
|
71
57
|
if (existing) return existing;
|
|
72
58
|
let session;
|
|
73
|
-
|
|
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)), {
|
|
59
|
+
session = new AgentSession(this.#llm ?? createLlm(this.#createLlmOptionsForSession()), {
|
|
83
60
|
key,
|
|
84
61
|
store: this.#store
|
|
85
62
|
}, this.#plugins, { executionHost: executionHost(this.#host) });
|
|
@@ -88,18 +65,15 @@ var Agent = class Agent {
|
|
|
88
65
|
publicHandle: {
|
|
89
66
|
delete: async () => {
|
|
90
67
|
session.kill();
|
|
91
|
-
await this.#cancelDurableChildRunsBeforeLocalCleanup(key, parentAgentNamespace);
|
|
92
68
|
this.#evictSessionHandle(key);
|
|
93
69
|
await session.delete();
|
|
94
|
-
await this.#childSessionCleanups.delete(key);
|
|
95
70
|
},
|
|
96
|
-
|
|
97
|
-
kill: async () => {
|
|
71
|
+
dispose: () => {
|
|
98
72
|
session.kill();
|
|
99
|
-
await this.#cancelDurableChildRunsBeforeLocalCleanup(key, parentAgentNamespace);
|
|
100
73
|
this.#evictSessionHandle(key);
|
|
101
|
-
|
|
74
|
+
return Promise.resolve();
|
|
102
75
|
},
|
|
76
|
+
interrupt: () => session.interrupt(),
|
|
103
77
|
send: (input) => session.send(input),
|
|
104
78
|
steer: (input) => session.steer(input)
|
|
105
79
|
}
|
|
@@ -107,48 +81,20 @@ var Agent = class Agent {
|
|
|
107
81
|
this.#sessions.set(key, entry);
|
|
108
82
|
return entry;
|
|
109
83
|
}
|
|
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
84
|
#evictSessionHandle(key) {
|
|
119
85
|
this.#sessions.delete(key);
|
|
120
|
-
this.#sessionGenerations.set(key, (this.#sessionGenerations.get(key) ?? 0) + 1);
|
|
121
86
|
}
|
|
122
87
|
#resumeNotification(notification) {
|
|
123
88
|
return this.#sessionEntry(notification.sessionKey).notify(notification.input, { observerEvents: notification.observerEvents });
|
|
124
89
|
}
|
|
125
|
-
#createLlmOptionsForSession(
|
|
90
|
+
#createLlmOptionsForSession() {
|
|
126
91
|
const modelOptions = this.#modelOptions;
|
|
127
92
|
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
93
|
return {
|
|
148
94
|
instructions: modelOptions.instructions,
|
|
149
95
|
model: modelOptions.model,
|
|
150
96
|
toolChoice: modelOptions.toolChoice,
|
|
151
|
-
tools
|
|
97
|
+
tools: this.#baseTools
|
|
152
98
|
};
|
|
153
99
|
}
|
|
154
100
|
};
|
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":["#baseTools","#llm","#modelOptions","#sessions","#sessionNamespace","#store","#host","#plugins","#resumeNotification","#sessionEntry","#createLlmOptionsForSession","#evictSessionHandle"],"sources":["../src/agent.ts"],"sourcesContent":["import type { ToolSet } from \"ai\";\nimport { sessionStoreForHost } from \"./agent-host-session-store\";\nimport { stableAgentNamespace } from \"./agent-namespace\";\nimport {\n type AgentConstructionOptions,\n type AgentModelOptions,\n assertAgentOptions,\n hasLanguageModel,\n hasRuntimeModel,\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 { createLlm, type RuntimeLlm } from \"./llm\";\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 #baseTools?: ToolSet;\n readonly #llm?: RuntimeLlm;\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 if (hasRuntimeModel(options)) {\n this.#llm = options.model;\n } else if (hasLanguageModel(options)) {\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 });\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 llm = this.#llm ?? createLlm(this.#createLlmOptionsForSession());\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 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 #createLlmOptionsForSession(): Parameters<typeof createLlm>[0] {\n const modelOptions = this.#modelOptions;\n if (!modelOptions) {\n throw new Error(\"Agent: missing model options.\");\n }\n\n return {\n instructions: modelOptions.instructions,\n model: modelOptions.model,\n toolChoice: modelOptions.toolChoice,\n tools: this.#baseTools,\n };\n }\n}\n"],"mappings":";;;;;;;;;AAyBA,IAAa,QAAb,MAAmB;CACjB;CACA;CACA;CACA,4BAAqB,IAAI,IAA+B;CACxD;CACA;CACA;CACA;CACA;CACA;CACA,YAAY,SAAmC;EAC7C,mBAAmB,OAAO;EAE1B,KAAK,YAAY,QAAQ;EACzB,KAAKI,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,IAAI,gBAAgB,OAAO,GACzB,KAAKN,OAAO,QAAQ;OACf,IAAI,iBAAiB,OAAO,GAAG;GACpC,KAAKD,aAAa,QAAQ;GAC1B,KAAKE,gBAAgB;IACnB,cAAc,QAAQ;IACtB,OAAO,QAAQ;IACf,YAAY,QAAQ;GACtB;EACF;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;EAEJ,UAAU,IAAI,aADF,KAAKF,QAAQ,UAAU,KAAKS,4BAA4B,CAAC,GAGnE;GAAE;GAAK,OAAO,KAAKL;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,KAAKK,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,KAAKR,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;CAEA,8BAA+D;EAC7D,MAAM,eAAe,KAAKP;EAC1B,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,+BAA+B;EAGjD,OAAO;GACL,cAAc,aAAa;GAC3B,OAAO,aAAa;GACpB,YAAY,aAAa;GACzB,OAAO,KAAKF;EACd;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
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createAlarmDrainState, normalizeAlarmDrainBudget, shouldStopRuns, shouldStopSessionPrompts } from "./cloudflare-alarm-budget.js";
|
|
2
|
+
import { listScheduledCloudflareRuns, listScheduledCloudflareSessionPrompts, rescheduleCloudflareAlarm } from "./cloudflare-host.js";
|
|
3
|
+
import { resumeScheduledRun, resumeScheduledSessionPrompt } from "./cloudflare-alarm-work.js";
|
|
4
|
+
//#region src/cloudflare/cloudflare-alarm-drainer.ts
|
|
5
|
+
var CloudflareAlarmDrainFailureError = class extends Error {
|
|
6
|
+
summary;
|
|
7
|
+
constructor(summary) {
|
|
8
|
+
super("Cloudflare alarm drain completed with failed scheduled work.");
|
|
9
|
+
this.name = "CloudflareAlarmDrainFailureError";
|
|
10
|
+
this.summary = summary;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
async function drainCloudflareAlarm({ agent, continuationRunAfterMs, deadlineMs, failureRunAfterMs, maxEvents, maxRuns, maxSessionPrompts, prefix, storage, throwOnFailure }) {
|
|
14
|
+
const budget = normalizeAlarmDrainBudget({
|
|
15
|
+
continuationRunAfterMs,
|
|
16
|
+
deadlineMs,
|
|
17
|
+
failureRunAfterMs,
|
|
18
|
+
maxEvents,
|
|
19
|
+
maxRuns,
|
|
20
|
+
maxSessionPrompts,
|
|
21
|
+
throwOnFailure
|
|
22
|
+
});
|
|
23
|
+
const state = createAlarmDrainState();
|
|
24
|
+
await drainRuns({
|
|
25
|
+
agent,
|
|
26
|
+
budget,
|
|
27
|
+
prefix,
|
|
28
|
+
state,
|
|
29
|
+
storage
|
|
30
|
+
});
|
|
31
|
+
await drainSessionPrompts({
|
|
32
|
+
agent,
|
|
33
|
+
budget,
|
|
34
|
+
prefix,
|
|
35
|
+
state,
|
|
36
|
+
storage
|
|
37
|
+
});
|
|
38
|
+
const summary = await summarizeDrain({
|
|
39
|
+
budget,
|
|
40
|
+
prefix,
|
|
41
|
+
state,
|
|
42
|
+
storage
|
|
43
|
+
});
|
|
44
|
+
if (budget.throwOnFailure && hasFailures(summary)) throw new CloudflareAlarmDrainFailureError(summary);
|
|
45
|
+
return summary;
|
|
46
|
+
}
|
|
47
|
+
async function drainRuns(options) {
|
|
48
|
+
for (const runId of await listScheduledCloudflareRuns(options.storage, { prefix: options.prefix })) {
|
|
49
|
+
if (shouldStopRuns(options.state, options.budget)) break;
|
|
50
|
+
options.state.runAttempts += 1;
|
|
51
|
+
await resumeScheduledRun({
|
|
52
|
+
...options,
|
|
53
|
+
runId
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function drainSessionPrompts(options) {
|
|
58
|
+
const prompts = await listScheduledCloudflareSessionPrompts(options.storage, { prefix: options.prefix });
|
|
59
|
+
for (const prompt of prompts) {
|
|
60
|
+
if (shouldStopSessionPrompts(options.state, options.budget)) break;
|
|
61
|
+
options.state.sessionPromptAttempts += 1;
|
|
62
|
+
await resumeScheduledSessionPrompt({
|
|
63
|
+
...options,
|
|
64
|
+
prompt
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function summarizeDrain({ budget, prefix, state, storage }) {
|
|
69
|
+
const remainingRuns = await listScheduledCloudflareRuns(storage, { prefix });
|
|
70
|
+
const remainingPrompts = await listScheduledCloudflareSessionPrompts(storage, { prefix });
|
|
71
|
+
if (state.failedRuns.length > 0 || state.failedSessionPrompts.length > 0) state.reasons.add("failure");
|
|
72
|
+
const continuationScheduled = shouldRearm(state, remainingRuns.length, remainingPrompts.length);
|
|
73
|
+
if (continuationScheduled) await rescheduleCloudflareAlarm(storage, { runAfterMs: state.reasons.has("failure") ? budget.failureRunAfterMs : budget.continuationRunAfterMs });
|
|
74
|
+
return {
|
|
75
|
+
consumedSessionPrompts: state.consumedSessionPrompts,
|
|
76
|
+
continuationReasons: [...state.reasons],
|
|
77
|
+
continuationScheduled,
|
|
78
|
+
droppedEvents: state.droppedEvents,
|
|
79
|
+
events: state.events,
|
|
80
|
+
failedRuns: state.failedRuns,
|
|
81
|
+
failedSessionPrompts: state.failedSessionPrompts,
|
|
82
|
+
markers: markersFor(state.reasons),
|
|
83
|
+
remainingRuns: remainingRuns.length,
|
|
84
|
+
remainingSessionPrompts: remainingPrompts.length,
|
|
85
|
+
resumedRuns: state.resumedRuns
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function shouldRearm(state, remainingRuns, remainingPrompts) {
|
|
89
|
+
return state.reasons.size > 0 && (remainingRuns > 0 || remainingPrompts > 0 || state.reasons.has("failure"));
|
|
90
|
+
}
|
|
91
|
+
function hasFailures(summary) {
|
|
92
|
+
return summary.failedRuns.length > 0 || summary.failedSessionPrompts.length > 0;
|
|
93
|
+
}
|
|
94
|
+
function markersFor(reasons) {
|
|
95
|
+
const markers = ["alarm:resume", "resume:session-prompt"];
|
|
96
|
+
if (reasons.size > 0) markers.push("alarm:continuation-rearm");
|
|
97
|
+
if (reasons.has("failure")) markers.push("alarm:failure");
|
|
98
|
+
return markers;
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { CloudflareAlarmDrainFailureError, drainCloudflareAlarm };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=cloudflare-alarm-drainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-alarm-drainer.js","names":[],"sources":["../../src/cloudflare/cloudflare-alarm-drainer.ts"],"sourcesContent":["import type { AgentEvent, AgentRun } from \"../index\";\nimport {\n type AlarmDrainState,\n type CloudflareAlarmContinuationReason,\n type CloudflareAlarmDrainBudget,\n createAlarmDrainState,\n type FailedScheduledWork,\n type NormalizedAlarmDrainBudget,\n normalizeAlarmDrainBudget,\n shouldStopRuns,\n shouldStopSessionPrompts,\n} from \"./cloudflare-alarm-budget\";\nimport {\n resumeScheduledRun,\n resumeScheduledSessionPrompt,\n} from \"./cloudflare-alarm-work\";\nimport {\n type CloudflareDurableObjectStorage,\n listScheduledCloudflareRuns,\n listScheduledCloudflareSessionPrompts,\n rescheduleCloudflareAlarm,\n} from \"./cloudflare-host\";\n\nexport type {\n CloudflareAlarmContinuationReason,\n CloudflareAlarmDrainBudget,\n FailedScheduledWork,\n} from \"./cloudflare-alarm-budget\";\n\nexport interface CloudflareAlarmDrainSummary {\n readonly consumedSessionPrompts: readonly string[];\n readonly continuationReasons: readonly CloudflareAlarmContinuationReason[];\n readonly continuationScheduled: boolean;\n readonly droppedEvents: number;\n readonly events: readonly AgentEvent[];\n readonly failedRuns: readonly FailedScheduledWork[];\n readonly failedSessionPrompts: readonly FailedScheduledWork[];\n readonly markers: readonly string[];\n readonly remainingRuns: number;\n readonly remainingSessionPrompts: number;\n readonly resumedRuns: readonly string[];\n}\n\nexport interface CloudflareAlarmAgent {\n resume(runId: string): Promise<AgentRun | null>;\n}\n\nexport class CloudflareAlarmDrainFailureError extends Error {\n readonly summary: CloudflareAlarmDrainSummary;\n\n constructor(summary: CloudflareAlarmDrainSummary) {\n super(\"Cloudflare alarm drain completed with failed scheduled work.\");\n this.name = \"CloudflareAlarmDrainFailureError\";\n this.summary = summary;\n }\n}\n\nexport async function drainCloudflareAlarm({\n agent,\n continuationRunAfterMs,\n deadlineMs,\n failureRunAfterMs,\n maxEvents,\n maxRuns,\n maxSessionPrompts,\n prefix,\n storage,\n throwOnFailure,\n}: {\n readonly agent: CloudflareAlarmAgent;\n readonly prefix: string;\n readonly storage: CloudflareDurableObjectStorage;\n} & CloudflareAlarmDrainBudget): Promise<CloudflareAlarmDrainSummary> {\n const budget = normalizeAlarmDrainBudget({\n continuationRunAfterMs,\n deadlineMs,\n failureRunAfterMs,\n maxEvents,\n maxRuns,\n maxSessionPrompts,\n throwOnFailure,\n });\n const state = createAlarmDrainState();\n\n await drainRuns({ agent, budget, prefix, state, storage });\n await drainSessionPrompts({ agent, budget, prefix, state, storage });\n\n const summary = await summarizeDrain({ budget, prefix, state, storage });\n if (budget.throwOnFailure && hasFailures(summary)) {\n throw new CloudflareAlarmDrainFailureError(summary);\n }\n return summary;\n}\n\nasync function drainRuns(options: DrainLoopOptions): Promise<void> {\n for (const runId of await listScheduledCloudflareRuns(options.storage, {\n prefix: options.prefix,\n })) {\n if (shouldStopRuns(options.state, options.budget)) {\n break;\n }\n options.state.runAttempts += 1;\n await resumeScheduledRun({ ...options, runId });\n }\n}\n\nasync function drainSessionPrompts(options: DrainLoopOptions): Promise<void> {\n const prompts = await listScheduledCloudflareSessionPrompts(options.storage, {\n prefix: options.prefix,\n });\n for (const prompt of prompts) {\n if (shouldStopSessionPrompts(options.state, options.budget)) {\n break;\n }\n options.state.sessionPromptAttempts += 1;\n await resumeScheduledSessionPrompt({ ...options, prompt });\n }\n}\n\nasync function summarizeDrain({\n budget,\n prefix,\n state,\n storage,\n}: {\n readonly budget: NormalizedAlarmDrainBudget;\n readonly prefix: string;\n readonly state: AlarmDrainState;\n readonly storage: CloudflareDurableObjectStorage;\n}): Promise<CloudflareAlarmDrainSummary> {\n const remainingRuns = await listScheduledCloudflareRuns(storage, { prefix });\n const remainingPrompts = await listScheduledCloudflareSessionPrompts(\n storage,\n {\n prefix,\n }\n );\n if (state.failedRuns.length > 0 || state.failedSessionPrompts.length > 0) {\n state.reasons.add(\"failure\");\n }\n const continuationScheduled = shouldRearm(\n state,\n remainingRuns.length,\n remainingPrompts.length\n );\n if (continuationScheduled) {\n await rescheduleCloudflareAlarm(storage, {\n runAfterMs: state.reasons.has(\"failure\")\n ? budget.failureRunAfterMs\n : budget.continuationRunAfterMs,\n });\n }\n return {\n consumedSessionPrompts: state.consumedSessionPrompts,\n continuationReasons: [...state.reasons],\n continuationScheduled,\n droppedEvents: state.droppedEvents,\n events: state.events,\n failedRuns: state.failedRuns,\n failedSessionPrompts: state.failedSessionPrompts,\n markers: markersFor(state.reasons),\n remainingRuns: remainingRuns.length,\n remainingSessionPrompts: remainingPrompts.length,\n resumedRuns: state.resumedRuns,\n };\n}\n\ninterface DrainLoopOptions {\n readonly agent: CloudflareAlarmAgent;\n readonly budget: NormalizedAlarmDrainBudget;\n readonly prefix: string;\n readonly state: AlarmDrainState;\n readonly storage: CloudflareDurableObjectStorage;\n}\n\nfunction shouldRearm(\n state: AlarmDrainState,\n remainingRuns: number,\n remainingPrompts: number\n): boolean {\n return (\n state.reasons.size > 0 &&\n (remainingRuns > 0 || remainingPrompts > 0 || state.reasons.has(\"failure\"))\n );\n}\n\nfunction hasFailures(summary: CloudflareAlarmDrainSummary): boolean {\n return (\n summary.failedRuns.length > 0 || summary.failedSessionPrompts.length > 0\n );\n}\n\nfunction markersFor(\n reasons: ReadonlySet<CloudflareAlarmContinuationReason>\n): readonly string[] {\n const markers = [\"alarm:resume\", \"resume:session-prompt\"];\n if (reasons.size > 0) {\n markers.push(\"alarm:continuation-rearm\");\n }\n if (reasons.has(\"failure\")) {\n markers.push(\"alarm:failure\");\n }\n return markers;\n}\n"],"mappings":";;;;AA+CA,IAAa,mCAAb,cAAsD,MAAM;CAC1D;CAEA,YAAY,SAAsC;EAChD,MAAM,8DAA8D;EACpE,KAAK,OAAO;EACZ,KAAK,UAAU;CACjB;AACF;AAEA,eAAsB,qBAAqB,EACzC,OACA,wBACA,YACA,mBACA,WACA,SACA,mBACA,QACA,SACA,kBAKoE;CACpE,MAAM,SAAS,0BAA0B;EACvC;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,QAAQ,sBAAsB;CAEpC,MAAM,UAAU;EAAE;EAAO;EAAQ;EAAQ;EAAO;CAAQ,CAAC;CACzD,MAAM,oBAAoB;EAAE;EAAO;EAAQ;EAAQ;EAAO;CAAQ,CAAC;CAEnE,MAAM,UAAU,MAAM,eAAe;EAAE;EAAQ;EAAQ;EAAO;CAAQ,CAAC;CACvE,IAAI,OAAO,kBAAkB,YAAY,OAAO,GAC9C,MAAM,IAAI,iCAAiC,OAAO;CAEpD,OAAO;AACT;AAEA,eAAe,UAAU,SAA0C;CACjE,KAAK,MAAM,SAAS,MAAM,4BAA4B,QAAQ,SAAS,EACrE,QAAQ,QAAQ,OAClB,CAAC,GAAG;EACF,IAAI,eAAe,QAAQ,OAAO,QAAQ,MAAM,GAC9C;EAEF,QAAQ,MAAM,eAAe;EAC7B,MAAM,mBAAmB;GAAE,GAAG;GAAS;EAAM,CAAC;CAChD;AACF;AAEA,eAAe,oBAAoB,SAA0C;CAC3E,MAAM,UAAU,MAAM,sCAAsC,QAAQ,SAAS,EAC3E,QAAQ,QAAQ,OAClB,CAAC;CACD,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,yBAAyB,QAAQ,OAAO,QAAQ,MAAM,GACxD;EAEF,QAAQ,MAAM,yBAAyB;EACvC,MAAM,6BAA6B;GAAE,GAAG;GAAS;EAAO,CAAC;CAC3D;AACF;AAEA,eAAe,eAAe,EAC5B,QACA,QACA,OACA,WAMuC;CACvC,MAAM,gBAAgB,MAAM,4BAA4B,SAAS,EAAE,OAAO,CAAC;CAC3E,MAAM,mBAAmB,MAAM,sCAC7B,SACA,EACE,OACF,CACF;CACA,IAAI,MAAM,WAAW,SAAS,KAAK,MAAM,qBAAqB,SAAS,GACrE,MAAM,QAAQ,IAAI,SAAS;CAE7B,MAAM,wBAAwB,YAC5B,OACA,cAAc,QACd,iBAAiB,MACnB;CACA,IAAI,uBACF,MAAM,0BAA0B,SAAS,EACvC,YAAY,MAAM,QAAQ,IAAI,SAAS,IACnC,OAAO,oBACP,OAAO,uBACb,CAAC;CAEH,OAAO;EACL,wBAAwB,MAAM;EAC9B,qBAAqB,CAAC,GAAG,MAAM,OAAO;EACtC;EACA,eAAe,MAAM;EACrB,QAAQ,MAAM;EACd,YAAY,MAAM;EAClB,sBAAsB,MAAM;EAC5B,SAAS,WAAW,MAAM,OAAO;EACjC,eAAe,cAAc;EAC7B,yBAAyB,iBAAiB;EAC1C,aAAa,MAAM;CACrB;AACF;AAUA,SAAS,YACP,OACA,eACA,kBACS;CACT,OACE,MAAM,QAAQ,OAAO,MACpB,gBAAgB,KAAK,mBAAmB,KAAK,MAAM,QAAQ,IAAI,SAAS;AAE7E;AAEA,SAAS,YAAY,SAA+C;CAClE,OACE,QAAQ,WAAW,SAAS,KAAK,QAAQ,qBAAqB,SAAS;AAE3E;AAEA,SAAS,WACP,SACmB;CACnB,MAAM,UAAU,CAAC,gBAAgB,uBAAuB;CACxD,IAAI,QAAQ,OAAO,GACjB,QAAQ,KAAK,0BAA0B;CAEzC,IAAI,QAAQ,IAAI,SAAS,GACvB,QAAQ,KAAK,eAAe;CAE9B,OAAO;AACT"}
|