@earendil-works/pi-durable 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +227 -0
- package/README.md +287 -82
- package/dist/codemode/codemode.d.ts +4 -4
- package/dist/codemode/codemode.d.ts.map +1 -1
- package/dist/codemode/codemode.js +21 -16
- package/dist/codemode/codemode.js.map +1 -1
- package/dist/codemode/models.d.ts.map +1 -1
- package/dist/codemode/models.js +6 -4
- package/dist/codemode/models.js.map +1 -1
- package/dist/documents.d.ts +1 -1
- package/dist/documents.d.ts.map +1 -1
- package/dist/documents.js.map +1 -1
- package/dist/env/index.d.ts +12 -10
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js.map +1 -1
- package/dist/env/node-watch.d.ts +3 -3
- package/dist/env/node-watch.d.ts.map +1 -1
- package/dist/env/node-watch.js +18 -16
- package/dist/env/node-watch.js.map +1 -1
- package/dist/env/node.d.ts +2 -2
- package/dist/env/node.d.ts.map +1 -1
- package/dist/env/node.js +12 -4
- package/dist/env/node.js.map +1 -1
- package/dist/errors.d.ts +18 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +26 -3
- package/dist/errors.js.map +1 -1
- package/dist/harness/agent.d.ts +13 -2
- package/dist/harness/agent.d.ts.map +1 -1
- package/dist/harness/agent.js +48 -6
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/compaction.d.ts +3 -1
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +38 -6
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/context.d.ts +23 -7
- package/dist/harness/context.d.ts.map +1 -1
- package/dist/harness/context.js +71 -25
- package/dist/harness/context.js.map +1 -1
- package/dist/harness/define.d.ts +7 -3
- package/dist/harness/define.d.ts.map +1 -1
- package/dist/harness/define.js +4 -0
- package/dist/harness/define.js.map +1 -1
- package/dist/harness/generation.d.ts +38 -5
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +497 -108
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts +7 -2
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +147 -57
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +7 -3
- package/dist/harness/inbox.d.ts.map +1 -1
- package/dist/harness/inbox.js +7 -4
- package/dist/harness/inbox.js.map +1 -1
- package/dist/harness/json.d.ts +20 -4
- package/dist/harness/json.d.ts.map +1 -1
- package/dist/harness/json.js +23 -5
- package/dist/harness/json.js.map +1 -1
- package/dist/harness/live.d.ts +122 -16
- package/dist/harness/live.d.ts.map +1 -1
- package/dist/harness/live.js +93 -12
- package/dist/harness/live.js.map +1 -1
- package/dist/harness/partial-changes.d.ts +54 -0
- package/dist/harness/partial-changes.d.ts.map +1 -0
- package/dist/harness/partial-changes.js +162 -0
- package/dist/harness/partial-changes.js.map +1 -0
- package/dist/harness/prompt.d.ts +1 -1
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +1 -1
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/registry-reader.d.ts +11 -0
- package/dist/harness/registry-reader.d.ts.map +1 -0
- package/dist/harness/registry-reader.js +25 -0
- package/dist/harness/registry-reader.js.map +1 -0
- package/dist/harness/scheduler.d.ts +86 -14
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +1459 -369
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +23 -11
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +104 -36
- package/dist/harness/submissions.js.map +1 -1
- package/dist/harness/task-graph.d.ts +28 -8
- package/dist/harness/task-graph.d.ts.map +1 -1
- package/dist/harness/task-graph.js +85 -36
- package/dist/harness/task-graph.js.map +1 -1
- package/dist/harness/telemetry.d.ts +307 -0
- package/dist/harness/telemetry.d.ts.map +1 -0
- package/dist/harness/telemetry.js +136 -0
- package/dist/harness/telemetry.js.map +1 -0
- package/dist/harness/tool.d.ts +2 -0
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +223 -61
- package/dist/harness/tool.js.map +1 -1
- package/dist/harness/transcript.d.ts +72 -0
- package/dist/harness/transcript.d.ts.map +1 -0
- package/dist/harness/transcript.js +264 -0
- package/dist/harness/transcript.js.map +1 -0
- package/dist/harness/types.d.ts +302 -48
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/util.d.ts +7 -1
- package/dist/harness/util.d.ts.map +1 -1
- package/dist/harness/util.js +13 -0
- package/dist/harness/util.js.map +1 -1
- package/dist/harness/view.d.ts +43 -22
- package/dist/harness/view.d.ts.map +1 -1
- package/dist/harness/view.js +130 -71
- package/dist/harness/view.js.map +1 -1
- package/dist/index.d.ts +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +19 -3
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +107 -44
- package/dist/search.js.map +1 -1
- package/dist/session/cached-storage.d.ts +71 -0
- package/dist/session/cached-storage.d.ts.map +1 -0
- package/dist/session/cached-storage.js +269 -0
- package/dist/session/cached-storage.js.map +1 -0
- package/dist/session/conversation-tails.d.ts +33 -0
- package/dist/session/conversation-tails.d.ts.map +1 -0
- package/dist/session/conversation-tails.js +101 -0
- package/dist/session/conversation-tails.js.map +1 -0
- package/dist/session/keys.d.ts +68 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +161 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/session.d.ts +181 -29
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +1073 -183
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts +86 -4
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +250 -38
- package/dist/session/transaction.js.map +1 -1
- package/dist/session/writer.d.ts +74 -0
- package/dist/session/writer.d.ts.map +1 -0
- package/dist/session/writer.js +294 -0
- package/dist/session/writer.js.map +1 -0
- package/dist/storage/indexeddb.d.ts +68 -0
- package/dist/storage/indexeddb.d.ts.map +1 -0
- package/dist/storage/indexeddb.js +881 -0
- package/dist/storage/indexeddb.js.map +1 -0
- package/dist/storage/jsonl/storage.d.ts +30 -2
- package/dist/storage/jsonl/storage.d.ts.map +1 -1
- package/dist/storage/jsonl/storage.js +88 -24
- package/dist/storage/jsonl/storage.js.map +1 -1
- package/dist/storage/memory.d.ts +7 -2
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +29 -3
- package/dist/storage/memory.js.map +1 -1
- package/dist/storage/sqlite/cloudflare.d.ts +2 -51
- package/dist/storage/sqlite/cloudflare.d.ts.map +1 -1
- package/dist/storage/sqlite/cloudflare.js +2 -133
- package/dist/storage/sqlite/cloudflare.js.map +1 -1
- package/dist/storage/sqlite/database.d.ts +1 -36
- package/dist/storage/sqlite/database.d.ts.map +1 -1
- package/dist/storage/sqlite/database.js.map +1 -1
- package/dist/storage/sqlite/index.d.ts +1 -1
- package/dist/storage/sqlite/index.d.ts.map +1 -1
- package/dist/storage/sqlite/index.js.map +1 -1
- package/dist/storage/sqlite/migrations.d.ts +2 -5
- package/dist/storage/sqlite/migrations.d.ts.map +1 -1
- package/dist/storage/sqlite/migrations.js +28 -28
- package/dist/storage/sqlite/migrations.js.map +1 -1
- package/dist/storage/sqlite/node.d.ts +2 -37
- package/dist/storage/sqlite/node.d.ts.map +1 -1
- package/dist/storage/sqlite/node.js +3 -174
- package/dist/storage/sqlite/node.js.map +1 -1
- package/dist/storage/sqlite/schema.d.ts +1 -3
- package/dist/storage/sqlite/schema.d.ts.map +1 -1
- package/dist/storage/sqlite/schema.js +2 -9
- package/dist/storage/sqlite/schema.js.map +1 -1
- package/dist/storage/sqlite/storage.d.ts +15 -3
- package/dist/storage/sqlite/storage.d.ts.map +1 -1
- package/dist/storage/sqlite/storage.js +110 -36
- package/dist/storage/sqlite/storage.js.map +1 -1
- package/dist/storage/store/commit.d.ts +33 -0
- package/dist/storage/store/commit.d.ts.map +1 -0
- package/dist/storage/store/commit.js +286 -0
- package/dist/storage/store/commit.js.map +1 -0
- package/dist/storage/store/documents.d.ts +43 -0
- package/dist/storage/store/documents.d.ts.map +1 -0
- package/dist/storage/store/documents.js +102 -0
- package/dist/storage/store/documents.js.map +1 -0
- package/dist/storage/store/index.d.ts +2 -0
- package/dist/storage/store/index.d.ts.map +1 -0
- package/dist/storage/store/index.js +2 -0
- package/dist/storage/store/index.js.map +1 -0
- package/dist/storage/store/queries.d.ts +49 -0
- package/dist/storage/store/queries.d.ts.map +1 -0
- package/dist/storage/store/queries.js +93 -0
- package/dist/storage/store/queries.js.map +1 -0
- package/dist/storage/store/storage.d.ts +59 -0
- package/dist/storage/store/storage.d.ts.map +1 -0
- package/dist/storage/store/storage.js +438 -0
- package/dist/storage/store/storage.js.map +1 -0
- package/dist/storage/store/tables.d.ts +54 -0
- package/dist/storage/store/tables.d.ts.map +1 -0
- package/dist/storage/store/tables.js +108 -0
- package/dist/storage/store/tables.js.map +1 -0
- package/dist/testing/commit-writes.d.ts +5 -0
- package/dist/testing/commit-writes.d.ts.map +1 -0
- package/dist/testing/commit-writes.js +12 -0
- package/dist/testing/commit-writes.js.map +1 -0
- package/dist/testing/env-conformance.js +7 -7
- package/dist/testing/env-conformance.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/storage-benchmark.d.ts.map +1 -1
- package/dist/testing/storage-benchmark.js +18 -17
- package/dist/testing/storage-benchmark.js.map +1 -1
- package/dist/testing/storage-conformance.d.ts.map +1 -1
- package/dist/testing/storage-conformance.js +369 -67
- package/dist/testing/storage-conformance.js.map +1 -1
- package/dist/timers.d.ts +21 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +72 -0
- package/dist/timers.js.map +1 -0
- package/dist/tool-search/tool-search.d.ts +6 -12
- package/dist/tool-search/tool-search.d.ts.map +1 -1
- package/dist/tool-search/tool-search.js +7 -7
- package/dist/tool-search/tool-search.js.map +1 -1
- package/dist/tools/bash.d.ts +12 -12
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +16 -15
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +7 -7
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +9 -9
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts +32 -32
- package/dist/tools/read.d.ts +6 -6
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +19 -8
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +4 -4
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +5 -5
- package/dist/tools/write.js.map +1 -1
- package/dist/types.d.ts +331 -64
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +27 -10
- package/dist/harness/events.d.ts +0 -186
- package/dist/harness/events.d.ts.map +0 -1
- package/dist/harness/events.js +0 -373
- package/dist/harness/events.js.map +0 -1
- package/dist/session/observation.d.ts +0 -42
- package/dist/session/observation.d.ts.map +0 -1
- package/dist/session/observation.js +0 -281
- package/dist/session/observation.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { withoutAbortSignal } from "@earendil-works/chord/context";
|
|
1
|
+
import { Watch } from "@earendil-works/chord";
|
|
2
|
+
import { BACKGROUND_CONTEXT, withoutAbortSignal } from "@earendil-works/chord/context";
|
|
3
3
|
import { applyImmutable } from "@earendil-works/chord/delta";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { closeEndOf, closeEnds, contained, guardObserver, observation, } from "../session/session.js";
|
|
5
|
+
import { blockedSubject } from "./scheduler.js";
|
|
6
6
|
import { closedError, scanAll } from "./util.js";
|
|
7
|
-
const LIVE_STATUSES = ["pending", "running", "waiting", "completing"];
|
|
7
|
+
const LIVE_STATUSES = ["pending", "running", "waiting", "sleeping", "completing"];
|
|
8
8
|
const SCAN_PAGE_SIZE = 256;
|
|
9
9
|
/**
|
|
10
10
|
* The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It
|
|
@@ -12,51 +12,64 @@ const SCAN_PAGE_SIZE = 256;
|
|
|
12
12
|
*/
|
|
13
13
|
export class TaskGraphView {
|
|
14
14
|
#session;
|
|
15
|
-
#
|
|
15
|
+
#blocking;
|
|
16
16
|
#mount;
|
|
17
17
|
#closed = false;
|
|
18
|
-
constructor(session,
|
|
18
|
+
constructor(session, blocking) {
|
|
19
19
|
this.#session = session;
|
|
20
|
-
this.#
|
|
21
|
-
session.
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
this.#blocking = blocking;
|
|
21
|
+
session.followCommits((publication, context) => {
|
|
22
|
+
// A commit held in memory changes documents only, which the graph does not show.
|
|
23
|
+
if (this.#mount === undefined || publication.kind === "memory")
|
|
24
|
+
return;
|
|
25
|
+
advance(this.#mount, publication, context, blocking.blocked, (error) => session.report(error));
|
|
24
26
|
});
|
|
27
|
+
blocking.subscribeBlocked(() => this.#refreshBlocked());
|
|
25
28
|
session.subscribeClose(() => {
|
|
26
29
|
this.#closed = true;
|
|
30
|
+
const ends = closeEnds(this.#session.failure);
|
|
27
31
|
for (const observer of [...(this.#mount?.observers ?? [])]) {
|
|
28
|
-
contained(() => observer.
|
|
32
|
+
contained(() => observer.end(closeEndOf(observer, ends)), (error) => session.report(error));
|
|
29
33
|
}
|
|
30
34
|
this.#mount = undefined;
|
|
31
35
|
});
|
|
32
36
|
}
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Attach a synchronous observer of the graph (`Harness.observeTaskGraph()`), behind `guardObserver()`; `context`
|
|
39
|
+
* governs only the attachment.
|
|
40
|
+
*/
|
|
41
|
+
async observe(observer, context) {
|
|
42
|
+
let value;
|
|
43
|
+
const attached = await this.#attach((current, release) => {
|
|
44
|
+
value = current;
|
|
45
|
+
return guardObserver(observer, release, (error) => this.#session.report(error));
|
|
46
|
+
}, context);
|
|
47
|
+
const signal = context.abortSignal;
|
|
48
|
+
if (signal?.aborted) {
|
|
49
|
+
attached.detach();
|
|
50
|
+
throw signal.reason;
|
|
42
51
|
}
|
|
52
|
+
return observation(value, attached.observer);
|
|
43
53
|
}
|
|
44
|
-
/** A serialized
|
|
54
|
+
/** A serialized watch of the graph, an observer of its mount; aborting `context` ends it `aborted`. */
|
|
45
55
|
async watch(context) {
|
|
46
|
-
const { observer } = await this.#attach((value, release) => new
|
|
56
|
+
const { observer } = await this.#attach((value, release) => new Watch(value, release, (error) => this.#session.report(error)), context);
|
|
47
57
|
const signal = context.abortSignal;
|
|
48
58
|
if (signal?.aborted) {
|
|
49
|
-
observer.
|
|
59
|
+
observer.abort();
|
|
50
60
|
throw signal.reason;
|
|
51
61
|
}
|
|
52
62
|
if (signal !== undefined)
|
|
53
|
-
observer.
|
|
63
|
+
observer.observeAbort(signal);
|
|
54
64
|
return observer;
|
|
55
65
|
}
|
|
56
66
|
/** Register an observer created from the current revision, atomically on the Session line. */
|
|
57
67
|
#attach(create, context) {
|
|
58
|
-
return this.#session.readOnLine(async () => {
|
|
59
|
-
const mount = this.#mount ?? {
|
|
68
|
+
return this.#session.readOnLine(async (storage) => {
|
|
69
|
+
const mount = this.#mount ?? {
|
|
70
|
+
...(await this.#build(storage, context)),
|
|
71
|
+
observers: new Set(),
|
|
72
|
+
};
|
|
60
73
|
const detach = () => {
|
|
61
74
|
mount.observers.delete(observer);
|
|
62
75
|
if (mount.observers.size === 0 && this.#mount === mount)
|
|
@@ -72,26 +85,51 @@ export class TaskGraphView {
|
|
|
72
85
|
return { observer, detach };
|
|
73
86
|
});
|
|
74
87
|
}
|
|
75
|
-
|
|
88
|
+
/** On the Session line: derive every node's blocked reason again, and publish the ones that changed. */
|
|
89
|
+
#refreshBlocked() {
|
|
90
|
+
if (this.#mount === undefined || this.#closed)
|
|
91
|
+
return;
|
|
92
|
+
this.#session
|
|
93
|
+
.readOnLine(async () => {
|
|
94
|
+
const mount = this.#mount;
|
|
95
|
+
if (mount === undefined)
|
|
96
|
+
return;
|
|
97
|
+
const ops = [];
|
|
98
|
+
for (const [key, record] of mount.records) {
|
|
99
|
+
const blocked = this.#blocking.blocked(record);
|
|
100
|
+
if (blocked === mount.value.tasks[key]?.blocked)
|
|
101
|
+
continue;
|
|
102
|
+
ops.push(blocked === undefined ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]);
|
|
103
|
+
}
|
|
104
|
+
publish(mount, ops, BACKGROUND_CONTEXT, (error) => this.#session.report(error));
|
|
105
|
+
})
|
|
106
|
+
// Rejected only once the Session is closing or failed.
|
|
107
|
+
.catch(() => { });
|
|
108
|
+
}
|
|
109
|
+
/** Read the graph on the line, through the line's `storage`. */
|
|
110
|
+
async #build(storage, context) {
|
|
76
111
|
const tasks = {};
|
|
112
|
+
const live = new Map();
|
|
77
113
|
const records = [];
|
|
78
114
|
for (const status of LIVE_STATUSES) {
|
|
79
|
-
records.push(...(await scanAll((cursor) =>
|
|
115
|
+
records.push(...(await scanAll((cursor) => storage.scanTasks({ status }, SCAN_PAGE_SIZE, cursor, context))));
|
|
80
116
|
}
|
|
81
117
|
records.sort((a, b) => a.id - b.id);
|
|
82
118
|
for (const record of records) {
|
|
83
|
-
const owned = await scanAll((cursor) =>
|
|
119
|
+
const owned = await scanAll((cursor) => storage.scanConversations({ ownerTaskId: record.id }, SCAN_PAGE_SIZE, cursor, context));
|
|
84
120
|
const conversations = owned.map((conversation) => conversation.id).sort((a, b) => a - b);
|
|
85
|
-
|
|
121
|
+
const subject = blockedSubject(record);
|
|
122
|
+
tasks[String(record.id)] = nodeOf(record, conversations, this.#blocking.blocked(subject));
|
|
123
|
+
live.set(String(record.id), subject);
|
|
86
124
|
}
|
|
87
|
-
return { tasks };
|
|
125
|
+
return { value: { tasks }, records: live };
|
|
88
126
|
}
|
|
89
127
|
}
|
|
90
128
|
/**
|
|
91
129
|
* Derive the mount's operations from one publication, apply them, and hand the revision to every observer; one that
|
|
92
130
|
* throws is reported through `report`, and the others still get it.
|
|
93
131
|
*/
|
|
94
|
-
function advance(mount, publication, context, report) {
|
|
132
|
+
function advance(mount, publication, context, blocked, report) {
|
|
95
133
|
const ops = [];
|
|
96
134
|
// Nodes this publication set or deleted, over the mount's value.
|
|
97
135
|
const changed = new Map();
|
|
@@ -103,13 +141,16 @@ function advance(mount, publication, context, report) {
|
|
|
103
141
|
const key = String(record.id);
|
|
104
142
|
const previous = node(key);
|
|
105
143
|
if (record.state.status === "terminal") {
|
|
144
|
+
mount.records.delete(key);
|
|
106
145
|
if (previous === undefined)
|
|
107
146
|
continue;
|
|
108
147
|
ops.push(["d", ["tasks", key]]);
|
|
109
148
|
changed.set(key, undefined);
|
|
110
149
|
continue;
|
|
111
150
|
}
|
|
112
|
-
const
|
|
151
|
+
const subject = blockedSubject(record);
|
|
152
|
+
mount.records.set(key, subject);
|
|
153
|
+
const next = nodeOf(record, previous?.conversations ?? [], blocked(subject));
|
|
113
154
|
if (previous !== undefined && JSON.stringify(next) === JSON.stringify(previous))
|
|
114
155
|
continue;
|
|
115
156
|
ops.push(["s", ["tasks", key], next]);
|
|
@@ -129,14 +170,19 @@ function advance(mount, publication, context, report) {
|
|
|
129
170
|
const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b);
|
|
130
171
|
ops.push(["s", ["tasks", key, "conversations"], conversations]);
|
|
131
172
|
}
|
|
173
|
+
publish(mount, ops, context, report);
|
|
174
|
+
}
|
|
175
|
+
/** Apply `ops` to the mount and hand the revision to every observer; one that throws is reported. */
|
|
176
|
+
function publish(mount, ops, context, report) {
|
|
132
177
|
if (ops.length === 0)
|
|
133
178
|
return;
|
|
134
179
|
mount.value = applyImmutable(mount.value, ops);
|
|
135
180
|
const frameContext = withoutAbortSignal(context);
|
|
181
|
+
const call = { kind: "value", value: mount.value, ops, retired: false };
|
|
136
182
|
for (const observer of [...mount.observers])
|
|
137
|
-
contained(() => observer.advance(
|
|
183
|
+
contained(() => observer.advance(call, frameContext), report);
|
|
138
184
|
}
|
|
139
|
-
function nodeOf(record, conversations) {
|
|
185
|
+
function nodeOf(record, conversations, blocked) {
|
|
140
186
|
return {
|
|
141
187
|
id: record.id,
|
|
142
188
|
kind: record.kind,
|
|
@@ -146,6 +192,7 @@ function nodeOf(record, conversations) {
|
|
|
146
192
|
abortRequested: record.abortRequested,
|
|
147
193
|
state: stateOf(record),
|
|
148
194
|
conversations,
|
|
195
|
+
...(blocked === undefined ? {} : { blocked }),
|
|
149
196
|
};
|
|
150
197
|
}
|
|
151
198
|
function stateOf(record) {
|
|
@@ -156,6 +203,8 @@ function stateOf(record) {
|
|
|
156
203
|
return { status: state.status, phase: phaseOf(state.checkpoint) };
|
|
157
204
|
case "waiting":
|
|
158
205
|
return { status: "waiting", phase: phaseOf(state.checkpoint), on: [...state.on], policy: state.policy };
|
|
206
|
+
case "sleeping":
|
|
207
|
+
return { status: "sleeping", phase: phaseOf(state.checkpoint), until: state.until };
|
|
159
208
|
// Terminal records never reach here: they leave the graph.
|
|
160
209
|
case "completing":
|
|
161
210
|
case "terminal":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-graph.js","sourceRoot":"","sources":["../../src/harness/task-graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AttachedReplicatedState, type Context, type JsonValue, replicatedState } from \"@earendil-works/chord\";\nimport { withoutAbortSignal } from \"@earendil-works/chord/context\";\nimport { applyImmutable, type Op } from \"@earendil-works/chord/delta\";\nimport { CommittedStateSource, CommittedWatch } from \"../session/observation.ts\";\nimport { contained, type SessionImpl } from \"../session/session.ts\";\nimport type {\n\tCommitPublication,\n\tConversationId,\n\tJoinPolicy,\n\tStorage,\n\tTaskId,\n\tTaskOutcome,\n\tTaskRecord,\n\tWatchHandle,\n} from \"../types.ts\";\nimport { closedError, scanAll } from \"./util.ts\";\n\n/** A live task's durable status without its checkpoint and outcome payloads (spec §9.5). */\nexport type TaskGraphState =\n\t| { readonly status: \"pending\" | \"running\"; readonly phase: string }\n\t| {\n\t\t\treadonly status: \"waiting\";\n\t\t\treadonly phase: string;\n\t\t\treadonly on: readonly TaskId[];\n\t\t\treadonly policy: JoinPolicy;\n\t }\n\t/** Outcome held until its ordinary owned work drains. */\n\t| { readonly status: \"completing\"; readonly outcome: TaskOutcome<JsonValue>[\"status\"] };\n\nexport type TaskGraphNode = {\n\treadonly id: TaskId;\n\treadonly kind: string;\n\treadonly conversationId: ConversationId;\n\t/** Owner task; absent for a conversation-owned task. */\n\treadonly owner?: TaskId;\n\treadonly background: boolean;\n\treadonly abortRequested: boolean;\n\treadonly state: TaskGraphState;\n\t/** Conversations this task owns, in ID order. */\n\treadonly conversations: readonly ConversationId[];\n};\n\n/** Every live task of the Session (spec §9.5). */\nexport type TaskGraph = {\n\t/** Every live task, keyed by its decimal ID. */\n\treadonly tasks: Readonly<Record<string, TaskGraphNode>>;\n};\n\nexport type TaskGraphWatch = WatchHandle<TaskGraph>;\n\ntype AnyTaskRecord = TaskRecord<JsonValue, JsonValue, JsonValue>;\ntype Observer = CommittedStateSource<TaskGraph> | CommittedWatch<TaskGraph>;\ntype Mount = { value: TaskGraph; readonly observers: Set<Observer> };\n\nconst LIVE_STATUSES = [\"pending\", \"running\", \"waiting\", \"completing\"] as const;\nconst SCAN_PAGE_SIZE = 256;\n\n/**\n * The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It\n * advances from the Session's commit publications, which are durable.\n */\nexport class TaskGraphView {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\t#mount: Mount | undefined;\n\t#closed = false;\n\n\tconstructor(session: SessionImpl, storage: Storage) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tsession.observeCommits((publication, context) => {\n\t\t\tif (this.#mount !== undefined) advance(this.#mount, publication, context, (error) => session.report(error));\n\t\t});\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tfor (const observer of [...(this.#mount?.observers ?? [])]) {\n\t\t\t\tcontained(\n\t\t\t\t\t() => observer.closeSession(this.#session.failure),\n\t\t\t\t\t(error) => session.report(error),\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.#mount = undefined;\n\t\t});\n\t}\n\n\t/** A disposable read-only Chord state of the graph. */\n\tasync state(context: Context): Promise<AttachedReplicatedState<TaskGraph>> {\n\t\tconst { observer, detach } = await this.#attach(\n\t\t\t(value, release) => new CommittedStateSource<TaskGraph>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\ttry {\n\t\t\treturn replicatedState(observer, { onError: (error) => this.#session.report(error) });\n\t\t} catch (error) {\n\t\t\tdetach();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** A serialized exact-frame watch of the graph; cancelling `context` stops it. */\n\tasync watch(context: Context): Promise<TaskGraphWatch> {\n\t\tconst { observer } = await this.#attach(\n\t\t\t(value, release) => new CommittedWatch<TaskGraph>(value, release, (error) => this.#session.report(error)),\n\t\t\tcontext,\n\t\t);\n\t\tconst signal = context.abortSignal;\n\t\tif (signal?.aborted) {\n\t\t\tobserver.cancel();\n\t\t\tthrow signal.reason;\n\t\t}\n\t\tif (signal !== undefined) observer.observeCancellation(signal);\n\t\treturn observer;\n\t}\n\n\t/** Register an observer created from the current revision, atomically on the Session line. */\n\t#attach<O extends Observer>(\n\t\tcreate: (value: TaskGraph, release: () => void) => O,\n\t\tcontext: Context,\n\t): Promise<{ observer: O; detach: () => void }> {\n\t\treturn this.#session.readOnLine(async () => {\n\t\t\tconst mount = this.#mount ?? { value: await this.#build(context), observers: new Set<Observer>() };\n\t\t\tconst detach = (): void => {\n\t\t\t\tmount.observers.delete(observer);\n\t\t\t\tif (mount.observers.size === 0 && this.#mount === mount) this.#mount = undefined;\n\t\t\t};\n\t\t\tconst observer = create(mount.value, detach);\n\t\t\t// Close or cancellation may begin while the mount builds; register nothing then.\n\t\t\tif (this.#closed) throw closedError(this.#session);\n\t\t\tcontext.abortSignal?.throwIfAborted();\n\t\t\tthis.#mount = mount;\n\t\t\tmount.observers.add(observer);\n\t\t\treturn { observer, detach };\n\t\t});\n\t}\n\n\tasync #build(context: Context): Promise<TaskGraph> {\n\t\tconst tasks: Record<string, TaskGraphNode> = {};\n\t\tconst records: AnyTaskRecord[] = [];\n\t\tfor (const status of LIVE_STATUSES) {\n\t\t\trecords.push(\n\t\t\t\t...(await scanAll((cursor) => this.#storage.scanTasks({ status }, SCAN_PAGE_SIZE, cursor, context))),\n\t\t\t);\n\t\t}\n\t\trecords.sort((a, b) => a.id - b.id);\n\t\tfor (const record of records) {\n\t\t\tconst owned = await scanAll((cursor) =>\n\t\t\t\tthis.#storage.scanConversations({ ownerTaskId: record.id }, SCAN_PAGE_SIZE, cursor, context),\n\t\t\t);\n\t\t\tconst conversations = owned.map((conversation) => conversation.id).sort((a, b) => a - b);\n\t\t\ttasks[String(record.id)] = nodeOf(record, conversations);\n\t\t}\n\t\treturn { tasks };\n\t}\n}\n\n/**\n * Derive the mount's operations from one publication, apply them, and hand the revision to every observer; one that\n * throws is reported through `report`, and the others still get it.\n */\nfunction advance(\n\tmount: Mount,\n\tpublication: CommitPublication,\n\tcontext: Context,\n\treport: (error: unknown) => void,\n): void {\n\tconst ops: Op[] = [];\n\t// Nodes this publication set or deleted, over the mount's value.\n\tconst changed = new Map<string, TaskGraphNode | undefined>();\n\tconst node = (key: string): TaskGraphNode | undefined =>\n\t\tchanged.has(key) ? changed.get(key) : mount.value.tasks[key];\n\tfor (const change of publication.changes) {\n\t\tif (change.type !== \"task\") continue;\n\t\tconst record = change.value;\n\t\tconst key = String(record.id);\n\t\tconst previous = node(key);\n\t\tif (record.state.status === \"terminal\") {\n\t\t\tif (previous === undefined) continue;\n\t\t\tops.push([\"d\", [\"tasks\", key]]);\n\t\t\tchanged.set(key, undefined);\n\t\t\tcontinue;\n\t\t}\n\t\tconst next = nodeOf(record, previous?.conversations ?? []);\n\t\tif (previous !== undefined && JSON.stringify(next) === JSON.stringify(previous)) continue;\n\t\tops.push([\"s\", [\"tasks\", key], next as unknown as JsonValue]);\n\t\tchanged.set(key, next);\n\t}\n\t// After the tasks, so a conversation created with its owner task in one commit finds the owner's node. Change order\n\t// within a publication is unspecified, so each owner's list is sorted again.\n\tconst created = new Map<string, ConversationId[]>();\n\tfor (const change of publication.changes) {\n\t\tif (change.type !== \"conversation\" || change.value.owner === undefined) continue;\n\t\tconst key = String(change.value.owner.taskId);\n\t\tif (node(key) !== undefined) created.set(key, [...(created.get(key) ?? []), change.value.id]);\n\t}\n\tfor (const [key, ids] of created) {\n\t\tconst conversations = [...node(key)!.conversations, ...ids].sort((a, b) => a - b);\n\t\tops.push([\"s\", [\"tasks\", key, \"conversations\"], conversations]);\n\t}\n\tif (ops.length === 0) return;\n\tmount.value = applyImmutable(mount.value, ops);\n\tconst frameContext = withoutAbortSignal(context);\n\tfor (const observer of [...mount.observers])\n\t\tcontained(() => observer.advance(mount.value, ops, frameContext), report);\n}\n\nfunction nodeOf(record: AnyTaskRecord, conversations: readonly ConversationId[]): TaskGraphNode {\n\treturn {\n\t\tid: record.id,\n\t\tkind: record.kind,\n\t\tconversationId: record.conversationId,\n\t\t...(record.owner === undefined ? {} : { owner: record.owner }),\n\t\tbackground: record.background,\n\t\tabortRequested: record.abortRequested,\n\t\tstate: stateOf(record),\n\t\tconversations,\n\t};\n}\n\nfunction stateOf(record: AnyTaskRecord): TaskGraphState {\n\tconst state = record.state;\n\tswitch (state.status) {\n\t\tcase \"pending\":\n\t\tcase \"running\":\n\t\t\treturn { status: state.status, phase: phaseOf(state.checkpoint) };\n\t\tcase \"waiting\":\n\t\t\treturn { status: \"waiting\", phase: phaseOf(state.checkpoint), on: [...state.on], policy: state.policy };\n\t\t// Terminal records never reach here: they leave the graph.\n\t\tcase \"completing\":\n\t\tcase \"terminal\":\n\t\t\treturn { status: \"completing\", outcome: state.outcome.status };\n\t}\n}\n\nfunction phaseOf(checkpoint: JsonValue): string {\n\treturn (checkpoint as { readonly phase: string }).phase;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"task-graph.js","sourceRoot":"","sources":["../../src/harness/task-graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Context, type JsonValue, Watch, type WatchCall, type WatchHandle } from \"@earendil-works/chord\";\nimport { BACKGROUND_CONTEXT, withoutAbortSignal } from \"@earendil-works/chord/context\";\nimport { applyImmutable, type Op } from \"@earendil-works/chord/delta\";\nimport {\n\tcloseEndOf,\n\tcloseEnds,\n\tcontained,\n\tguardObserver,\n\ttype ObservedCommit,\n\tobservation,\n\ttype SessionImpl,\n} from \"../session/session.ts\";\nimport type {\n\tConversationId,\n\tJoinPolicy,\n\tObservation,\n\tObserver,\n\tStorage,\n\tTaskId,\n\tTaskOutcome,\n\tTaskRecord,\n} from \"../types.ts\";\nimport { type BlockedReason, type BlockedSubject, blockedSubject } from \"./scheduler.ts\";\nimport { closedError, scanAll } from \"./util.ts\";\n\n/** A live task's durable status without its checkpoint and outcome payloads (spec §9.4). */\nexport type TaskGraphState =\n\t| { readonly status: \"pending\" | \"running\"; readonly phase: string }\n\t| {\n\t\t\treadonly status: \"waiting\";\n\t\t\treadonly phase: string;\n\t\t\treadonly on: readonly TaskId[];\n\t\t\treadonly policy: JoinPolicy;\n\t }\n\t/** Asleep until the Harness clock reaches `until`. */\n\t| { readonly status: \"sleeping\"; readonly phase: string; readonly until: number }\n\t/** Outcome held until its ordinary owned work drains. */\n\t| { readonly status: \"completing\"; readonly outcome: TaskOutcome<JsonValue>[\"status\"] };\n\nexport type TaskGraphNode = {\n\treadonly id: TaskId;\n\treadonly kind: string;\n\treadonly conversationId: ConversationId;\n\t/** Owner task; absent for a conversation-owned task. */\n\treadonly owner?: TaskId;\n\treadonly background: boolean;\n\treadonly abortRequested: boolean;\n\treadonly state: TaskGraphState;\n\t/**\n\t * Why it cannot run here, when it cannot: no registered definition takes it (`missing_task`, `task_too_old`,\n\t * `migration_failed`). Follows registry changes.\n\t */\n\treadonly blocked?: BlockedReason;\n\t/** Conversations this task owns, in ID order. */\n\treadonly conversations: readonly ConversationId[];\n};\n\n/** Every live task of the Session (spec §9.4). */\nexport type TaskGraph = {\n\t/** Every live task, keyed by its decimal ID. */\n\treadonly tasks: Readonly<Record<string, TaskGraphNode>>;\n};\n\nexport type TaskGraphWatch = WatchHandle<TaskGraph>;\n\ntype AnyTaskRecord = TaskRecord<JsonValue, JsonValue, JsonValue>;\ntype Mount = {\n\tvalue: TaskGraph;\n\t/** Watches and guarded host observers (`observeTaskGraph()`). */\n\treadonly observers: Set<Observer<TaskGraph>>;\n\t/** What the blocked reason reads of each live task, so a registry change can derive it again without payloads. */\n\treadonly records: Map<string, BlockedSubject>;\n};\n\n/** What the graph asks the scheduler: a task's blocked reason, and when reasons may change without a commit. */\nexport type TaskGraphBlocking = {\n\treadonly blocked: (record: BlockedSubject) => BlockedReason | undefined;\n\treadonly subscribeBlocked: (listener: () => void) => () => void;\n};\n\nconst LIVE_STATUSES = [\"pending\", \"running\", \"waiting\", \"sleeping\", \"completing\"] as const;\nconst SCAN_PAGE_SIZE = 256;\n\n/**\n * The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It\n * advances from the Session's commit publications, which are durable.\n */\nexport class TaskGraphView {\n\treadonly #session: SessionImpl;\n\treadonly #blocking: TaskGraphBlocking;\n\t#mount: Mount | undefined;\n\t#closed = false;\n\n\tconstructor(session: SessionImpl, blocking: TaskGraphBlocking) {\n\t\tthis.#session = session;\n\t\tthis.#blocking = blocking;\n\t\tsession.followCommits((publication, context) => {\n\t\t\t// A commit held in memory changes documents only, which the graph does not show.\n\t\t\tif (this.#mount === undefined || publication.kind === \"memory\") return;\n\t\t\tadvance(this.#mount, publication, context, blocking.blocked, (error) => session.report(error));\n\t\t});\n\t\tblocking.subscribeBlocked(() => this.#refreshBlocked());\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tconst ends = closeEnds(this.#session.failure);\n\t\t\tfor (const observer of [...(this.#mount?.observers ?? [])]) {\n\t\t\t\tcontained(\n\t\t\t\t\t() => observer.end(closeEndOf(observer, ends)),\n\t\t\t\t\t(error) => session.report(error),\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.#mount = undefined;\n\t\t});\n\t}\n\n\t/**\n\t * Attach a synchronous observer of the graph (`Harness.observeTaskGraph()`), behind `guardObserver()`; `context`\n\t * governs only the attachment.\n\t */\n\tasync observe(observer: Observer<TaskGraph>, context: Context): Promise<Observation<TaskGraph>> {\n\t\tlet value!: TaskGraph;\n\t\tconst attached = await this.#attach((current, release) => {\n\t\t\tvalue = current;\n\t\t\treturn guardObserver(observer, release, (error) => this.#session.report(error));\n\t\t}, context);\n\t\tconst signal = context.abortSignal;\n\t\tif (signal?.aborted) {\n\t\t\tattached.detach();\n\t\t\tthrow signal.reason;\n\t\t}\n\t\treturn observation(value, attached.observer);\n\t}\n\n\t/** A serialized watch of the graph, an observer of its mount; aborting `context` ends it `aborted`. */\n\tasync watch(context: Context): Promise<TaskGraphWatch> {\n\t\tconst { observer } = await this.#attach(\n\t\t\t(value, release) => new Watch<TaskGraph>(value, release, (error) => this.#session.report(error)),\n\t\t\tcontext,\n\t\t);\n\t\tconst signal = context.abortSignal;\n\t\tif (signal?.aborted) {\n\t\t\tobserver.abort();\n\t\t\tthrow signal.reason;\n\t\t}\n\t\tif (signal !== undefined) observer.observeAbort(signal);\n\t\treturn observer;\n\t}\n\n\t/** Register an observer created from the current revision, atomically on the Session line. */\n\t#attach<O extends Observer<TaskGraph>>(\n\t\tcreate: (value: TaskGraph, release: () => void) => O,\n\t\tcontext: Context,\n\t): Promise<{ observer: O; detach: () => void }> {\n\t\treturn this.#session.readOnLine(async (storage) => {\n\t\t\tconst mount = this.#mount ?? {\n\t\t\t\t...(await this.#build(storage, context)),\n\t\t\t\tobservers: new Set<Observer<TaskGraph>>(),\n\t\t\t};\n\t\t\tconst detach = (): void => {\n\t\t\t\tmount.observers.delete(observer);\n\t\t\t\tif (mount.observers.size === 0 && this.#mount === mount) this.#mount = undefined;\n\t\t\t};\n\t\t\tconst observer = create(mount.value, detach);\n\t\t\t// Close or cancellation may begin while the mount builds; register nothing then.\n\t\t\tif (this.#closed) throw closedError(this.#session);\n\t\t\tcontext.abortSignal?.throwIfAborted();\n\t\t\tthis.#mount = mount;\n\t\t\tmount.observers.add(observer);\n\t\t\treturn { observer, detach };\n\t\t});\n\t}\n\n\t/** On the Session line: derive every node's blocked reason again, and publish the ones that changed. */\n\t#refreshBlocked(): void {\n\t\tif (this.#mount === undefined || this.#closed) return;\n\t\tthis.#session\n\t\t\t.readOnLine(async () => {\n\t\t\t\tconst mount = this.#mount;\n\t\t\t\tif (mount === undefined) return;\n\t\t\t\tconst ops: Op[] = [];\n\t\t\t\tfor (const [key, record] of mount.records) {\n\t\t\t\t\tconst blocked = this.#blocking.blocked(record);\n\t\t\t\t\tif (blocked === mount.value.tasks[key]?.blocked) continue;\n\t\t\t\t\tops.push(\n\t\t\t\t\t\tblocked === undefined ? [\"d\", [\"tasks\", key, \"blocked\"]] : [\"s\", [\"tasks\", key, \"blocked\"], blocked],\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tpublish(mount, ops, BACKGROUND_CONTEXT, (error) => this.#session.report(error));\n\t\t\t})\n\t\t\t// Rejected only once the Session is closing or failed.\n\t\t\t.catch(() => {});\n\t}\n\n\t/** Read the graph on the line, through the line's `storage`. */\n\tasync #build(storage: Storage, context: Context): Promise<Omit<Mount, \"observers\">> {\n\t\tconst tasks: Record<string, TaskGraphNode> = {};\n\t\tconst live = new Map<string, BlockedSubject>();\n\t\tconst records: AnyTaskRecord[] = [];\n\t\tfor (const status of LIVE_STATUSES) {\n\t\t\trecords.push(...(await scanAll((cursor) => storage.scanTasks({ status }, SCAN_PAGE_SIZE, cursor, context))));\n\t\t}\n\t\trecords.sort((a, b) => a.id - b.id);\n\t\tfor (const record of records) {\n\t\t\tconst owned = await scanAll((cursor) =>\n\t\t\t\tstorage.scanConversations({ ownerTaskId: record.id }, SCAN_PAGE_SIZE, cursor, context),\n\t\t\t);\n\t\t\tconst conversations = owned.map((conversation) => conversation.id).sort((a, b) => a - b);\n\t\t\tconst subject = blockedSubject(record);\n\t\t\ttasks[String(record.id)] = nodeOf(record, conversations, this.#blocking.blocked(subject));\n\t\t\tlive.set(String(record.id), subject);\n\t\t}\n\t\treturn { value: { tasks }, records: live };\n\t}\n}\n\n/**\n * Derive the mount's operations from one publication, apply them, and hand the revision to every observer; one that\n * throws is reported through `report`, and the others still get it.\n */\nfunction advance(\n\tmount: Mount,\n\tpublication: ObservedCommit,\n\tcontext: Context,\n\tblocked: TaskGraphBlocking[\"blocked\"],\n\treport: (error: unknown) => void,\n): void {\n\tconst ops: Op[] = [];\n\t// Nodes this publication set or deleted, over the mount's value.\n\tconst changed = new Map<string, TaskGraphNode | undefined>();\n\tconst node = (key: string): TaskGraphNode | undefined =>\n\t\tchanged.has(key) ? changed.get(key) : mount.value.tasks[key];\n\tfor (const change of publication.changes) {\n\t\tif (change.type !== \"task\") continue;\n\t\tconst record = change.value;\n\t\tconst key = String(record.id);\n\t\tconst previous = node(key);\n\t\tif (record.state.status === \"terminal\") {\n\t\t\tmount.records.delete(key);\n\t\t\tif (previous === undefined) continue;\n\t\t\tops.push([\"d\", [\"tasks\", key]]);\n\t\t\tchanged.set(key, undefined);\n\t\t\tcontinue;\n\t\t}\n\t\tconst subject = blockedSubject(record);\n\t\tmount.records.set(key, subject);\n\t\tconst next = nodeOf(record, previous?.conversations ?? [], blocked(subject));\n\t\tif (previous !== undefined && JSON.stringify(next) === JSON.stringify(previous)) continue;\n\t\tops.push([\"s\", [\"tasks\", key], next as unknown as JsonValue]);\n\t\tchanged.set(key, next);\n\t}\n\t// After the tasks, so a conversation created with its owner task in one commit finds the owner's node. Change order\n\t// within a publication is unspecified, so each owner's list is sorted again.\n\tconst created = new Map<string, ConversationId[]>();\n\tfor (const change of publication.changes) {\n\t\tif (change.type !== \"conversation\" || change.value.owner === undefined) continue;\n\t\tconst key = String(change.value.owner.taskId);\n\t\tif (node(key) !== undefined) created.set(key, [...(created.get(key) ?? []), change.value.id]);\n\t}\n\tfor (const [key, ids] of created) {\n\t\tconst conversations = [...node(key)!.conversations, ...ids].sort((a, b) => a - b);\n\t\tops.push([\"s\", [\"tasks\", key, \"conversations\"], conversations]);\n\t}\n\tpublish(mount, ops, context, report);\n}\n\n/** Apply `ops` to the mount and hand the revision to every observer; one that throws is reported. */\nfunction publish(mount: Mount, ops: Op[], context: Context, report: (error: unknown) => void): void {\n\tif (ops.length === 0) return;\n\tmount.value = applyImmutable(mount.value, ops);\n\tconst frameContext = withoutAbortSignal(context);\n\tconst call: WatchCall<TaskGraph> = { kind: \"value\", value: mount.value, ops, retired: false };\n\tfor (const observer of [...mount.observers]) contained(() => observer.advance(call, frameContext), report);\n}\n\nfunction nodeOf(\n\trecord: AnyTaskRecord,\n\tconversations: readonly ConversationId[],\n\tblocked: BlockedReason | undefined,\n): TaskGraphNode {\n\treturn {\n\t\tid: record.id,\n\t\tkind: record.kind,\n\t\tconversationId: record.conversationId,\n\t\t...(record.owner === undefined ? {} : { owner: record.owner }),\n\t\tbackground: record.background,\n\t\tabortRequested: record.abortRequested,\n\t\tstate: stateOf(record),\n\t\tconversations,\n\t\t...(blocked === undefined ? {} : { blocked }),\n\t};\n}\n\nfunction stateOf(record: AnyTaskRecord): TaskGraphState {\n\tconst state = record.state;\n\tswitch (state.status) {\n\t\tcase \"pending\":\n\t\tcase \"running\":\n\t\t\treturn { status: state.status, phase: phaseOf(state.checkpoint) };\n\t\tcase \"waiting\":\n\t\t\treturn { status: \"waiting\", phase: phaseOf(state.checkpoint), on: [...state.on], policy: state.policy };\n\t\tcase \"sleeping\":\n\t\t\treturn { status: \"sleeping\", phase: phaseOf(state.checkpoint), until: state.until };\n\t\t// Terminal records never reach here: they leave the graph.\n\t\tcase \"completing\":\n\t\tcase \"terminal\":\n\t\t\treturn { status: \"completing\", outcome: state.outcome.status };\n\t}\n}\n\nfunction phaseOf(checkpoint: JsonValue): string {\n\treturn (checkpoint as { readonly phase: string }).phase;\n}\n"]}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/** Durable's content-free span, event, and metric vocabulary. IDs address durable records, never content. */
|
|
2
|
+
export declare const DURABLE_TELEMETRY_SCHEMA: {
|
|
3
|
+
readonly version: 1;
|
|
4
|
+
readonly spans: {
|
|
5
|
+
readonly "pi.durable.submit": {
|
|
6
|
+
readonly description: "Public submission admission: with its commit for submit(draft, context); the admission only for submit(tx, draft), whose result is provisional (a later throw or storage failure of the caller's commit leaves no submission) and whose commit events go to the caller's commit context. Inputs and continues start root traces linked to their callers; writes are children. Internal admissions emit phase events only.";
|
|
7
|
+
readonly parents: {
|
|
8
|
+
readonly kind: "any";
|
|
9
|
+
};
|
|
10
|
+
readonly startAttributes: {
|
|
11
|
+
readonly "submission.type": {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
readonly required: true;
|
|
14
|
+
readonly values: readonly ["input", "write", "continue"];
|
|
15
|
+
readonly description: "Submission type.";
|
|
16
|
+
};
|
|
17
|
+
readonly "conversation.id": {
|
|
18
|
+
readonly type: "number";
|
|
19
|
+
readonly required: true;
|
|
20
|
+
readonly description: "Conversation ID.";
|
|
21
|
+
readonly cardinality: "high";
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
readonly endAttributes: {
|
|
25
|
+
readonly "submission.id": {
|
|
26
|
+
readonly type: "number";
|
|
27
|
+
readonly description: "Admitted submission ID.";
|
|
28
|
+
readonly cardinality: "high";
|
|
29
|
+
};
|
|
30
|
+
readonly result: {
|
|
31
|
+
readonly type: "string";
|
|
32
|
+
readonly values: readonly ["queued", "placed", "done"];
|
|
33
|
+
readonly description: "Admission result; stale writes report done.";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly events: {
|
|
37
|
+
"pi.durable.entry": {
|
|
38
|
+
readonly description: "A transcript entry was committed; content remains in the transcript.";
|
|
39
|
+
readonly attributes: {
|
|
40
|
+
readonly "entry.id": {
|
|
41
|
+
readonly type: "number";
|
|
42
|
+
readonly required: true;
|
|
43
|
+
readonly description: "Transcript entry ID.";
|
|
44
|
+
readonly cardinality: "high";
|
|
45
|
+
};
|
|
46
|
+
readonly "entry.kind": {
|
|
47
|
+
readonly type: "string";
|
|
48
|
+
readonly required: true;
|
|
49
|
+
readonly description: "Entry kind.";
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
"pi.durable.submission": {
|
|
54
|
+
readonly description: "A submission was settled.";
|
|
55
|
+
readonly attributes: {
|
|
56
|
+
readonly "submission.id": {
|
|
57
|
+
readonly type: "number";
|
|
58
|
+
readonly required: true;
|
|
59
|
+
readonly description: "Submission ID.";
|
|
60
|
+
readonly cardinality: "high";
|
|
61
|
+
};
|
|
62
|
+
readonly status: {
|
|
63
|
+
readonly type: "string";
|
|
64
|
+
readonly required: true;
|
|
65
|
+
readonly values: readonly ["done", "unanswered"];
|
|
66
|
+
readonly description: "Settlement.";
|
|
67
|
+
};
|
|
68
|
+
readonly "answer.entry_id": {
|
|
69
|
+
readonly type: "number";
|
|
70
|
+
readonly required: false;
|
|
71
|
+
readonly description: "Answer entry ID.";
|
|
72
|
+
readonly cardinality: "high";
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
"pi.durable.report": {
|
|
77
|
+
readonly description: "A report was raised; no error payload is recorded.";
|
|
78
|
+
readonly attributes: {
|
|
79
|
+
readonly type: {
|
|
80
|
+
readonly type: "string";
|
|
81
|
+
readonly required: true;
|
|
82
|
+
readonly description: "Report kind (`Report.kind`).";
|
|
83
|
+
readonly values: readonly ["storage_failed", "task_faulted", "task_interrupted", "migration_failed", "task_outdated", "task_error", "extension_error", "host_error", "listener_error"];
|
|
84
|
+
};
|
|
85
|
+
readonly reason: {
|
|
86
|
+
readonly type: "string";
|
|
87
|
+
readonly required: false;
|
|
88
|
+
readonly description: "Fixed report reason, when present.";
|
|
89
|
+
readonly values: readonly ["threw", "restart_limit", "interrupted", "missing_task", "task_too_old", "migration_failed"];
|
|
90
|
+
};
|
|
91
|
+
readonly extension: {
|
|
92
|
+
readonly type: "string";
|
|
93
|
+
readonly required: false;
|
|
94
|
+
readonly description: "Registered extension name, when present.";
|
|
95
|
+
};
|
|
96
|
+
readonly "task.id": {
|
|
97
|
+
readonly type: "number";
|
|
98
|
+
readonly required: false;
|
|
99
|
+
readonly description: "Task ID, when present.";
|
|
100
|
+
readonly cardinality: "high";
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
readonly status: {
|
|
106
|
+
readonly default: "ok";
|
|
107
|
+
readonly errorWhen: "Admission failed.";
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
readonly "pi.durable.phase": {
|
|
111
|
+
readonly description: "One task phase invocation, including its decision commit, never a wait or restart.";
|
|
112
|
+
readonly parents: {
|
|
113
|
+
readonly kind: "any";
|
|
114
|
+
};
|
|
115
|
+
readonly startAttributes: {
|
|
116
|
+
readonly "task.id": {
|
|
117
|
+
readonly type: "number";
|
|
118
|
+
readonly required: true;
|
|
119
|
+
readonly description: "Task ID.";
|
|
120
|
+
readonly cardinality: "high";
|
|
121
|
+
};
|
|
122
|
+
readonly "task.name": {
|
|
123
|
+
readonly type: "string";
|
|
124
|
+
readonly required: true;
|
|
125
|
+
readonly description: "Registered task name.";
|
|
126
|
+
};
|
|
127
|
+
readonly phase: {
|
|
128
|
+
readonly type: "string";
|
|
129
|
+
readonly required: true;
|
|
130
|
+
readonly description: "Invoked checkpoint phase.";
|
|
131
|
+
};
|
|
132
|
+
readonly kind: {
|
|
133
|
+
readonly type: "string";
|
|
134
|
+
readonly required: true;
|
|
135
|
+
readonly values: readonly ["run", "abort"];
|
|
136
|
+
readonly description: "Invocation kind.";
|
|
137
|
+
};
|
|
138
|
+
readonly attempt: {
|
|
139
|
+
readonly type: "number";
|
|
140
|
+
readonly required: false;
|
|
141
|
+
readonly description: "Checkpoint attempt, when present.";
|
|
142
|
+
};
|
|
143
|
+
readonly resumed: {
|
|
144
|
+
readonly type: "boolean";
|
|
145
|
+
readonly required: true;
|
|
146
|
+
readonly description: "First invocation of a task loaded in this process.";
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
readonly endAttributes: {
|
|
150
|
+
readonly outcome: {
|
|
151
|
+
readonly type: "string";
|
|
152
|
+
readonly description: "next=<phase>, waiting, sleeping, done, faulted, or aborted.";
|
|
153
|
+
};
|
|
154
|
+
readonly "tool.name": {
|
|
155
|
+
readonly type: "string";
|
|
156
|
+
readonly description: "Called tool name.";
|
|
157
|
+
};
|
|
158
|
+
readonly "tool.call_id": {
|
|
159
|
+
readonly type: "string";
|
|
160
|
+
readonly description: "Transcript tool call ID.";
|
|
161
|
+
readonly cardinality: "high";
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
readonly events: {
|
|
165
|
+
readonly "pi.durable.entry": {
|
|
166
|
+
readonly description: "A transcript entry was committed; content remains in the transcript.";
|
|
167
|
+
readonly attributes: {
|
|
168
|
+
readonly "entry.id": {
|
|
169
|
+
readonly type: "number";
|
|
170
|
+
readonly required: true;
|
|
171
|
+
readonly description: "Transcript entry ID.";
|
|
172
|
+
readonly cardinality: "high";
|
|
173
|
+
};
|
|
174
|
+
readonly "entry.kind": {
|
|
175
|
+
readonly type: "string";
|
|
176
|
+
readonly required: true;
|
|
177
|
+
readonly description: "Entry kind.";
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
readonly "pi.durable.submission": {
|
|
182
|
+
readonly description: "A submission was settled.";
|
|
183
|
+
readonly attributes: {
|
|
184
|
+
readonly "submission.id": {
|
|
185
|
+
readonly type: "number";
|
|
186
|
+
readonly required: true;
|
|
187
|
+
readonly description: "Submission ID.";
|
|
188
|
+
readonly cardinality: "high";
|
|
189
|
+
};
|
|
190
|
+
readonly status: {
|
|
191
|
+
readonly type: "string";
|
|
192
|
+
readonly required: true;
|
|
193
|
+
readonly values: readonly ["done", "unanswered"];
|
|
194
|
+
readonly description: "Settlement.";
|
|
195
|
+
};
|
|
196
|
+
readonly "answer.entry_id": {
|
|
197
|
+
readonly type: "number";
|
|
198
|
+
readonly required: false;
|
|
199
|
+
readonly description: "Answer entry ID.";
|
|
200
|
+
readonly cardinality: "high";
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
readonly "pi.durable.report": {
|
|
205
|
+
readonly description: "A report was raised; no error payload is recorded.";
|
|
206
|
+
readonly attributes: {
|
|
207
|
+
readonly type: {
|
|
208
|
+
readonly type: "string";
|
|
209
|
+
readonly required: true;
|
|
210
|
+
readonly description: "Report kind (`Report.kind`).";
|
|
211
|
+
readonly values: readonly ["storage_failed", "task_faulted", "task_interrupted", "migration_failed", "task_outdated", "task_error", "extension_error", "host_error", "listener_error"];
|
|
212
|
+
};
|
|
213
|
+
readonly reason: {
|
|
214
|
+
readonly type: "string";
|
|
215
|
+
readonly required: false;
|
|
216
|
+
readonly description: "Fixed report reason, when present.";
|
|
217
|
+
readonly values: readonly ["threw", "restart_limit", "interrupted", "missing_task", "task_too_old", "migration_failed"];
|
|
218
|
+
};
|
|
219
|
+
readonly extension: {
|
|
220
|
+
readonly type: "string";
|
|
221
|
+
readonly required: false;
|
|
222
|
+
readonly description: "Registered extension name, when present.";
|
|
223
|
+
};
|
|
224
|
+
readonly "task.id": {
|
|
225
|
+
readonly type: "number";
|
|
226
|
+
readonly required: false;
|
|
227
|
+
readonly description: "Task ID, when present.";
|
|
228
|
+
readonly cardinality: "high";
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
readonly "pi.durable.checkpoint": {
|
|
233
|
+
readonly description: "The running checkpoint's phase changed while the invocation continued.";
|
|
234
|
+
readonly attributes: {
|
|
235
|
+
readonly phase: {
|
|
236
|
+
readonly type: "string";
|
|
237
|
+
readonly required: true;
|
|
238
|
+
readonly description: "Committed checkpoint phase.";
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
readonly "pi.durable.replay": {
|
|
243
|
+
readonly description: "A nested tool call was answered from its stored result.";
|
|
244
|
+
readonly attributes: {
|
|
245
|
+
readonly "tool.name": {
|
|
246
|
+
readonly type: "string";
|
|
247
|
+
readonly required: true;
|
|
248
|
+
readonly description: "Called tool name.";
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
readonly status: {
|
|
254
|
+
readonly default: "ok";
|
|
255
|
+
readonly errorWhen: "Faulted, failed, and orphaned outcomes use task_faulted, task_failed, and task_orphaned with a diagnostic capped at 500 characters. Aborted outcomes keep status ok.";
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
readonly metrics: {
|
|
260
|
+
readonly "pi.durable.reports": {
|
|
261
|
+
readonly kind: "counter";
|
|
262
|
+
readonly description: "Reports raised, grouped by their fixed kind.";
|
|
263
|
+
readonly attributes: {
|
|
264
|
+
type: {
|
|
265
|
+
readonly type: "string";
|
|
266
|
+
readonly required: true;
|
|
267
|
+
readonly description: "Report kind (`Report.kind`).";
|
|
268
|
+
readonly values: readonly ["storage_failed", "task_faulted", "task_interrupted", "migration_failed", "task_outdated", "task_error", "extension_error", "host_error", "listener_error"];
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
readonly "pi.durable.phase.duration": {
|
|
273
|
+
readonly kind: "histogram";
|
|
274
|
+
readonly unit: "ms";
|
|
275
|
+
readonly description: "Duration of a phase invocation and its decision commit.";
|
|
276
|
+
readonly attributes: {
|
|
277
|
+
readonly task: {
|
|
278
|
+
readonly type: "string";
|
|
279
|
+
readonly required: true;
|
|
280
|
+
readonly description: "Registered task name.";
|
|
281
|
+
};
|
|
282
|
+
readonly phase: {
|
|
283
|
+
readonly type: "string";
|
|
284
|
+
readonly required: true;
|
|
285
|
+
readonly description: "Invoked checkpoint phase.";
|
|
286
|
+
};
|
|
287
|
+
readonly outcome: {
|
|
288
|
+
readonly type: "string";
|
|
289
|
+
readonly required: true;
|
|
290
|
+
readonly description: "Phase outcome.";
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
};
|
|
294
|
+
readonly "pi.durable.tasks.active": {
|
|
295
|
+
readonly kind: "upDownCounter";
|
|
296
|
+
readonly description: "Live tasks held by this Harness; decremented at terminal settlement or close.";
|
|
297
|
+
readonly attributes: {
|
|
298
|
+
readonly task: {
|
|
299
|
+
readonly type: "string";
|
|
300
|
+
readonly required: true;
|
|
301
|
+
readonly description: "Registered task name.";
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
};
|
|
306
|
+
};
|
|
307
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/harness/telemetry.ts"],"names":[],"mappings":"AAgDA,6GAA6G;AAC7G,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAwBxB,kBAAkB;0CAtEjB,sEAAsE;;iCAElF,UAAU;qCAAI,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAQ,WAAW,EAAE,sBAAsB;qCAAE,WAAW,EAAE,MAAM;;iCACtG,YAAY;qCAAI,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAQ,WAAW,EAAE,aAAa;;;;gBAmEpC,uBAAuB;0CAjCjD,2BAA2B;;iCAEvC,eAAe;qCAAI,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAQ,WAAW,EAAE,gBAAgB;qCAAE,WAAW,EAAE,MAAM;;iCACrG,MAAM;qCAAI,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAQ,MAAM,YAAG,MAAM,EAAE,YAAY;qCAAG,WAAW,EAAE,aAAa;;iCACpG,iBAAiB;qCAAI,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAS,WAAW,EAAE,kBAAkB;qCAAE,WAAW,EAAE,MAAM;;;;gBA6B/B,mBAAmB;0CArClF,oDAAoD;;;qCAzBhE,IAAI,EAAE,QAAQ;qCACd,QAAQ;qCACR,WAAW,EAAE,8BAA8B;qCAC3C,MAAM,YACL,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,gBAAgB;;;qCAIjB,IAAI,EAAE,QAAQ;qCACd,QAAQ;qCACR,WAAW,EAAE,oCAAoC;qCACjD,MAAM,YAAG,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB;;;qCAExF,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAS,WAAW,EAAE,0CAA0C;;;qCACxF,IAAI,EAAE,QAAQ;qCAAE,QAAQ;qCAAS,WAAW,EAAE,wBAAwB;qCAAE,WAAW,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAuFxF,IAAI;mCA7Gb,QAAQ;;0CAED,8BAA8B;+CAE1C,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmHjB,CAAC"}
|