@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,15 +1,25 @@
|
|
|
1
1
|
import { type Context } from "@earendil-works/chord";
|
|
2
|
+
import { type TelemetryContext, type TelemetrySpan } from "@earendil-works/pi-telemetry";
|
|
2
3
|
import type { SessionImpl } from "../session/session.ts";
|
|
3
|
-
import type { ConversationId,
|
|
4
|
+
import type { ConversationId, SubmissionId, SubmissionRecord, Tx } from "../types.ts";
|
|
4
5
|
import { type QueueModes } from "./inbox.ts";
|
|
5
6
|
import type { SettledSubmissionRecord, Submission, SubmissionDraft } from "./types.ts";
|
|
6
7
|
type AbortResult = "aborted" | "already_placed" | "settled";
|
|
8
|
+
type Admission = {
|
|
9
|
+
readonly id: SubmissionId;
|
|
10
|
+
readonly status: "queued" | "placed" | "done";
|
|
11
|
+
};
|
|
7
12
|
/** Admission, waits, and withdrawal of the durable submissions of one Harness. */
|
|
8
13
|
export declare class Submissions {
|
|
9
14
|
#private;
|
|
10
|
-
constructor(session: SessionImpl,
|
|
15
|
+
constructor(session: SessionImpl, now: () => number, queueModes: () => QueueModes, resume: () => void, telemetry?: TelemetryContext);
|
|
11
16
|
/** Admit a submission in one commit; see `admitSubmission()`. */
|
|
12
17
|
submit(conversationId: ConversationId, draft: SubmissionDraft, context: Context): Promise<Submission>;
|
|
18
|
+
/**
|
|
19
|
+
* Admit a submission inside the caller's commit `tx`, with the rules of `submit()`. The admission is stored or lost
|
|
20
|
+
* with that commit. It must come before the commit's first table write, another admission's included.
|
|
21
|
+
*/
|
|
22
|
+
admit(tx: Tx, conversationId: ConversationId, draft: SubmissionDraft): Promise<SubmissionId>;
|
|
13
23
|
/** Handle for an existing submission, or `undefined`. */
|
|
14
24
|
get(id: SubmissionId, context: Context): Promise<Submission | undefined>;
|
|
15
25
|
status(id: SubmissionId, context: Context): Promise<SubmissionRecord>;
|
|
@@ -18,15 +28,17 @@ export declare class Submissions {
|
|
|
18
28
|
abort(id: SubmissionId, context: Context, conversationId?: ConversationId): Promise<AbortResult | "not_found">;
|
|
19
29
|
}
|
|
20
30
|
/**
|
|
21
|
-
* Admit a submission inside a commit (spec §6); `Conversation.submit()` and conversation-owned compactions
|
|
22
|
-
* known request ID returns its existing submission without writing. A display-only write (only `kind` and
|
|
23
|
-
* appended and settled `done` at once, busy or not, as it changes nothing the model sees; only behind a
|
|
24
|
-
* queues, so it lands after the reset instead of before it in the context the reset ends. A busy
|
|
25
|
-
* `pi.inbox`, or rejects `whenBusy: "reject"` input
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
31
|
+
* Admit a submission inside a commit (spec §6); both `Conversation.submit()` forms and conversation-owned compactions
|
|
32
|
+
* share it. A known request ID returns its existing submission without writing. A display-only write (only `kind` and
|
|
33
|
+
* `data`) is appended and settled `done` at once, busy or not, as it changes nothing the model sees; only behind a
|
|
34
|
+
* queued reset it queues, so it lands after the reset instead of before it in the context the reset ends. A busy
|
|
35
|
+
* conversation queues anything else in `pi.inbox`, or rejects `whenBusy: "reject"` input and any continue with
|
|
36
|
+
* `ConversationBusy`; an idle one rejects `whenIdle: "reject"` input with `ConversationIdle`. An idle continue places
|
|
37
|
+
* queued items and starts a run with them and itself, placing no entry of its own. An idle conversation with queued
|
|
38
|
+
* items queues it behind them and runs a final boundary. Otherwise idle input places its entry (`pi.user`, or the
|
|
39
|
+
* input's own) and starts a run, and an idle write appends its entry and settles `done`, or `stale` when its head
|
|
40
|
+
* reaches before the active range.
|
|
29
41
|
*/
|
|
30
|
-
export declare function admitSubmission(tx: Tx, conversationId: ConversationId, draft: SubmissionDraft, now: number, queueModes: QueueModes): Promise<
|
|
42
|
+
export declare function admitSubmission(tx: Tx, conversationId: ConversationId, draft: SubmissionDraft, now: number, queueModes: QueueModes, span?: TelemetrySpan): Promise<Admission>;
|
|
31
43
|
export {};
|
|
32
44
|
//# sourceMappingURL=submissions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submissions.d.ts","sourceRoot":"","sources":["../../src/harness/submissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAqC,MAAM,uBAAuB,CAAC;AAExF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"submissions.d.ts","sourceRoot":"","sources":["../../src/harness/submissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAqC,MAAM,uBAAuB,CAAC;AAExF,OAAO,EAGN,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAc,YAAY,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAElG,OAAO,EASN,KAAK,UAAU,EAEf,MAAM,YAAY,CAAC;AAGpB,OAAO,KAAK,EAAc,uBAAuB,EAAE,UAAU,EAAE,eAAe,EAAa,MAAM,YAAY,CAAC;AAG9G,KAAK,WAAW,GAAG,SAAS,GAAG,gBAAgB,GAAG,SAAS,CAAC;AAC5D,KAAK,SAAS,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAA;CAAE,CAAC;AAE9F,kFAAkF;AAClF,qBAAa,WAAW;;IAWvB,YACC,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,MAAM,EACjB,UAAU,EAAE,MAAM,UAAU,EAC5B,MAAM,EAAE,MAAM,IAAI,EAClB,SAAS,GAAE,gBAAyC,EAYpD;IAED,iEAAiE;IAC3D,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAQ1G;IAED;;;OAGG;IACG,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAQjG;IAkCD,yDAAyD;IACnD,GAAG,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAG7E;IAEK,MAAM,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAI1E;IAEK,IAAI,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAY/E;IAED,kHAAkH;IAClH,KAAK,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC,CAa7G;CAUD;AAwCD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACpC,EAAE,EAAE,EAAE,EACN,cAAc,EAAE,cAAc,EAC9B,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,EACtB,IAAI,CAAC,EAAE,aAAa,GAClB,OAAO,CAAC,SAAS,CAAC,CAuFpB"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { copyJson } from "@earendil-works/chord";
|
|
2
|
-
import {
|
|
2
|
+
import { withTelemetry } from "@earendil-works/chord/context";
|
|
3
|
+
import { createTypedSpanStarter, NOOP_TELEMETRY_CONTEXT, } from "@earendil-works/pi-telemetry";
|
|
4
|
+
import { ConversationBusy, ConversationIdle, ReadAfterWrite } from "../errors.js";
|
|
3
5
|
import { startRun } from "./generation.js";
|
|
4
6
|
import { appendInput, applyBoundary, hasQueuedReset, InboxDoc, isDisplayOnly, isStale, pickInputEntry, prepareBoundary, removeInboxItem, } from "./inbox.js";
|
|
5
7
|
import { LiveDoc } from "./live.js";
|
|
8
|
+
import { DURABLE_TELEMETRY_SCHEMA } from "./telemetry.js";
|
|
6
9
|
import { closedError, Waiters } from "./util.js";
|
|
7
10
|
/** Admission, waits, and withdrawal of the durable submissions of one Harness. */
|
|
8
11
|
export class Submissions {
|
|
12
|
+
#telemetry;
|
|
9
13
|
#session;
|
|
10
|
-
#storage;
|
|
11
14
|
#now;
|
|
12
15
|
/** Read at each admission, on the Session line. */
|
|
13
16
|
#queueModes;
|
|
@@ -15,13 +18,13 @@ export class Submissions {
|
|
|
15
18
|
#resume;
|
|
16
19
|
#waiters = new Waiters();
|
|
17
20
|
#closed = false;
|
|
18
|
-
constructor(session,
|
|
21
|
+
constructor(session, now, queueModes, resume, telemetry = NOOP_TELEMETRY_CONTEXT) {
|
|
22
|
+
this.#telemetry = telemetry;
|
|
19
23
|
this.#session = session;
|
|
20
|
-
this.#storage = storage;
|
|
21
24
|
this.#now = now;
|
|
22
25
|
this.#queueModes = queueModes;
|
|
23
26
|
this.#resume = resume;
|
|
24
|
-
session.
|
|
27
|
+
session.followCommits((publication) => this.#observe(publication));
|
|
25
28
|
session.subscribeClose(() => {
|
|
26
29
|
this.#closed = true;
|
|
27
30
|
this.#waiters.rejectAll(closedError(this.#session));
|
|
@@ -29,17 +32,53 @@ export class Submissions {
|
|
|
29
32
|
}
|
|
30
33
|
/** Admit a submission in one commit; see `admitSubmission()`. */
|
|
31
34
|
async submit(conversationId, draft, context) {
|
|
32
|
-
this.#
|
|
33
|
-
const id = await this.#session.commitWith((tx) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes()), context);
|
|
35
|
+
const { id } = await this.#traced(conversationId, draft, context, (span) => this.#session.commitWith((tx) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes(), span), withTelemetry(span, context)));
|
|
34
36
|
return new SubmissionHandle(id, this);
|
|
35
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Admit a submission inside the caller's commit `tx`, with the rules of `submit()`. The admission is stored or lost
|
|
40
|
+
* with that commit. It must come before the commit's first table write, another admission's included.
|
|
41
|
+
*/
|
|
42
|
+
async admit(tx, conversationId, draft) {
|
|
43
|
+
if (!this.#session.ownsTransaction(tx))
|
|
44
|
+
throw new Error("The transaction belongs to another Session");
|
|
45
|
+
// Enforced on every path: admission reads tables only on some (request IDs, an idle boundary, a steer's trace).
|
|
46
|
+
if (tx.hasTableWrite)
|
|
47
|
+
throw new ReadAfterWrite("submit(tx, draft)");
|
|
48
|
+
const admission = await this.#traced(conversationId, draft, tx.context, (span) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes(), span));
|
|
49
|
+
return admission.id;
|
|
50
|
+
}
|
|
51
|
+
/** Run one admission in its `pi.durable.submit` span, asking for progress first, as the run it starts needs it. */
|
|
52
|
+
#traced(conversationId, draft, context, admit) {
|
|
53
|
+
this.#resume();
|
|
54
|
+
// Inputs and continues start runs: root traces linked to their callers.
|
|
55
|
+
const startsRun = draft.type !== "write";
|
|
56
|
+
const parent = startsRun ? this.#telemetry : context.telemetry;
|
|
57
|
+
return createTypedSpanStarter(parent, [DURABLE_TELEMETRY_SCHEMA])("pi.durable.submit", {
|
|
58
|
+
"submission.type": draft.type,
|
|
59
|
+
"conversation.id": conversationId,
|
|
60
|
+
}, async (span) => {
|
|
61
|
+
if (startsRun)
|
|
62
|
+
span.addLink({ context: context.telemetry });
|
|
63
|
+
try {
|
|
64
|
+
const admission = await admit(span);
|
|
65
|
+
span.setAttributes({ "submission.id": admission.id, result: admission.status });
|
|
66
|
+
return admission;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
// Error text may contain caller content. Record only the status.
|
|
70
|
+
span.setStatus({ status: "error" });
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
36
75
|
/** Handle for an existing submission, or `undefined`. */
|
|
37
76
|
async get(id, context) {
|
|
38
|
-
const record = await this.#session.readOnLine(() =>
|
|
77
|
+
const record = await this.#session.readOnLine((storage) => storage.submission(id, context));
|
|
39
78
|
return record === undefined ? undefined : new SubmissionHandle(record.id, this);
|
|
40
79
|
}
|
|
41
80
|
async status(id, context) {
|
|
42
|
-
const record = await this.#session.readOnLine(() =>
|
|
81
|
+
const record = await this.#session.readOnLine((storage) => storage.submission(id, context));
|
|
43
82
|
if (record === undefined)
|
|
44
83
|
throw new Error(`Submission ${id} does not exist`);
|
|
45
84
|
return record;
|
|
@@ -47,8 +86,8 @@ export class Submissions {
|
|
|
47
86
|
async wait(id, context) {
|
|
48
87
|
this.#resume();
|
|
49
88
|
// Check and register on the line so no settling publication falls between them.
|
|
50
|
-
const found = await this.#session.readOnLine(async () => {
|
|
51
|
-
const record = await
|
|
89
|
+
const found = await this.#session.readOnLine(async (storage) => {
|
|
90
|
+
const record = await storage.submission(id, context);
|
|
52
91
|
if (record === undefined)
|
|
53
92
|
throw new Error(`Submission ${id} does not exist`);
|
|
54
93
|
if (isSettled(record))
|
|
@@ -76,6 +115,9 @@ export class Submissions {
|
|
|
76
115
|
}, context);
|
|
77
116
|
}
|
|
78
117
|
#observe(publication) {
|
|
118
|
+
// A commit held in memory changes documents only.
|
|
119
|
+
if (publication.kind === "memory")
|
|
120
|
+
return;
|
|
79
121
|
for (const change of publication.changes) {
|
|
80
122
|
if (change.type !== "submission" || !isSettled(change.value))
|
|
81
123
|
continue;
|
|
@@ -114,16 +156,18 @@ function checkInputEntry(entry) {
|
|
|
114
156
|
}
|
|
115
157
|
}
|
|
116
158
|
/**
|
|
117
|
-
* Admit a submission inside a commit (spec §6); `Conversation.submit()` and conversation-owned compactions
|
|
118
|
-
* known request ID returns its existing submission without writing. A display-only write (only `kind` and
|
|
119
|
-
* appended and settled `done` at once, busy or not, as it changes nothing the model sees; only behind a
|
|
120
|
-
* queues, so it lands after the reset instead of before it in the context the reset ends. A busy
|
|
121
|
-
* `pi.inbox`, or rejects `whenBusy: "reject"` input
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
159
|
+
* Admit a submission inside a commit (spec §6); both `Conversation.submit()` forms and conversation-owned compactions
|
|
160
|
+
* share it. A known request ID returns its existing submission without writing. A display-only write (only `kind` and
|
|
161
|
+
* `data`) is appended and settled `done` at once, busy or not, as it changes nothing the model sees; only behind a
|
|
162
|
+
* queued reset it queues, so it lands after the reset instead of before it in the context the reset ends. A busy
|
|
163
|
+
* conversation queues anything else in `pi.inbox`, or rejects `whenBusy: "reject"` input and any continue with
|
|
164
|
+
* `ConversationBusy`; an idle one rejects `whenIdle: "reject"` input with `ConversationIdle`. An idle continue places
|
|
165
|
+
* queued items and starts a run with them and itself, placing no entry of its own. An idle conversation with queued
|
|
166
|
+
* items queues it behind them and runs a final boundary. Otherwise idle input places its entry (`pi.user`, or the
|
|
167
|
+
* input's own) and starts a run, and an idle write appends its entry and settles `done`, or `stale` when its head
|
|
168
|
+
* reaches before the active range.
|
|
125
169
|
*/
|
|
126
|
-
export async function admitSubmission(tx, conversationId, draft, now, queueModes) {
|
|
170
|
+
export async function admitSubmission(tx, conversationId, draft, now, queueModes, span) {
|
|
127
171
|
if (draft.type === "input" && draft.entry !== undefined)
|
|
128
172
|
checkInputEntry(draft.entry);
|
|
129
173
|
if (draft.requestId !== undefined) {
|
|
@@ -132,27 +176,48 @@ export async function admitSubmission(tx, conversationId, draft, now, queueModes
|
|
|
132
176
|
if (existing.type !== draft.type) {
|
|
133
177
|
throw new Error(`Request ${draft.requestId} already identifies a submission of type ${existing.type}`);
|
|
134
178
|
}
|
|
135
|
-
return existing.id;
|
|
179
|
+
return { id: existing.id, status: existing.status === "unanswered" ? "done" : existing.status };
|
|
136
180
|
}
|
|
137
181
|
}
|
|
138
|
-
const
|
|
182
|
+
const fields = { conversationId, requestId: draft.requestId, trace: span?.propagation?.inject(span) };
|
|
139
183
|
if (draft.type === "write" &&
|
|
140
184
|
isDisplayOnly(draft.entry) &&
|
|
141
185
|
!hasQueuedReset((await tx.doc(InboxDoc, conversationId)).items)) {
|
|
142
186
|
const entry = await tx.appendEntry(conversationId, draft.entry);
|
|
143
|
-
const write = {
|
|
144
|
-
return (await tx.createSubmission(write)).id;
|
|
187
|
+
const write = { ...fields, type: "write", status: "done", entry: entry.id };
|
|
188
|
+
return { id: (await tx.createSubmission(write)).id, status: "done" };
|
|
145
189
|
}
|
|
146
190
|
const live = await tx.doc(LiveDoc, conversationId);
|
|
147
191
|
const busy = live.run !== undefined;
|
|
192
|
+
if (draft.type === "input" &&
|
|
193
|
+
draft.whenBusy === "steer" &&
|
|
194
|
+
live.run !== undefined &&
|
|
195
|
+
span?.propagation !== undefined) {
|
|
196
|
+
const run = await tx.task(live.run.taskId);
|
|
197
|
+
if (run?.trace !== undefined)
|
|
198
|
+
span.addLink({ context: span.propagation.extract(run.trace) });
|
|
199
|
+
}
|
|
148
200
|
if (busy && draft.type === "input" && draft.whenBusy === "reject")
|
|
149
201
|
throw new ConversationBusy(conversationId);
|
|
202
|
+
if (!busy && draft.type === "input" && draft.whenIdle === "reject")
|
|
203
|
+
throw new ConversationIdle(conversationId);
|
|
204
|
+
if (draft.type === "continue") {
|
|
205
|
+
// Never queued: whether a run can continue depends on how the current one ends. Rejected before any write.
|
|
206
|
+
if (busy)
|
|
207
|
+
throw new ConversationBusy(conversationId);
|
|
208
|
+
const boundary = await prepareBoundary(tx, conversationId, queueModes);
|
|
209
|
+
const { id } = await tx.createSubmission({ ...fields, type: "continue", status: "placed" });
|
|
210
|
+
// Items an earlier failed run left queued (`afterFailedRun: "keep"`) are placed first and join the run. Its history
|
|
211
|
+
// starts with the failed run's, so `afterRun` hooks see what that run did.
|
|
212
|
+
const { users, first } = await applyBoundary(tx, boundary, "final", now);
|
|
213
|
+
await startRun(tx, conversationId, live, { inputs: [...users, id], first: live.runFailure?.first ?? first });
|
|
214
|
+
return { id, status: "placed" };
|
|
215
|
+
}
|
|
150
216
|
// A boundary reads the table, so it is prepared before the first table write; a busy one needs none.
|
|
151
217
|
const boundary = busy ? undefined : await prepareBoundary(tx, conversationId, queueModes);
|
|
152
218
|
if (boundary === undefined || boundary.inbox.items.length > 0) {
|
|
153
219
|
const { id } = await tx.createSubmission({
|
|
154
|
-
|
|
155
|
-
...requestId,
|
|
220
|
+
...fields,
|
|
156
221
|
type: draft.type,
|
|
157
222
|
status: "queued",
|
|
158
223
|
});
|
|
@@ -170,25 +235,28 @@ export async function admitSubmission(tx, conversationId, draft, now, queueModes
|
|
|
170
235
|
items.push({ id, mode, content, ...entry });
|
|
171
236
|
}
|
|
172
237
|
if (boundary === undefined)
|
|
173
|
-
return id;
|
|
174
|
-
const { users } = await applyBoundary(tx, boundary, "final", now);
|
|
238
|
+
return { id, status: "queued" };
|
|
239
|
+
const { users, first } = await applyBoundary(tx, boundary, "final", now);
|
|
175
240
|
if (users.length > 0)
|
|
176
|
-
await startRun(tx, conversationId, live, users);
|
|
177
|
-
return id;
|
|
241
|
+
await startRun(tx, conversationId, live, { inputs: users, first });
|
|
242
|
+
return { id, status: draft.type === "write" ? "done" : users.at(-1) === id ? "placed" : "queued" };
|
|
178
243
|
}
|
|
179
244
|
if (draft.type === "write") {
|
|
180
245
|
if (isStale(boundary, draft.entry)) {
|
|
181
246
|
const stale = { status: "unanswered", reason: "stale" };
|
|
182
|
-
return
|
|
247
|
+
return {
|
|
248
|
+
id: (await tx.createSubmission({ ...fields, type: "write", ...stale })).id,
|
|
249
|
+
status: "done",
|
|
250
|
+
};
|
|
183
251
|
}
|
|
184
252
|
const entry = await tx.appendEntry(conversationId, draft.entry);
|
|
185
|
-
const write = {
|
|
186
|
-
return (await tx.createSubmission(write)).id;
|
|
253
|
+
const write = { ...fields, type: "write", status: "done", entry: entry.id };
|
|
254
|
+
return { id: (await tx.createSubmission(write)).id, status: "done" };
|
|
187
255
|
}
|
|
188
256
|
const entry = await appendInput(tx, conversationId, draft.content, draft.entry, now);
|
|
189
|
-
const input = {
|
|
257
|
+
const input = { ...fields, type: "input", status: "placed", entry: entry.id };
|
|
190
258
|
const { id } = await tx.createSubmission(input);
|
|
191
|
-
await startRun(tx, conversationId, live, [id]);
|
|
192
|
-
return id;
|
|
259
|
+
await startRun(tx, conversationId, live, { inputs: [id], first: entry.id });
|
|
260
|
+
return { id, status: "placed" };
|
|
193
261
|
}
|
|
194
262
|
//# sourceMappingURL=submissions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submissions.js","sourceRoot":"","sources":["../../src/harness/submissions.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Context, copyJson, type JsonRepresentation } from \"@earendil-works/chord\";\nimport { ConversationBusy } from \"../errors.ts\";\nimport type { SessionImpl } from \"../session/session.ts\";\nimport type {\n\tCommitPublication,\n\tConversationId,\n\tJsonObject,\n\tStorage,\n\tSubmissionId,\n\tSubmissionRecord,\n\tTx,\n} from \"../types.ts\";\nimport { startRun } from \"./generation.ts\";\nimport {\n\tappendInput,\n\tapplyBoundary,\n\thasQueuedReset,\n\tInboxDoc,\n\tisDisplayOnly,\n\tisStale,\n\tpickInputEntry,\n\tprepareBoundary,\n\ttype QueueModes,\n\tremoveInboxItem,\n} from \"./inbox.ts\";\nimport { LiveDoc } from \"./live.ts\";\nimport type { InputEntry, SettledSubmissionRecord, Submission, SubmissionDraft, UserInput } from \"./types.ts\";\nimport { closedError, Waiters } from \"./util.ts\";\n\ntype AbortResult = \"aborted\" | \"already_placed\" | \"settled\";\n\n/** Admission, waits, and withdrawal of the durable submissions of one Harness. */\nexport class Submissions {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\treadonly #now: () => number;\n\t/** Read at each admission, on the Session line. */\n\treadonly #queueModes: () => QueueModes;\n\t/** Enable task scheduling; submitting or waiting asks for progress. */\n\treadonly #resume: () => void;\n\treadonly #waiters = new Waiters<SubmissionId, SettledSubmissionRecord>();\n\t#closed = false;\n\n\tconstructor(\n\t\tsession: SessionImpl,\n\t\tstorage: Storage,\n\t\tnow: () => number,\n\t\tqueueModes: () => QueueModes,\n\t\tresume: () => void,\n\t) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tthis.#now = now;\n\t\tthis.#queueModes = queueModes;\n\t\tthis.#resume = resume;\n\t\tsession.observeCommits((publication) => this.#observe(publication));\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tthis.#waiters.rejectAll(closedError(this.#session));\n\t\t});\n\t}\n\n\t/** Admit a submission in one commit; see `admitSubmission()`. */\n\tasync submit(conversationId: ConversationId, draft: SubmissionDraft, context: Context): Promise<Submission> {\n\t\tthis.#resume();\n\t\tconst id = await this.#session.commitWith(\n\t\t\t(tx) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes()),\n\t\t\tcontext,\n\t\t);\n\t\treturn new SubmissionHandle(id, this);\n\t}\n\n\t/** Handle for an existing submission, or `undefined`. */\n\tasync get(id: SubmissionId, context: Context): Promise<Submission | undefined> {\n\t\tconst record = await this.#session.readOnLine(() => this.#storage.submission(id, context));\n\t\treturn record === undefined ? undefined : new SubmissionHandle(record.id, this);\n\t}\n\n\tasync status(id: SubmissionId, context: Context): Promise<SubmissionRecord> {\n\t\tconst record = await this.#session.readOnLine(() => this.#storage.submission(id, context));\n\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\treturn record;\n\t}\n\n\tasync wait(id: SubmissionId, context: Context): Promise<SettledSubmissionRecord> {\n\t\tthis.#resume();\n\t\t// Check and register on the line so no settling publication falls between them.\n\t\tconst found = await this.#session.readOnLine(async () => {\n\t\t\tconst record = await this.#storage.submission(id, context);\n\t\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\t\tif (isSettled(record)) return { promise: Promise.resolve(record) };\n\t\t\t// Close rejects registered waiters synchronously and may begin during the read.\n\t\t\tif (this.#closed) throw closedError(this.#session);\n\t\t\treturn { promise: this.#waiters.add(id, context) };\n\t\t});\n\t\treturn found.promise;\n\t}\n\n\t/** Withdraw a queued submission and remove its inbox item; placed inputs and settled submissions are reported. */\n\tabort(id: SubmissionId, context: Context, conversationId?: ConversationId): Promise<AbortResult | \"not_found\"> {\n\t\treturn this.#session.commitWith(async (tx) => {\n\t\t\tconst record = await tx.submission(id);\n\t\t\tif (record === undefined || (conversationId !== undefined && record.conversationId !== conversationId)) {\n\t\t\t\treturn \"not_found\";\n\t\t\t}\n\t\t\tif (record.status === \"queued\") {\n\t\t\t\ttx.settleSubmission(id, { status: \"unanswered\", reason: \"aborted\" });\n\t\t\t\tawait removeInboxItem(tx, record.conversationId, id);\n\t\t\t\treturn \"aborted\";\n\t\t\t}\n\t\t\treturn record.status === \"placed\" ? \"already_placed\" : \"settled\";\n\t\t}, context);\n\t}\n\n\t#observe(publication: CommitPublication): void {\n\t\tfor (const change of publication.changes) {\n\t\t\tif (change.type !== \"submission\" || !isSettled(change.value)) continue;\n\t\t\tthis.#waiters.resolve(change.value.id, change.value);\n\t\t}\n\t}\n}\n\nclass SubmissionHandle implements Submission {\n\treadonly id: SubmissionId;\n\treadonly #submissions: Submissions;\n\n\tconstructor(id: SubmissionId, submissions: Submissions) {\n\t\tthis.id = id;\n\t\tthis.#submissions = submissions;\n\t}\n\n\tstatus(context: Context): Promise<SubmissionRecord> {\n\t\treturn this.#submissions.status(this.id, context);\n\t}\n\n\twait(context: Context): Promise<SettledSubmissionRecord> {\n\t\treturn this.#submissions.wait(this.id, context);\n\t}\n\n\tasync abort(context: Context): Promise<AbortResult> {\n\t\tconst result = await this.#submissions.abort(this.id, context);\n\t\tif (result === \"not_found\") throw new Error(`Submission ${this.id} does not exist`);\n\t\treturn result;\n\t}\n}\n\nfunction isSettled(record: SubmissionRecord): record is SettledSubmissionRecord {\n\treturn record.status === \"done\" || record.status === \"unanswered\";\n}\n\n/** Reject an input entry an untyped caller got wrong: its kind must be a non-empty string outside the `pi.` prefix. */\nfunction checkInputEntry(entry: InputEntry): void {\n\tconst { kind } = entry;\n\tif (typeof kind !== \"string\" || kind.length === 0 || kind.startsWith(\"pi.\")) {\n\t\tthrow new TypeError(\n\t\t\t`An input entry's kind must be a non-empty string not starting with \"pi.\", got ${String(kind)}`,\n\t\t);\n\t}\n}\n\n/**\n * Admit a submission inside a commit (spec §6); `Conversation.submit()` and conversation-owned compactions share it. A\n * known request ID returns its existing submission without writing. A display-only write (only `kind` and `data`) is\n * appended and settled `done` at once, busy or not, as it changes nothing the model sees; only behind a queued reset it\n * queues, so it lands after the reset instead of before it in the context the reset ends. A busy conversation queues anything else in\n * `pi.inbox`, or rejects `whenBusy: \"reject\"` input with `ConversationBusy`. An idle conversation with queued items\n * queues it behind them and runs a final boundary. Otherwise idle input places its entry (`pi.user`, or the input's\n * own) and starts a run, and an idle write appends its entry and settles `done`, or `stale` when its head reaches\n * before the active range.\n */\nexport async function admitSubmission(\n\ttx: Tx,\n\tconversationId: ConversationId,\n\tdraft: SubmissionDraft,\n\tnow: number,\n\tqueueModes: QueueModes,\n): Promise<SubmissionId> {\n\tif (draft.type === \"input\" && draft.entry !== undefined) checkInputEntry(draft.entry);\n\tif (draft.requestId !== undefined) {\n\t\tconst existing = await tx.submissionByRequest(conversationId, draft.requestId);\n\t\tif (existing !== undefined) {\n\t\t\tif (existing.type !== draft.type) {\n\t\t\t\tthrow new Error(`Request ${draft.requestId} already identifies a submission of type ${existing.type}`);\n\t\t\t}\n\t\t\treturn existing.id;\n\t\t}\n\t}\n\tconst requestId = draft.requestId === undefined ? {} : { requestId: draft.requestId };\n\tif (\n\t\tdraft.type === \"write\" &&\n\t\tisDisplayOnly(draft.entry) &&\n\t\t!hasQueuedReset((await tx.doc(InboxDoc, conversationId)).items)\n\t) {\n\t\tconst entry = await tx.appendEntry(conversationId, draft.entry);\n\t\tconst write = { conversationId, ...requestId, type: \"write\", status: \"done\", entry: entry.id } as const;\n\t\treturn (await tx.createSubmission(write)).id;\n\t}\n\tconst live = await tx.doc(LiveDoc, conversationId);\n\tconst busy = live.run !== undefined;\n\tif (busy && draft.type === \"input\" && draft.whenBusy === \"reject\") throw new ConversationBusy(conversationId);\n\t// A boundary reads the table, so it is prepared before the first table write; a busy one needs none.\n\tconst boundary = busy ? undefined : await prepareBoundary(tx, conversationId, queueModes);\n\tif (boundary === undefined || boundary.inbox.items.length > 0) {\n\t\tconst { id } = await tx.createSubmission({\n\t\t\tconversationId,\n\t\t\t...requestId,\n\t\t\ttype: draft.type,\n\t\t\tstatus: \"queued\",\n\t\t});\n\t\t// Hosts may leave optional fields `undefined`; drafts take strict JSON.\n\t\tconst value = copyJson(draft.type === \"write\" ? draft.entry : draft.content, {\n\t\t\tomitUndefinedProperties: true,\n\t\t});\n\t\tconst items = (boundary?.inbox ?? (await tx.doc(InboxDoc, conversationId))).items;\n\t\tif (draft.type === \"write\") items.push({ id, mode: \"write\", entry: value as JsonObject });\n\t\telse {\n\t\t\tconst mode = draft.whenBusy === \"steer\" ? \"steer\" : \"followUp\";\n\t\t\tconst content = value as JsonRepresentation<UserInput>;\n\t\t\tconst entry = draft.entry === undefined ? {} : { entry: pickInputEntry(draft.entry) };\n\t\t\titems.push({ id, mode, content, ...entry });\n\t\t}\n\t\tif (boundary === undefined) return id;\n\t\tconst { users } = await applyBoundary(tx, boundary, \"final\", now);\n\t\tif (users.length > 0) await startRun(tx, conversationId, live, users);\n\t\treturn id;\n\t}\n\tif (draft.type === \"write\") {\n\t\tif (isStale(boundary, draft.entry)) {\n\t\t\tconst stale = { status: \"unanswered\", reason: \"stale\" } as const;\n\t\t\treturn (await tx.createSubmission({ conversationId, ...requestId, type: \"write\", ...stale })).id;\n\t\t}\n\t\tconst entry = await tx.appendEntry(conversationId, draft.entry);\n\t\tconst write = { conversationId, ...requestId, type: \"write\", status: \"done\", entry: entry.id } as const;\n\t\treturn (await tx.createSubmission(write)).id;\n\t}\n\tconst entry = await appendInput(tx, conversationId, draft.content, draft.entry, now);\n\tconst input = { conversationId, ...requestId, type: \"input\", status: \"placed\", entry: entry.id } as const;\n\tconst { id } = await tx.createSubmission(input);\n\tawait startRun(tx, conversationId, live, [id]);\n\treturn id;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"submissions.js","sourceRoot":"","sources":["../../src/harness/submissions.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Context, copyJson, type JsonRepresentation } from \"@earendil-works/chord\";\nimport { withTelemetry } from \"@earendil-works/chord/context\";\nimport {\n\tcreateTypedSpanStarter,\n\tNOOP_TELEMETRY_CONTEXT,\n\ttype TelemetryContext,\n\ttype TelemetrySpan,\n} from \"@earendil-works/pi-telemetry\";\nimport { ConversationBusy, ConversationIdle, ReadAfterWrite } from \"../errors.ts\";\nimport type { ObservedCommit, SessionImpl } from \"../session/session.ts\";\nimport type { ConversationId, JsonObject, SubmissionId, SubmissionRecord, Tx } from \"../types.ts\";\nimport { startRun } from \"./generation.ts\";\nimport {\n\tappendInput,\n\tapplyBoundary,\n\thasQueuedReset,\n\tInboxDoc,\n\tisDisplayOnly,\n\tisStale,\n\tpickInputEntry,\n\tprepareBoundary,\n\ttype QueueModes,\n\tremoveInboxItem,\n} from \"./inbox.ts\";\nimport { LiveDoc } from \"./live.ts\";\nimport { DURABLE_TELEMETRY_SCHEMA } from \"./telemetry.ts\";\nimport type { InputEntry, SettledSubmissionRecord, Submission, SubmissionDraft, UserInput } from \"./types.ts\";\nimport { closedError, Waiters } from \"./util.ts\";\n\ntype AbortResult = \"aborted\" | \"already_placed\" | \"settled\";\ntype Admission = { readonly id: SubmissionId; readonly status: \"queued\" | \"placed\" | \"done\" };\n\n/** Admission, waits, and withdrawal of the durable submissions of one Harness. */\nexport class Submissions {\n\treadonly #telemetry: TelemetryContext;\n\treadonly #session: SessionImpl;\n\treadonly #now: () => number;\n\t/** Read at each admission, on the Session line. */\n\treadonly #queueModes: () => QueueModes;\n\t/** Enable task scheduling; submitting or waiting asks for progress. */\n\treadonly #resume: () => void;\n\treadonly #waiters = new Waiters<SubmissionId, SettledSubmissionRecord>();\n\t#closed = false;\n\n\tconstructor(\n\t\tsession: SessionImpl,\n\t\tnow: () => number,\n\t\tqueueModes: () => QueueModes,\n\t\tresume: () => void,\n\t\ttelemetry: TelemetryContext = NOOP_TELEMETRY_CONTEXT,\n\t) {\n\t\tthis.#telemetry = telemetry;\n\t\tthis.#session = session;\n\t\tthis.#now = now;\n\t\tthis.#queueModes = queueModes;\n\t\tthis.#resume = resume;\n\t\tsession.followCommits((publication) => this.#observe(publication));\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tthis.#waiters.rejectAll(closedError(this.#session));\n\t\t});\n\t}\n\n\t/** Admit a submission in one commit; see `admitSubmission()`. */\n\tasync submit(conversationId: ConversationId, draft: SubmissionDraft, context: Context): Promise<Submission> {\n\t\tconst { id } = await this.#traced(conversationId, draft, context, (span) =>\n\t\t\tthis.#session.commitWith(\n\t\t\t\t(tx) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes(), span),\n\t\t\t\twithTelemetry(span, context),\n\t\t\t),\n\t\t);\n\t\treturn new SubmissionHandle(id, this);\n\t}\n\n\t/**\n\t * Admit a submission inside the caller's commit `tx`, with the rules of `submit()`. The admission is stored or lost\n\t * with that commit. It must come before the commit's first table write, another admission's included.\n\t */\n\tasync admit(tx: Tx, conversationId: ConversationId, draft: SubmissionDraft): Promise<SubmissionId> {\n\t\tif (!this.#session.ownsTransaction(tx)) throw new Error(\"The transaction belongs to another Session\");\n\t\t// Enforced on every path: admission reads tables only on some (request IDs, an idle boundary, a steer's trace).\n\t\tif (tx.hasTableWrite) throw new ReadAfterWrite(\"submit(tx, draft)\");\n\t\tconst admission = await this.#traced(conversationId, draft, tx.context, (span) =>\n\t\t\tadmitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes(), span),\n\t\t);\n\t\treturn admission.id;\n\t}\n\n\t/** Run one admission in its `pi.durable.submit` span, asking for progress first, as the run it starts needs it. */\n\t#traced(\n\t\tconversationId: ConversationId,\n\t\tdraft: SubmissionDraft,\n\t\tcontext: Context,\n\t\tadmit: (span: TelemetrySpan) => Promise<Admission>,\n\t): Promise<Admission> {\n\t\tthis.#resume();\n\t\t// Inputs and continues start runs: root traces linked to their callers.\n\t\tconst startsRun = draft.type !== \"write\";\n\t\tconst parent = startsRun ? this.#telemetry : context.telemetry;\n\t\treturn createTypedSpanStarter(parent, [DURABLE_TELEMETRY_SCHEMA])(\n\t\t\t\"pi.durable.submit\",\n\t\t\t{\n\t\t\t\t\"submission.type\": draft.type,\n\t\t\t\t\"conversation.id\": conversationId,\n\t\t\t},\n\t\t\tasync (span) => {\n\t\t\t\tif (startsRun) span.addLink({ context: context.telemetry });\n\t\t\t\ttry {\n\t\t\t\t\tconst admission = await admit(span);\n\t\t\t\t\tspan.setAttributes({ \"submission.id\": admission.id, result: admission.status });\n\t\t\t\t\treturn admission;\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Error text may contain caller content. Record only the status.\n\t\t\t\t\tspan.setStatus({ status: \"error\" });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t}\n\n\t/** Handle for an existing submission, or `undefined`. */\n\tasync get(id: SubmissionId, context: Context): Promise<Submission | undefined> {\n\t\tconst record = await this.#session.readOnLine((storage) => storage.submission(id, context));\n\t\treturn record === undefined ? undefined : new SubmissionHandle(record.id, this);\n\t}\n\n\tasync status(id: SubmissionId, context: Context): Promise<SubmissionRecord> {\n\t\tconst record = await this.#session.readOnLine((storage) => storage.submission(id, context));\n\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\treturn record;\n\t}\n\n\tasync wait(id: SubmissionId, context: Context): Promise<SettledSubmissionRecord> {\n\t\tthis.#resume();\n\t\t// Check and register on the line so no settling publication falls between them.\n\t\tconst found = await this.#session.readOnLine(async (storage) => {\n\t\t\tconst record = await storage.submission(id, context);\n\t\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\t\tif (isSettled(record)) return { promise: Promise.resolve(record) };\n\t\t\t// Close rejects registered waiters synchronously and may begin during the read.\n\t\t\tif (this.#closed) throw closedError(this.#session);\n\t\t\treturn { promise: this.#waiters.add(id, context) };\n\t\t});\n\t\treturn found.promise;\n\t}\n\n\t/** Withdraw a queued submission and remove its inbox item; placed inputs and settled submissions are reported. */\n\tabort(id: SubmissionId, context: Context, conversationId?: ConversationId): Promise<AbortResult | \"not_found\"> {\n\t\treturn this.#session.commitWith(async (tx) => {\n\t\t\tconst record = await tx.submission(id);\n\t\t\tif (record === undefined || (conversationId !== undefined && record.conversationId !== conversationId)) {\n\t\t\t\treturn \"not_found\";\n\t\t\t}\n\t\t\tif (record.status === \"queued\") {\n\t\t\t\ttx.settleSubmission(id, { status: \"unanswered\", reason: \"aborted\" });\n\t\t\t\tawait removeInboxItem(tx, record.conversationId, id);\n\t\t\t\treturn \"aborted\";\n\t\t\t}\n\t\t\treturn record.status === \"placed\" ? \"already_placed\" : \"settled\";\n\t\t}, context);\n\t}\n\n\t#observe(publication: ObservedCommit): void {\n\t\t// A commit held in memory changes documents only.\n\t\tif (publication.kind === \"memory\") return;\n\t\tfor (const change of publication.changes) {\n\t\t\tif (change.type !== \"submission\" || !isSettled(change.value)) continue;\n\t\t\tthis.#waiters.resolve(change.value.id, change.value);\n\t\t}\n\t}\n}\n\nclass SubmissionHandle implements Submission {\n\treadonly id: SubmissionId;\n\treadonly #submissions: Submissions;\n\n\tconstructor(id: SubmissionId, submissions: Submissions) {\n\t\tthis.id = id;\n\t\tthis.#submissions = submissions;\n\t}\n\n\tstatus(context: Context): Promise<SubmissionRecord> {\n\t\treturn this.#submissions.status(this.id, context);\n\t}\n\n\twait(context: Context): Promise<SettledSubmissionRecord> {\n\t\treturn this.#submissions.wait(this.id, context);\n\t}\n\n\tasync abort(context: Context): Promise<AbortResult> {\n\t\tconst result = await this.#submissions.abort(this.id, context);\n\t\tif (result === \"not_found\") throw new Error(`Submission ${this.id} does not exist`);\n\t\treturn result;\n\t}\n}\n\nfunction isSettled(record: SubmissionRecord): record is SettledSubmissionRecord {\n\treturn record.status === \"done\" || record.status === \"unanswered\";\n}\n\n/** Reject an input entry an untyped caller got wrong: its kind must be a non-empty string outside the `pi.` prefix. */\nfunction checkInputEntry(entry: InputEntry): void {\n\tconst { kind } = entry;\n\tif (typeof kind !== \"string\" || kind.length === 0 || kind.startsWith(\"pi.\")) {\n\t\tthrow new TypeError(\n\t\t\t`An input entry's kind must be a non-empty string not starting with \"pi.\", got ${String(kind)}`,\n\t\t);\n\t}\n}\n\n/**\n * Admit a submission inside a commit (spec §6); both `Conversation.submit()` forms and conversation-owned compactions\n * share it. A known request ID returns its existing submission without writing. A display-only write (only `kind` and\n * `data`) is appended and settled `done` at once, busy or not, as it changes nothing the model sees; only behind a\n * queued reset it queues, so it lands after the reset instead of before it in the context the reset ends. A busy\n * conversation queues anything else in `pi.inbox`, or rejects `whenBusy: \"reject\"` input and any continue with\n * `ConversationBusy`; an idle one rejects `whenIdle: \"reject\"` input with `ConversationIdle`. An idle continue places\n * queued items and starts a run with them and itself, placing no entry of its own. An idle conversation with queued\n * items queues it behind them and runs a final boundary. Otherwise idle input places its entry (`pi.user`, or the\n * input's own) and starts a run, and an idle write appends its entry and settles `done`, or `stale` when its head\n * reaches before the active range.\n */\nexport async function admitSubmission(\n\ttx: Tx,\n\tconversationId: ConversationId,\n\tdraft: SubmissionDraft,\n\tnow: number,\n\tqueueModes: QueueModes,\n\tspan?: TelemetrySpan,\n): Promise<Admission> {\n\tif (draft.type === \"input\" && draft.entry !== undefined) checkInputEntry(draft.entry);\n\tif (draft.requestId !== undefined) {\n\t\tconst existing = await tx.submissionByRequest(conversationId, draft.requestId);\n\t\tif (existing !== undefined) {\n\t\t\tif (existing.type !== draft.type) {\n\t\t\t\tthrow new Error(`Request ${draft.requestId} already identifies a submission of type ${existing.type}`);\n\t\t\t}\n\t\t\treturn { id: existing.id, status: existing.status === \"unanswered\" ? \"done\" : existing.status };\n\t\t}\n\t}\n\tconst fields = { conversationId, requestId: draft.requestId, trace: span?.propagation?.inject(span) };\n\tif (\n\t\tdraft.type === \"write\" &&\n\t\tisDisplayOnly(draft.entry) &&\n\t\t!hasQueuedReset((await tx.doc(InboxDoc, conversationId)).items)\n\t) {\n\t\tconst entry = await tx.appendEntry(conversationId, draft.entry);\n\t\tconst write = { ...fields, type: \"write\", status: \"done\", entry: entry.id } as const;\n\t\treturn { id: (await tx.createSubmission(write)).id, status: \"done\" };\n\t}\n\tconst live = await tx.doc(LiveDoc, conversationId);\n\tconst busy = live.run !== undefined;\n\tif (\n\t\tdraft.type === \"input\" &&\n\t\tdraft.whenBusy === \"steer\" &&\n\t\tlive.run !== undefined &&\n\t\tspan?.propagation !== undefined\n\t) {\n\t\tconst run = await tx.task(live.run.taskId);\n\t\tif (run?.trace !== undefined) span.addLink({ context: span.propagation.extract(run.trace) });\n\t}\n\tif (busy && draft.type === \"input\" && draft.whenBusy === \"reject\") throw new ConversationBusy(conversationId);\n\tif (!busy && draft.type === \"input\" && draft.whenIdle === \"reject\") throw new ConversationIdle(conversationId);\n\tif (draft.type === \"continue\") {\n\t\t// Never queued: whether a run can continue depends on how the current one ends. Rejected before any write.\n\t\tif (busy) throw new ConversationBusy(conversationId);\n\t\tconst boundary = await prepareBoundary(tx, conversationId, queueModes);\n\t\tconst { id } = await tx.createSubmission({ ...fields, type: \"continue\", status: \"placed\" });\n\t\t// Items an earlier failed run left queued (`afterFailedRun: \"keep\"`) are placed first and join the run. Its history\n\t\t// starts with the failed run's, so `afterRun` hooks see what that run did.\n\t\tconst { users, first } = await applyBoundary(tx, boundary, \"final\", now);\n\t\tawait startRun(tx, conversationId, live, { inputs: [...users, id], first: live.runFailure?.first ?? first });\n\t\treturn { id, status: \"placed\" };\n\t}\n\t// A boundary reads the table, so it is prepared before the first table write; a busy one needs none.\n\tconst boundary = busy ? undefined : await prepareBoundary(tx, conversationId, queueModes);\n\tif (boundary === undefined || boundary.inbox.items.length > 0) {\n\t\tconst { id } = await tx.createSubmission({\n\t\t\t...fields,\n\t\t\ttype: draft.type,\n\t\t\tstatus: \"queued\",\n\t\t});\n\t\t// Hosts may leave optional fields `undefined`; drafts take strict JSON.\n\t\tconst value = copyJson(draft.type === \"write\" ? draft.entry : draft.content, {\n\t\t\tomitUndefinedProperties: true,\n\t\t});\n\t\tconst items = (boundary?.inbox ?? (await tx.doc(InboxDoc, conversationId))).items;\n\t\tif (draft.type === \"write\") items.push({ id, mode: \"write\", entry: value as JsonObject });\n\t\telse {\n\t\t\tconst mode = draft.whenBusy === \"steer\" ? \"steer\" : \"followUp\";\n\t\t\tconst content = value as JsonRepresentation<UserInput>;\n\t\t\tconst entry = draft.entry === undefined ? {} : { entry: pickInputEntry(draft.entry) };\n\t\t\titems.push({ id, mode, content, ...entry });\n\t\t}\n\t\tif (boundary === undefined) return { id, status: \"queued\" };\n\t\tconst { users, first } = await applyBoundary(tx, boundary, \"final\", now);\n\t\tif (users.length > 0) await startRun(tx, conversationId, live, { inputs: users, first });\n\t\treturn { id, status: draft.type === \"write\" ? \"done\" : users.at(-1) === id ? \"placed\" : \"queued\" };\n\t}\n\tif (draft.type === \"write\") {\n\t\tif (isStale(boundary, draft.entry)) {\n\t\t\tconst stale = { status: \"unanswered\", reason: \"stale\" } as const;\n\t\t\treturn {\n\t\t\t\tid: (await tx.createSubmission({ ...fields, type: \"write\", ...stale })).id,\n\t\t\t\tstatus: \"done\",\n\t\t\t};\n\t\t}\n\t\tconst entry = await tx.appendEntry(conversationId, draft.entry);\n\t\tconst write = { ...fields, type: \"write\", status: \"done\", entry: entry.id } as const;\n\t\treturn { id: (await tx.createSubmission(write)).id, status: \"done\" };\n\t}\n\tconst entry = await appendInput(tx, conversationId, draft.content, draft.entry, now);\n\tconst input = { ...fields, type: \"input\", status: \"placed\", entry: entry.id } as const;\n\tconst { id } = await tx.createSubmission(input);\n\tawait startRun(tx, conversationId, live, { inputs: [id], first: entry.id });\n\treturn { id, status: \"placed\" };\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Context, type JsonValue, type WatchHandle } from "@earendil-works/chord";
|
|
2
2
|
import { type SessionImpl } from "../session/session.ts";
|
|
3
|
-
import type { ConversationId, JoinPolicy,
|
|
4
|
-
|
|
3
|
+
import type { ConversationId, JoinPolicy, Observation, Observer, TaskId, TaskOutcome } from "../types.ts";
|
|
4
|
+
import { type BlockedReason, type BlockedSubject } from "./scheduler.ts";
|
|
5
|
+
/** A live task's durable status without its checkpoint and outcome payloads (spec §9.4). */
|
|
5
6
|
export type TaskGraphState = {
|
|
6
7
|
readonly status: "pending" | "running";
|
|
7
8
|
readonly phase: string;
|
|
@@ -11,6 +12,12 @@ export type TaskGraphState = {
|
|
|
11
12
|
readonly on: readonly TaskId[];
|
|
12
13
|
readonly policy: JoinPolicy;
|
|
13
14
|
}
|
|
15
|
+
/** Asleep until the Harness clock reaches `until`. */
|
|
16
|
+
| {
|
|
17
|
+
readonly status: "sleeping";
|
|
18
|
+
readonly phase: string;
|
|
19
|
+
readonly until: number;
|
|
20
|
+
}
|
|
14
21
|
/** Outcome held until its ordinary owned work drains. */
|
|
15
22
|
| {
|
|
16
23
|
readonly status: "completing";
|
|
@@ -25,25 +32,38 @@ export type TaskGraphNode = {
|
|
|
25
32
|
readonly background: boolean;
|
|
26
33
|
readonly abortRequested: boolean;
|
|
27
34
|
readonly state: TaskGraphState;
|
|
35
|
+
/**
|
|
36
|
+
* Why it cannot run here, when it cannot: no registered definition takes it (`missing_task`, `task_too_old`,
|
|
37
|
+
* `migration_failed`). Follows registry changes.
|
|
38
|
+
*/
|
|
39
|
+
readonly blocked?: BlockedReason;
|
|
28
40
|
/** Conversations this task owns, in ID order. */
|
|
29
41
|
readonly conversations: readonly ConversationId[];
|
|
30
42
|
};
|
|
31
|
-
/** Every live task of the Session (spec §9.
|
|
43
|
+
/** Every live task of the Session (spec §9.4). */
|
|
32
44
|
export type TaskGraph = {
|
|
33
45
|
/** Every live task, keyed by its decimal ID. */
|
|
34
46
|
readonly tasks: Readonly<Record<string, TaskGraphNode>>;
|
|
35
47
|
};
|
|
36
48
|
export type TaskGraphWatch = WatchHandle<TaskGraph>;
|
|
49
|
+
/** What the graph asks the scheduler: a task's blocked reason, and when reasons may change without a commit. */
|
|
50
|
+
export type TaskGraphBlocking = {
|
|
51
|
+
readonly blocked: (record: BlockedSubject) => BlockedReason | undefined;
|
|
52
|
+
readonly subscribeBlocked: (listener: () => void) => () => void;
|
|
53
|
+
};
|
|
37
54
|
/**
|
|
38
55
|
* The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It
|
|
39
56
|
* advances from the Session's commit publications, which are durable.
|
|
40
57
|
*/
|
|
41
58
|
export declare class TaskGraphView {
|
|
42
59
|
#private;
|
|
43
|
-
constructor(session: SessionImpl,
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
constructor(session: SessionImpl, blocking: TaskGraphBlocking);
|
|
61
|
+
/**
|
|
62
|
+
* Attach a synchronous observer of the graph (`Harness.observeTaskGraph()`), behind `guardObserver()`; `context`
|
|
63
|
+
* governs only the attachment.
|
|
64
|
+
*/
|
|
65
|
+
observe(observer: Observer<TaskGraph>, context: Context): Promise<Observation<TaskGraph>>;
|
|
66
|
+
/** A serialized watch of the graph, an observer of its mount; aborting `context` ends it `aborted`. */
|
|
47
67
|
watch(context: Context): Promise<TaskGraphWatch>;
|
|
48
68
|
}
|
|
49
69
|
//# sourceMappingURL=task-graph.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-graph.d.ts","sourceRoot":"","sources":["../../src/harness/task-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"task-graph.d.ts","sourceRoot":"","sources":["../../src/harness/task-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAyB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAG9G,OAAO,EAON,KAAK,WAAW,EAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACX,cAAc,EACd,UAAU,EACV,WAAW,EACX,QAAQ,EAER,MAAM,EACN,WAAW,EAEX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAkB,MAAM,gBAAgB,CAAC;AAGzF,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClE;IACA,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC3B;AACH,sDAAsD;GACpD;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACjF,yDAAyD;GACvD;IAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC;AAEzF,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IACjC,iDAAiD;IACjD,QAAQ,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC;CAClD,CAAC;AAEF,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG;IACvB,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;AAWpD,gHAAgH;AAChH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,aAAa,GAAG,SAAS,CAAC;IACxE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;CAChE,CAAC;AAKF;;;GAGG;AACH,qBAAa,aAAa;;IAMzB,YAAY,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAoB5D;IAED;;;OAGG;IACG,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAY9F;IAED,uGAAuG;IACjG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAYrD;CAmED"}
|