@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
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Context, Draft, JsonValue, WatchCall, WatchEnd, WatchHandle } from "@earendil-works/chord";
|
|
2
2
|
import type { Op } from "@earendil-works/chord/delta";
|
|
3
3
|
import type { Message, Models } from "@earendil-works/pi-ai";
|
|
4
|
+
import type { TelemetryCarrier } from "@earendil-works/pi-telemetry";
|
|
4
5
|
import type { ExecutionEnv } from "./env/index.ts";
|
|
5
6
|
import type { Agent, ContextView, ConversationHandle, RegistrySnapshot, Settings, SettledTask } from "./harness/types.ts";
|
|
6
7
|
/** JSON object used as the root of every durable document. */
|
|
@@ -62,8 +63,8 @@ export type CommonDocDefinition<T extends JsonObject> = {
|
|
|
62
63
|
readonly version: number;
|
|
63
64
|
initial(): T;
|
|
64
65
|
migrate?(value: JsonObject, fromVersion: number): T;
|
|
65
|
-
/**
|
|
66
|
-
checkpointWhen
|
|
66
|
+
/** Required policy: return true to store this ordinary change as a complete base instead of a delta. */
|
|
67
|
+
checkpointWhen(value: Readonly<T>, ops: readonly Op[], info: CheckpointInfo): boolean;
|
|
67
68
|
};
|
|
68
69
|
/** Singleton document definition. */
|
|
69
70
|
export type DocDefinition<T extends JsonObject> = CommonDocDefinition<T> & DocumentSemantics;
|
|
@@ -99,6 +100,98 @@ export type RewindableConversationDocFamilyToken<T extends JsonObject, I extends
|
|
|
99
100
|
export type TaskDocFamilyToken<T extends JsonObject, I extends JsonValue> = DocFamilyToken<T, I, DocFamilyDefinition<T, I> & {
|
|
100
101
|
readonly scope: "task";
|
|
101
102
|
}>;
|
|
103
|
+
/** The task a report is about. */
|
|
104
|
+
export type ReportTask = {
|
|
105
|
+
readonly id: TaskId;
|
|
106
|
+
/** The task's registered name. */
|
|
107
|
+
readonly kind: string;
|
|
108
|
+
readonly conversationId: ConversationId;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* A host callback, by its `HarnessOptions` name; `env` is the environment builder, `models` a provider call, and
|
|
112
|
+
* `telemetry` a telemetry adapter call made while a commit is published, which must not fail it.
|
|
113
|
+
*/
|
|
114
|
+
export type HostCallback = "now" | "settings" | "registry" | "env" | "models" | "setTimer" | "onWake" | "telemetry";
|
|
115
|
+
/**
|
|
116
|
+
* What a report to `HarnessOptions.onReport` is about, by `kind` (`Report` adds the error). `extension`, where present,
|
|
117
|
+
* names the extension whose code failed, when known; for a task's own code, the one that installed the definition the
|
|
118
|
+
* task ran.
|
|
119
|
+
* - `storage_failed`: the error failed the Session, which closes: a Storage error, often a platform reset.
|
|
120
|
+
* - `task_faulted`: the task ended `faulted`: its phase threw (`reason: "threw"`), or its abort handler was cut off
|
|
121
|
+
* `settings.restartLimit` times (`reason: "restart_limit"`), as was a phase of a task of an extension's kind.
|
|
122
|
+
* - `task_interrupted`: crashes ended the task: it ended itself after being cut off `settings.restartLimit` times in a
|
|
123
|
+
* row (`reason: "restart_limit"`; a tool call, a compaction, a generation), or a generation's run ended because the
|
|
124
|
+
* host kept stopping while the model answered (`reason: "interrupted"`). `restarts` is the task's count when it ended.
|
|
125
|
+
* - `migration_failed`: the task's stored state could not be migrated; it is blocked until the registry changes.
|
|
126
|
+
* - `task_outdated`: a running task keeps running under its old definition, which was uninstalled (`missing_task`)
|
|
127
|
+
* or replaced by one that cannot take over its state: older than the task (`task_too_old`), or newer without a
|
|
128
|
+
* `migrate` (`migration_failed`).
|
|
129
|
+
* - `task_error`: the task's own `runtime.report()`, or a failure in running it.
|
|
130
|
+
* - `extension_error`: a hook, a section, a wrapper, or a tool's invalid structured output; with the task that ran it,
|
|
131
|
+
* or, outside a task, the conversation whose agent was resolved.
|
|
132
|
+
* - `host_error`: a host callback threw; with the task that called it, if one did.
|
|
133
|
+
* - `listener_error`: a commit, close, watch, view, or document listener threw.
|
|
134
|
+
*/
|
|
135
|
+
export type ReportInfo = {
|
|
136
|
+
readonly kind: "storage_failed";
|
|
137
|
+
} | {
|
|
138
|
+
readonly kind: "task_faulted";
|
|
139
|
+
readonly task: ReportTask;
|
|
140
|
+
readonly extension?: string;
|
|
141
|
+
readonly reason: "threw" | "restart_limit";
|
|
142
|
+
} | {
|
|
143
|
+
readonly kind: "task_interrupted";
|
|
144
|
+
readonly task: ReportTask;
|
|
145
|
+
readonly extension?: string;
|
|
146
|
+
readonly reason: "restart_limit" | "interrupted";
|
|
147
|
+
readonly restarts: number;
|
|
148
|
+
} | {
|
|
149
|
+
readonly kind: "migration_failed";
|
|
150
|
+
readonly task: ReportTask;
|
|
151
|
+
readonly extension?: string;
|
|
152
|
+
} | {
|
|
153
|
+
readonly kind: "task_outdated";
|
|
154
|
+
readonly task: ReportTask;
|
|
155
|
+
readonly extension?: string;
|
|
156
|
+
readonly reason: "missing_task" | "task_too_old" | "migration_failed";
|
|
157
|
+
} | {
|
|
158
|
+
readonly kind: "task_error";
|
|
159
|
+
readonly task: ReportTask;
|
|
160
|
+
readonly extension?: string;
|
|
161
|
+
} | {
|
|
162
|
+
readonly kind: "extension_error";
|
|
163
|
+
readonly extension?: string;
|
|
164
|
+
readonly task?: ReportTask;
|
|
165
|
+
readonly conversationId?: ConversationId;
|
|
166
|
+
} | {
|
|
167
|
+
readonly kind: "host_error";
|
|
168
|
+
readonly callback: HostCallback;
|
|
169
|
+
readonly task?: ReportTask;
|
|
170
|
+
} | {
|
|
171
|
+
readonly kind: "listener_error";
|
|
172
|
+
};
|
|
173
|
+
/** One report to `HarnessOptions.onReport`: what it is about (`ReportInfo`, by `kind`) and the `error` reported. */
|
|
174
|
+
export type Report = ReportInfo & {
|
|
175
|
+
readonly error: unknown;
|
|
176
|
+
};
|
|
177
|
+
/** Whose code a task's `runtime.report()` is about when not the task's own: an extension's, or a host callback. */
|
|
178
|
+
export type ReportFrom = {
|
|
179
|
+
readonly kind: "extension";
|
|
180
|
+
readonly extension?: string;
|
|
181
|
+
} | {
|
|
182
|
+
readonly kind: "host";
|
|
183
|
+
readonly callback: HostCallback;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* A host timer, given as `HarnessOptions.setTimer`: call `callback` once, about `delayMs` from now, and return
|
|
187
|
+
* a function that disarms it. `background` timers only free memory, and a host may decline one by returning
|
|
188
|
+
* `undefined`, for example where a pending timer keeps the process from hibernating; the Harness then frees that memory
|
|
189
|
+
* at later commits. Other timers pace or resume work: one the host throws on or declines is armed with `setTimeout`.
|
|
190
|
+
* A timer should not fire early; callers check their clock again when it fires.
|
|
191
|
+
*/
|
|
192
|
+
export type SetTimer = (callback: () => void, delayMs: number, options: {
|
|
193
|
+
readonly background: boolean;
|
|
194
|
+
}) => (() => void) | undefined;
|
|
102
195
|
/** Live task record reserved by one invocation. */
|
|
103
196
|
export type RunningTask<I, S, R> = TaskRecord<I, S, R> & {
|
|
104
197
|
readonly state: Extract<TaskState<S, R>, {
|
|
@@ -106,11 +199,11 @@ export type RunningTask<I, S, R> = TaskRecord<I, S, R> & {
|
|
|
106
199
|
}>;
|
|
107
200
|
};
|
|
108
201
|
/**
|
|
109
|
-
* Next state a task commits for itself: a replacement checkpoint, a wait, or its outcome. A returned `terminal` state is
|
|
202
|
+
* Next state a task commits for itself: a replacement checkpoint, a wait on tasks, a sleep, or its outcome. A returned `terminal` state is
|
|
110
203
|
* stored as `completing` while ordinary owned work below the task is live (spec §5.5).
|
|
111
204
|
*/
|
|
112
205
|
export type NextTaskState<S, R> = Extract<TaskState<S, R>, {
|
|
113
|
-
readonly status: "running" | "waiting" | "terminal";
|
|
206
|
+
readonly status: "running" | "waiting" | "sleeping" | "terminal";
|
|
114
207
|
}>;
|
|
115
208
|
/**
|
|
116
209
|
* Runs one checkpoint phase. It must commit a changed checkpoint or a terminal outcome through `runtime.commit()`;
|
|
@@ -143,6 +236,7 @@ export interface TaskRuntime<I, S, R, H extends object> extends DocumentObserver
|
|
|
143
236
|
agent(context: Context): Promise<Agent>;
|
|
144
237
|
/** `HarnessOptions.settings`, resolved at each access. */
|
|
145
238
|
readonly settings: Settings;
|
|
239
|
+
/** `HarnessOptions.models`, resolved at each access. */
|
|
146
240
|
readonly models: Models;
|
|
147
241
|
/** Calls `HarnessOptions.env` for the task's conversation; rejects with its error. */
|
|
148
242
|
env(context: Context): Promise<ExecutionEnv | undefined>;
|
|
@@ -152,9 +246,11 @@ export interface TaskRuntime<I, S, R, H extends object> extends DocumentObserver
|
|
|
152
246
|
* Commit on the Session line after rereading the task. Rejects when the task is terminal, the invocation ended, the
|
|
153
247
|
* Harness is closing, or, in a run invocation, the task carries an abort mark. A returned state replaces the task's
|
|
154
248
|
* state in the same commit; returning nothing leaves it unchanged. `tx.createTask()` defaults to the task's
|
|
155
|
-
* conversation. Inside the callback read only through `tx`: `snapshot()`, `
|
|
249
|
+
* conversation. Inside the callback read only through `tx`: `snapshot()`, `watchDoc()`, `getTask()`, and the other Session and runtime reads may queue on the line the callback holds, and then never resolve.
|
|
250
|
+
* `options.persistence` may defer storing a commit that changes only documents (`CommitPersistence`); one that returns
|
|
251
|
+
* a state is immediate.
|
|
156
252
|
*/
|
|
157
|
-
commit(change: (tx: Tx, current: RunningTask<I, S, R>) => NextTaskState<S, R> | undefined | Promise<NextTaskState<S, R> | undefined>, context: Context): Promise<void>;
|
|
253
|
+
commit(change: (tx: Tx, current: RunningTask<I, S, R>) => NextTaskState<S, R> | undefined | Promise<NextTaskState<S, R> | undefined>, context: Context, options?: CommitOptions): Promise<void>;
|
|
158
254
|
/** Read a durable memo of this task. */
|
|
159
255
|
memo<T extends JsonValue>(name: string, context: Context): Promise<T | undefined>;
|
|
160
256
|
/** Store `candidate` unless a memo already exists; return the durable winner. */
|
|
@@ -184,16 +280,37 @@ export interface TaskRuntime<I, S, R, H extends object> extends DocumentObserver
|
|
|
184
280
|
entry(id: EntryId, context: Context): Promise<EntryRecord | undefined>;
|
|
185
281
|
/** Undefined when the entry is absent, not visible, or has another kind. */
|
|
186
282
|
entry<D extends JsonValue>(token: Entry<D>, id: EntryId, context: Context): Promise<TypedEntry<D> | undefined>;
|
|
283
|
+
/**
|
|
284
|
+
* Committed raw history of the task's conversation, fork-aware, as `Conversation.entries()`: every entry, also those a
|
|
285
|
+
* compaction summary or reset left behind. Entries never change, so a range bounded by entry IDs reads the same
|
|
286
|
+
* before and after a compaction, and in a rerun after a crash.
|
|
287
|
+
*/
|
|
288
|
+
entries(query: Omit<EntryQuery, "conversationId">, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<EntryRecord, Cursor>>;
|
|
187
289
|
/** Committed raw active transcript and model context, optionally cut off at the visible entry `at`. */
|
|
188
290
|
context(conversationId: ConversationId, context: Context, options?: {
|
|
189
291
|
readonly at?: EntryId;
|
|
190
292
|
}): Promise<ContextView>;
|
|
191
293
|
/** The Harness clock. */
|
|
192
294
|
now(): number;
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Call `callback` once after about `delayMs` on the Harness's timer (`HarnessOptions.setTimer`), for pacing work
|
|
297
|
+
* inside a phase, such as throttled progress commits. Not durable: the invocation's end disarms it, and after its end
|
|
298
|
+
* nothing is armed. Returns a function that disarms it. Wait for time between phases with `sleepUntil()`.
|
|
299
|
+
*/
|
|
300
|
+
setTimer(callback: () => void, delayMs: number): () => void;
|
|
301
|
+
/**
|
|
302
|
+
* Forward a non-fatal failure to `HarnessOptions.onReport`, with this task in its info: a `task_error` about the
|
|
303
|
+
* task's own code, or, with `from`, an `extension_error` about extension code it called, such as a section, or a
|
|
304
|
+
* `host_error` about a host callback, such as the environment builder.
|
|
305
|
+
*/
|
|
306
|
+
report(error: unknown, from?: ReportFrom): void;
|
|
307
|
+
/**
|
|
308
|
+
* Commit a sleep: the task holds no invocation until the Harness clock reaches `until`, then resumes at `checkpoint`.
|
|
309
|
+
* Resolves once the sleep is stored, not when the time comes; the phase returns right after. Returning
|
|
310
|
+
* `{ status: "sleeping", until, checkpoint }` from `commit()` is the same sleep, for one that must commit together
|
|
311
|
+
* with other writes.
|
|
312
|
+
*/
|
|
313
|
+
sleepUntil(until: number, checkpoint: S, context: Context): Promise<void>;
|
|
197
314
|
}
|
|
198
315
|
/** Executable durable state machine definition, registered in the registry by `name`. */
|
|
199
316
|
export type TaskDefinition<I, S extends {
|
|
@@ -237,6 +354,10 @@ export type TaskOwnership = {
|
|
|
237
354
|
export type JoinPolicy = "failFast" | "allSettled";
|
|
238
355
|
/** Creation options for a durable task. */
|
|
239
356
|
export type TaskOptions = {
|
|
357
|
+
/** Omitted: inherit the creator's carrier. "root": start at the adapter root without a stored carrier. */
|
|
358
|
+
readonly trace?: TelemetryCarrier | "root";
|
|
359
|
+
/** Immutable creation-time links, attached to the spans of this task's first invocation. */
|
|
360
|
+
readonly links?: readonly TelemetryCarrier[];
|
|
240
361
|
/** Required: a task always names its owner (spec §5.5). */
|
|
241
362
|
readonly ownership: TaskOwnership;
|
|
242
363
|
/**
|
|
@@ -327,12 +448,14 @@ export interface Entry<D extends JsonValue = never> {
|
|
|
327
448
|
}
|
|
328
449
|
/** Identity fields shared by every durable submission state. */
|
|
329
450
|
type SubmissionRecordBase = {
|
|
451
|
+
/** Adapter-owned context of the admission span; absent without propagation. */
|
|
452
|
+
readonly trace?: TelemetryCarrier;
|
|
330
453
|
readonly id: SubmissionId;
|
|
331
454
|
readonly conversationId: ConversationId;
|
|
332
455
|
/** Host-provided deduplication key, scoped to the conversation. */
|
|
333
456
|
readonly requestId?: string;
|
|
334
457
|
};
|
|
335
|
-
/** Durable lifecycle of one admitted user input
|
|
458
|
+
/** Durable lifecycle of one admitted user input, passive entry write, or continue. */
|
|
336
459
|
export type SubmissionRecord = (SubmissionRecordBase & {
|
|
337
460
|
readonly type: "input";
|
|
338
461
|
} & ({
|
|
@@ -386,6 +509,30 @@ export type SubmissionRecord = (SubmissionRecordBase & {
|
|
|
386
509
|
readonly answer?: never;
|
|
387
510
|
readonly reason: string;
|
|
388
511
|
readonly detail?: JsonValue;
|
|
512
|
+
})) | (SubmissionRecordBase & {
|
|
513
|
+
/** A run started without a user message; it places no entry and is never queued. */
|
|
514
|
+
readonly type: "continue";
|
|
515
|
+
} & ({
|
|
516
|
+
/** Owned by an active run. */
|
|
517
|
+
readonly status: "placed";
|
|
518
|
+
readonly entry?: never;
|
|
519
|
+
readonly answer?: never;
|
|
520
|
+
readonly reason?: never;
|
|
521
|
+
readonly detail?: never;
|
|
522
|
+
} | {
|
|
523
|
+
/** The run answered. */
|
|
524
|
+
readonly status: "done";
|
|
525
|
+
readonly entry?: never;
|
|
526
|
+
readonly answer: EntryId;
|
|
527
|
+
readonly reason?: never;
|
|
528
|
+
readonly detail?: never;
|
|
529
|
+
} | {
|
|
530
|
+
/** The run ended without an answer. */
|
|
531
|
+
readonly status: "unanswered";
|
|
532
|
+
readonly entry?: never;
|
|
533
|
+
readonly answer?: never;
|
|
534
|
+
readonly reason: string;
|
|
535
|
+
readonly detail?: JsonValue;
|
|
389
536
|
}));
|
|
390
537
|
/** Terminal status staged for a submission; identity, type, and entry come from its current record. */
|
|
391
538
|
export type SubmissionSettlement = {
|
|
@@ -459,6 +606,15 @@ export type TaskState<S, R> = {
|
|
|
459
606
|
readonly on: readonly TaskId[];
|
|
460
607
|
readonly policy: JoinPolicy;
|
|
461
608
|
readonly outcome?: never;
|
|
609
|
+
} | {
|
|
610
|
+
/**
|
|
611
|
+
* Parked without an invocation until the Harness clock reaches `until`, in milliseconds on the
|
|
612
|
+
* `HarnessOptions.now` clock; then resumes at `checkpoint`. An abort mark does not wait for it.
|
|
613
|
+
*/
|
|
614
|
+
readonly status: "sleeping";
|
|
615
|
+
readonly checkpoint: S;
|
|
616
|
+
readonly until: number;
|
|
617
|
+
readonly outcome?: never;
|
|
462
618
|
} | {
|
|
463
619
|
/** Outcome decided; becomes terminal once no ordinary owned work below is live. Runs no more code. */
|
|
464
620
|
readonly status: "completing";
|
|
@@ -472,6 +628,10 @@ export type TaskState<S, R> = {
|
|
|
472
628
|
};
|
|
473
629
|
/** Identity, definition, and scheduling fields shared by every task state. */
|
|
474
630
|
type TaskRecordBase<I, R> = {
|
|
631
|
+
/** Adapter-owned context that created this task; phase invocations extract it as their parent. */
|
|
632
|
+
readonly trace?: TelemetryCarrier;
|
|
633
|
+
/** Immutable creation-time links for the task's first invocation. */
|
|
634
|
+
readonly links?: readonly TelemetryCarrier[];
|
|
475
635
|
readonly id: TaskId<R>;
|
|
476
636
|
readonly conversationId: ConversationId;
|
|
477
637
|
/** Registered task definition name. */
|
|
@@ -502,11 +662,18 @@ type TaskRecordBase<I, R> = {
|
|
|
502
662
|
readonly startedAt?: number;
|
|
503
663
|
/** Wall-clock milliseconds of the change to `terminal`, stamped by the Session; absent while live. */
|
|
504
664
|
readonly endedAt?: number;
|
|
665
|
+
/**
|
|
666
|
+
* How many times in a row a crash, eviction, or reset cut the task off while it ran, without the task changing its
|
|
667
|
+
* state since; open counts them, and a close does not. At `HarnessSettings.restartLimit` the task ends (the built-in
|
|
668
|
+
* tasks end themselves, visibly; the scheduler faults any other kind), and a generation reads it to charge an
|
|
669
|
+
* interrupted model request as a failed attempt.
|
|
670
|
+
*/
|
|
671
|
+
readonly restarts?: number;
|
|
505
672
|
};
|
|
506
673
|
/** Complete replacement record for one durable task state machine. */
|
|
507
674
|
export type TaskRecord<I, S, R> = TaskRecordBase<I, R> & ({
|
|
508
675
|
readonly state: Extract<TaskState<S, R>, {
|
|
509
|
-
readonly status: "pending" | "running" | "waiting";
|
|
676
|
+
readonly status: "pending" | "running" | "waiting" | "sleeping";
|
|
510
677
|
}>;
|
|
511
678
|
/** Small first-writer-wins values retained while the task can run. */
|
|
512
679
|
readonly memos?: Readonly<Record<string, JsonValue>>;
|
|
@@ -674,20 +841,30 @@ export type StorageWrite = {
|
|
|
674
841
|
readonly type: "document.retire";
|
|
675
842
|
readonly id: DocumentId;
|
|
676
843
|
};
|
|
677
|
-
/**
|
|
844
|
+
/**
|
|
845
|
+
* Committed change of one document incarnation: `type: "document"` with `kind: "change"` (a creation or an update) or
|
|
846
|
+
* `kind: "retire"` (this commit retired the incarnation), or a `document.copy`.
|
|
847
|
+
*/
|
|
678
848
|
export type DocumentCommitChange = {
|
|
679
849
|
readonly type: "document";
|
|
850
|
+
readonly kind: "change";
|
|
680
851
|
readonly record: DocumentRecord;
|
|
681
852
|
/** Conversation owning the document; task documents derive it from their task record. Undefined only for Session documents. */
|
|
682
853
|
readonly conversationId: ConversationId | undefined;
|
|
683
|
-
/** Definition version of `value
|
|
684
|
-
readonly version: number
|
|
685
|
-
/** Exact adopted immutable revision
|
|
686
|
-
readonly value: JsonObject
|
|
687
|
-
/** Exact adopted operations for an ordinary update; empty for creation
|
|
854
|
+
/** Definition version of `value`. */
|
|
855
|
+
readonly version: number;
|
|
856
|
+
/** Exact adopted immutable revision. */
|
|
857
|
+
readonly value: JsonObject;
|
|
858
|
+
/** Exact adopted operations for an ordinary update; empty for creation. */
|
|
688
859
|
readonly ops: readonly Op[];
|
|
689
860
|
} | {
|
|
690
|
-
|
|
861
|
+
readonly type: "document";
|
|
862
|
+
readonly kind: "retire";
|
|
863
|
+
readonly record: DocumentRecord;
|
|
864
|
+
/** Conversation owning the document; task documents derive it from their task record. Undefined only for Session documents. */
|
|
865
|
+
readonly conversationId: ConversationId | undefined;
|
|
866
|
+
} | {
|
|
867
|
+
/** Definition-free child initialization; consumers hydrate through watch acquisition. */
|
|
691
868
|
readonly type: "document.copy";
|
|
692
869
|
readonly record: DocumentRecord;
|
|
693
870
|
readonly conversationId: ConversationId;
|
|
@@ -698,14 +875,20 @@ export type TableCommitChange = Extract<StorageWrite, {
|
|
|
698
875
|
readonly type: "conversation" | "entry" | "task" | "submission";
|
|
699
876
|
}>;
|
|
700
877
|
export type CommitChange = TableCommitChange | DocumentCommitChange;
|
|
701
|
-
/**
|
|
878
|
+
/**
|
|
879
|
+
* Every immutable change one Session storage transaction stored, with its `seq`. Change order is unspecified. A commit
|
|
880
|
+
* held in memory (`CommitPersistence`) is published once it is stored: by the next commit that reads or writes its
|
|
881
|
+
* document, alone (`seq` of its own), or with that commit, whose document change then carries the held operations
|
|
882
|
+
* followed by its own.
|
|
883
|
+
*/
|
|
702
884
|
export type CommitPublication = {
|
|
703
885
|
readonly seq: Seq;
|
|
704
886
|
readonly changes: readonly CommitChange[];
|
|
705
887
|
};
|
|
706
888
|
/**
|
|
707
889
|
* Transaction surface of one Session commit callback.
|
|
708
|
-
* Table reads and creation results are trusted immutable values and may be shared with internal commit state
|
|
890
|
+
* Table reads and creation results are trusted immutable values and may be shared with internal commit state; the
|
|
891
|
+
* Session may freeze them (its caches and context ranges keep them), so mutating one can throw.
|
|
709
892
|
*/
|
|
710
893
|
export interface Tx {
|
|
711
894
|
conversation(id: ConversationId): Promise<ConversationRecord | undefined>;
|
|
@@ -719,6 +902,8 @@ export interface Tx {
|
|
|
719
902
|
latestHeadMarker(conversationId: ConversationId): Promise<(EntryRecord & {
|
|
720
903
|
readonly head: EntryId;
|
|
721
904
|
}) | undefined>;
|
|
905
|
+
/** ID of the newest entry visible from the conversation; `undefined` when it has none. */
|
|
906
|
+
latestEntryId(conversationId: ConversationId): Promise<EntryId | undefined>;
|
|
722
907
|
scanTasks(query: TaskQuery, limit: number, cursor?: Cursor): Promise<Page<TaskRecord<JsonValue, JsonValue, JsonValue>, Cursor>>;
|
|
723
908
|
/** Committed submission with a conversation-scoped request ID. */
|
|
724
909
|
submissionByRequest(conversationId: ConversationId, requestId: string): Promise<SubmissionRecord | undefined>;
|
|
@@ -743,7 +928,7 @@ export interface Tx {
|
|
|
743
928
|
*/
|
|
744
929
|
createSubmission(create: SubmissionCreate): Promise<SubmissionRecord>;
|
|
745
930
|
/**
|
|
746
|
-
* Settle a queued or placed submission; only a placed input can be answered, and a settled submission stays
|
|
931
|
+
* Settle a queued or placed submission; only a placed input or continue can be answered, and a settled submission stays
|
|
747
932
|
* unchanged. Resolved against this transaction's latest record of the submission, so it works after table writes.
|
|
748
933
|
* Run tasks settle the inputs they answer.
|
|
749
934
|
*/
|
|
@@ -766,32 +951,53 @@ export interface Tx {
|
|
|
766
951
|
retireDoc<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string): Promise<void>;
|
|
767
952
|
retireDoc<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string): Promise<void>;
|
|
768
953
|
}
|
|
769
|
-
/**
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
954
|
+
/**
|
|
955
|
+
* Watch of one document address (kind, scope, and key), from the incarnation found at acquisition on. A retirement is a
|
|
956
|
+
* call with `retired` set, the last value the watch was given and no ops (a change made in the retiring commit itself
|
|
957
|
+
* is not shown: that commit publishes the retirement only); the watch goes on, and a document created at the address
|
|
958
|
+
* later arrives as `[["r", value]]`, folded with what is pending. It ends `ended` when its scope's owner ends: a task
|
|
959
|
+
* document's watch once the retirement call of the commit that makes its task terminal returned, every watch at Session
|
|
960
|
+
* close (a pending retirement dropped); `failed` with the error that failed the Session.
|
|
961
|
+
*/
|
|
962
|
+
export type DocumentWatch<T extends JsonObject> = WatchHandle<Readonly<T>>;
|
|
963
|
+
/**
|
|
964
|
+
* A synchronous observer of committed Durable state, for adapters such as a Chord source (`observeDoc()`,
|
|
965
|
+
* `Harness.observeConversation()`, `Harness.observeTaskGraph()`), with the shapes of Chord's watch: `advance` gets a
|
|
966
|
+
* `WatchCall`, `end` a `WatchEnd`. `advance` gets every change, unfolded, as memory adopts it: for a stored commit at its
|
|
967
|
+
* publication once Storage stored it, for a deferred one before it is stored. A view or the graph gets at most one call
|
|
968
|
+
* per commit, a document observer one per change at its address (two for a commit that retires and recreates it); the
|
|
969
|
+
* task graph also advances outside any commit's publication, on the Session line, when a registry change or a failed
|
|
970
|
+
* migration changes a
|
|
971
|
+
* `blocked` reason. Durable's failures are final, so every call is a `value` call; a failure ends the observer. Calls
|
|
972
|
+
* may come before the attaching promise resolves; their ops apply from `Observation.value`. `advance` must only record
|
|
973
|
+
* the call, synchronously and quickly, never await, call the Session, or throw. A throw is reported as
|
|
974
|
+
* `listener_error`, detaches the observer, and ends it `listener_error` with the error. `end` is called once: `ended`
|
|
975
|
+
* when the observed scope's owner ends (a task document's task, after its retirement change, inside that commit's
|
|
976
|
+
* `adopt`), `failed` with "session closed" when the Session closes (an adapter follows the next Session) or with the
|
|
977
|
+
* error that failed the Session; never after `detach()`.
|
|
978
|
+
*/
|
|
979
|
+
export type Observer<T> = {
|
|
980
|
+
advance(call: WatchCall<T>, context: Context): void;
|
|
981
|
+
end(end: WatchEnd): void;
|
|
982
|
+
};
|
|
983
|
+
/**
|
|
984
|
+
* A synchronous observer of stored commits (`Session.observeCommits()`): `advance` gets each `CommitPublication`, `end`
|
|
985
|
+
* the Session's close (`failed` with "session closed", or with the error that failed the Session).
|
|
986
|
+
*/
|
|
987
|
+
export type CommitObserver = {
|
|
988
|
+
advance(publication: CommitPublication, context: Context): void;
|
|
989
|
+
end(end: WatchEnd): void;
|
|
990
|
+
};
|
|
991
|
+
/** An attached `CommitObserver`: how to detach it. Idempotent: no `advance` or `end` follows it. */
|
|
992
|
+
export type CommitObservation = {
|
|
993
|
+
detach(): void;
|
|
782
994
|
};
|
|
783
|
-
/**
|
|
784
|
-
export
|
|
785
|
-
/** Acquisition revision before start; latest delivered immutable revision afterward. */
|
|
995
|
+
/** An attached `Observer`: the value at attachment, which every later `advance` starts from, and how to detach it. */
|
|
996
|
+
export type Observation<T> = {
|
|
786
997
|
readonly value: T;
|
|
787
|
-
/**
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
stop(): Promise<WatchEnd>;
|
|
791
|
-
/** Settle when the watch terminates; an already-running callback remains caller-owned. */
|
|
792
|
-
readonly closed: Promise<WatchEnd>;
|
|
793
|
-
}
|
|
794
|
-
export type DocumentWatch<T extends JsonObject> = WatchHandle<Readonly<T> | null>;
|
|
998
|
+
/** Idempotent: no `advance` or `end` follows it, not even for the rest of a commit underway. */
|
|
999
|
+
detach(): void;
|
|
1000
|
+
};
|
|
795
1001
|
/** Committed document reads. */
|
|
796
1002
|
export type DocumentReader = Pick<Session, "snapshot" | "snapshotAsOf">;
|
|
797
1003
|
/** Non-creating document watch acquisition shared by Session and later invocation APIs. */
|
|
@@ -803,19 +1009,43 @@ export interface DocumentObserver {
|
|
|
803
1009
|
watchDoc<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
804
1010
|
watchDoc<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
805
1011
|
}
|
|
806
|
-
/** Why a Session ended
|
|
1012
|
+
/** Why a Session ended, by `kind`: `close()`, or a failed Storage call, whose error it carries. */
|
|
807
1013
|
export type SessionEnd = {
|
|
808
|
-
readonly
|
|
1014
|
+
readonly kind: "closed";
|
|
809
1015
|
} | {
|
|
810
|
-
readonly
|
|
1016
|
+
readonly kind: "failed";
|
|
811
1017
|
readonly error: unknown;
|
|
812
1018
|
};
|
|
1019
|
+
/**
|
|
1020
|
+
* When a commit reaches Storage. `immediate`, the default: before `commit()` resolves. `deferred`: when every write of
|
|
1021
|
+
* the commit changes an existing conversation document with `history: "latest"` and `fork: "initial"` (no creation,
|
|
1022
|
+
* migration, or retirement), the Session adopts it in memory, shows it to watches and views, and resolves, but stores it
|
|
1023
|
+
* later: with the next commit that reads (`tx.doc()`) or writes that document, before the document leaves memory or
|
|
1024
|
+
* retires, at `close()`, and at the latest about `withinMs` after the commit (default `settings.progress.persistWithinMs`,
|
|
1025
|
+
* 1,000 ms; `Infinity` waits for one of the others). A commit that writes anything else is immediate. A crash loses what
|
|
1026
|
+
* is held, so only state whose loss is acceptable, such as streamed progress, should be deferred, and nothing durable may
|
|
1027
|
+
* depend on it without reading it in a commit.
|
|
1028
|
+
*/
|
|
1029
|
+
export type CommitPersistence = {
|
|
1030
|
+
readonly kind: "immediate";
|
|
1031
|
+
} | {
|
|
1032
|
+
readonly kind: "deferred";
|
|
1033
|
+
readonly withinMs?: number;
|
|
1034
|
+
};
|
|
1035
|
+
/** Options of one Session commit. */
|
|
1036
|
+
export type CommitOptions = {
|
|
1037
|
+
readonly persistence?: CommitPersistence;
|
|
1038
|
+
};
|
|
813
1039
|
/** Owner of one mutation line, its records, and its tracked documents. */
|
|
814
1040
|
export interface Session extends DocumentObserver {
|
|
815
1041
|
/**
|
|
816
|
-
* Run one atomic transaction on the Session mutation line. Inside the callback read only through `tx`: `snapshot()`, `
|
|
1042
|
+
* Run one atomic transaction on the Session mutation line. Inside the callback read only through `tx`: `snapshot()`, `watchDoc()`, `getTask()`, and the other Session and runtime reads may queue on the line the callback holds, and then never resolve.
|
|
1043
|
+
* `options.persistence` may defer storing it (`CommitPersistence`). The callback may run while an earlier commit is
|
|
1044
|
+
* being stored: at its first read or write of what an unpublished commit wrote, it waits until that commit is stored
|
|
1045
|
+
* and published; code before that runs early, so act on what it computes only once the commit resolves. Resolves
|
|
1046
|
+
* once the commit is stored and published, after every earlier commit's outcome.
|
|
817
1047
|
*/
|
|
818
|
-
commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context): Promise<T>;
|
|
1048
|
+
commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context, options?: CommitOptions): Promise<T>;
|
|
819
1049
|
/** Seal admission, settle admitted commits, then close storage. */
|
|
820
1050
|
close(context: Context): Promise<void>;
|
|
821
1051
|
/**
|
|
@@ -823,8 +1053,30 @@ export interface Session extends DocumentObserver {
|
|
|
823
1053
|
* which closes the Session itself. A failed Session is reopened from Storage; nothing else is left to clean up.
|
|
824
1054
|
*/
|
|
825
1055
|
readonly closed: Promise<SessionEnd>;
|
|
826
|
-
/**
|
|
827
|
-
|
|
1056
|
+
/**
|
|
1057
|
+
* Attach a synchronous `Observer` to one document address, atomically on the Session line, as `watchDoc()` acquires
|
|
1058
|
+
* a watch: the observation's value includes every commit before it, and `advance` gets every later one, retirements
|
|
1059
|
+
* and later incarnations included. `undefined` when the address is absent. `context` governs only the attachment:
|
|
1060
|
+
* cancelled while attaching, the promise rejects and nothing stays attached.
|
|
1061
|
+
*/
|
|
1062
|
+
observeDoc<T extends JsonObject>(token: SessionDocToken<T>, observer: Observer<Readonly<T>>, context: Context): Promise<Observation<Readonly<T>> | undefined>;
|
|
1063
|
+
observeDoc<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId, observer: Observer<Readonly<T>>, context: Context): Promise<Observation<Readonly<T>> | undefined>;
|
|
1064
|
+
observeDoc<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId, observer: Observer<Readonly<T>>, context: Context): Promise<Observation<Readonly<T>> | undefined>;
|
|
1065
|
+
observeDoc<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, observer: Observer<Readonly<T>>, context: Context): Promise<Observation<Readonly<T>> | undefined>;
|
|
1066
|
+
observeDoc<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, observer: Observer<Readonly<T>>, context: Context): Promise<Observation<Readonly<T>> | undefined>;
|
|
1067
|
+
observeDoc<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, observer: Observer<Readonly<T>>, context: Context): Promise<Observation<Readonly<T>> | undefined>;
|
|
1068
|
+
/**
|
|
1069
|
+
* Observe stored commits, each with exactly what it stored, except that a document the commit retires is published
|
|
1070
|
+
* as its retirement only; a commit held in memory is published when it is stored (`CommitPublication`). Commits are
|
|
1071
|
+
* published in line order once Storage stored them, a macrotask apart; a publication queues one dispatch, which runs
|
|
1072
|
+
* a microtask later, before every wait the commit resolves and every abort it queues, and calls the observers
|
|
1073
|
+
* attached by then; a commit published while none was attached has no dispatch. There is no order relative to watch listeners. `advance` runs synchronously and must not block or
|
|
1074
|
+
* call Session APIs; a throw is reported as `listener_error`, detaches the observer, and ends it `listener_error`.
|
|
1075
|
+
* `end` is called once, when the Session closes (`ended`, after its last publication) or fails (`failed`), never
|
|
1076
|
+
* after `detach()`. Attaches synchronously; the observation has no `value`: commits are events, not a state, and the
|
|
1077
|
+
* Session does not know Storage's newest `seq` before its own first commit.
|
|
1078
|
+
*/
|
|
1079
|
+
observeCommits(observer: CommitObserver): CommitObservation;
|
|
828
1080
|
/**
|
|
829
1081
|
* Observe close synchronously when it begins, also when a failed Storage call closes the Session. The listener must
|
|
830
1082
|
* not block or call Session APIs.
|
|
@@ -836,15 +1088,14 @@ export interface Session extends DocumentObserver {
|
|
|
836
1088
|
snapshot<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, context: Context): Promise<Readonly<T> | undefined>;
|
|
837
1089
|
snapshot<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, context: Context): Promise<Readonly<T> | undefined>;
|
|
838
1090
|
snapshot<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, context: Context): Promise<Readonly<T> | undefined>;
|
|
839
|
-
documentState<T extends JsonObject>(token: SessionDocToken<T>, context: Context): Promise<DocumentState<T> | undefined>;
|
|
840
|
-
documentState<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId, context: Context): Promise<DocumentState<T> | undefined>;
|
|
841
|
-
documentState<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId, context: Context): Promise<DocumentState<T> | undefined>;
|
|
842
|
-
documentState<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, context: Context): Promise<DocumentState<T> | undefined>;
|
|
843
|
-
documentState<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, context: Context): Promise<DocumentState<T> | undefined>;
|
|
844
|
-
documentState<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, context: Context): Promise<DocumentState<T> | undefined>;
|
|
845
1091
|
snapshotAsOf<T extends JsonObject>(token: RewindableConversationDocToken<T>, conversationId: ConversationId, at: EntryId, context: Context): Promise<Readonly<T> | undefined>;
|
|
846
1092
|
snapshotAsOf<T extends JsonObject, I extends JsonValue>(token: RewindableConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, at: EntryId, context: Context): Promise<Readonly<T> | undefined>;
|
|
847
1093
|
}
|
|
1094
|
+
/** What `Storage.commit()` stored: the number of durable batches, and why the next one was refused, if one was. */
|
|
1095
|
+
export type CommitResult = {
|
|
1096
|
+
readonly stored: number;
|
|
1097
|
+
readonly refused?: unknown;
|
|
1098
|
+
};
|
|
848
1099
|
/**
|
|
849
1100
|
* Atomic persistence boundary for Session records.
|
|
850
1101
|
*
|
|
@@ -860,12 +1111,28 @@ export interface Session extends DocumentObserver {
|
|
|
860
1111
|
*/
|
|
861
1112
|
export interface Storage {
|
|
862
1113
|
/**
|
|
863
|
-
*
|
|
1114
|
+
* Persist `batches` in order, each as one ordinary atomic commit with its own seq, checked against the state the
|
|
1115
|
+
* earlier ones left, in as few round trips as the backend can. Every batch has at least one write: a commit without
|
|
1116
|
+
* writes never reaches Storage, so the Session never sends an empty batch. Stops at the first batch Durable's own checks refuse
|
|
1117
|
+
* (global IDs, document actions, copy resolution): the batches before it are durable, it and the ones after are not.
|
|
1118
|
+
* Calls `receive(index, seq)` once per durable batch, in order, synchronously, after all of them are durable and
|
|
1119
|
+
* before the next commit starts. Resolves with the number of durable batches and the refusal, if any. Rejects for an
|
|
1120
|
+
* unknown outcome (connection lost, statement or commit failed); `receive` calls made before the rejection still
|
|
1121
|
+
* stand. `receive` is a durability receipt, not publication: the Session publishes later. Once it resolved, later
|
|
1122
|
+
* reads through this storage observe the stored batches.
|
|
1123
|
+
*/
|
|
1124
|
+
commit(batches: readonly (readonly StorageWrite[])[], receive: (index: number, seq: Seq) => void, context: Context): Promise<CommitResult>;
|
|
1125
|
+
/**
|
|
1126
|
+
* Optional. Run `publish`, the Session's publication of one stored or held commit (its cache write-through,
|
|
1127
|
+
* adoption, and observers), inside this storage's own scope, such as a store's attached host batch, so what the
|
|
1128
|
+
* publication marks lands together. Call `publish` exactly once, now or soon after; the Session publishes the next
|
|
1129
|
+
* commit only once it ran. Without it, the Session publishes directly.
|
|
864
1130
|
*/
|
|
865
|
-
|
|
1131
|
+
publishing?(publish: () => void, context: Context): void;
|
|
866
1132
|
/**
|
|
867
|
-
* Return a fresh branded candidate from the Session-global numeric ID namespace, greater than every ID minted
|
|
868
|
-
*
|
|
1133
|
+
* Return a fresh branded candidate from the Session-global numeric ID namespace, greater than every ID minted since
|
|
1134
|
+
* this storage was opened and every ID stored, also across reopen: scans order by ID as creation order, and the
|
|
1135
|
+
* Harness relies on it.
|
|
869
1136
|
*/
|
|
870
1137
|
mintId<I extends Id<string>>(): Promise<I>;
|
|
871
1138
|
/** Look up one conversation by exact ID. */
|