videobook-engine 4.2.0 → 5.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -39
- package/dist/artifacts.d.ts +5 -10
- package/dist/artifacts.d.ts.map +1 -1
- package/dist/artifacts.js +79 -142
- package/dist/artifacts.js.map +1 -1
- package/dist/books.d.ts +1 -1
- package/dist/books.d.ts.map +1 -1
- package/dist/books.js +16 -9
- package/dist/books.js.map +1 -1
- package/dist/cas.d.ts +2 -1
- package/dist/cas.d.ts.map +1 -1
- package/dist/cas.js +33 -4
- package/dist/cas.js.map +1 -1
- package/dist/catalog-gc-state.d.ts +4 -0
- package/dist/catalog-gc-state.d.ts.map +1 -0
- package/dist/catalog-gc-state.js +49 -0
- package/dist/catalog-gc-state.js.map +1 -0
- package/dist/catalog-metadata.d.ts +2 -2
- package/dist/catalog-metadata.js +3 -3
- package/dist/catalog-metadata.js.map +1 -1
- package/dist/context.d.ts +5 -5
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +17 -49
- package/dist/context.js.map +1 -1
- package/dist/domain.d.ts +35 -2
- package/dist/domain.d.ts.map +1 -1
- package/dist/domain.js +131 -161
- package/dist/domain.js.map +1 -1
- package/dist/edits.js +2 -2
- package/dist/edits.js.map +1 -1
- package/dist/engine-types.d.ts +159 -39
- package/dist/engine-types.d.ts.map +1 -1
- package/dist/engine-types.js +2 -1
- package/dist/engine-types.js.map +1 -1
- package/dist/engine.d.ts +30 -20
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +46 -4
- package/dist/engine.js.map +1 -1
- package/dist/files.d.ts +10 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +49 -2
- package/dist/files.js.map +1 -1
- package/dist/fork.d.ts +14 -30
- package/dist/fork.d.ts.map +1 -1
- package/dist/fork.js +18 -27
- package/dist/fork.js.map +1 -1
- package/dist/generations.d.ts +9 -0
- package/dist/generations.d.ts.map +1 -0
- package/dist/generations.js +175 -0
- package/dist/generations.js.map +1 -0
- package/dist/history.d.ts +2 -1
- package/dist/history.d.ts.map +1 -1
- package/dist/history.js +30 -57
- package/dist/history.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/inline-temporal-models.d.ts +43 -0
- package/dist/inline-temporal-models.d.ts.map +1 -0
- package/dist/inline-temporal-models.js +236 -0
- package/dist/inline-temporal-models.js.map +1 -0
- package/dist/isolated-models.d.ts +8 -0
- package/dist/isolated-models.d.ts.map +1 -0
- package/dist/isolated-models.js +25 -0
- package/dist/isolated-models.js.map +1 -0
- package/dist/job-queue.d.ts +1 -1
- package/dist/job-queue.d.ts.map +1 -1
- package/dist/job-queue.js +20 -6
- package/dist/job-queue.js.map +1 -1
- package/dist/media-image.d.ts +8 -0
- package/dist/media-image.d.ts.map +1 -0
- package/dist/media-image.js +41 -0
- package/dist/media-image.js.map +1 -0
- package/dist/media-process.d.ts +13 -0
- package/dist/media-process.d.ts.map +1 -0
- package/dist/media-process.js +89 -0
- package/dist/media-process.js.map +1 -0
- package/dist/media.d.ts +3 -3
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +5 -5
- package/dist/media.js.map +1 -1
- package/dist/merge-policy.d.ts +16 -36
- package/dist/merge-policy.d.ts.map +1 -1
- package/dist/merge-policy.js +13 -125
- package/dist/merge-policy.js.map +1 -1
- package/dist/metadata.d.ts +1 -0
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +13 -3
- package/dist/metadata.js.map +1 -1
- package/dist/migrate-grid-text.d.ts +17 -0
- package/dist/migrate-grid-text.d.ts.map +1 -0
- package/dist/migrate-grid-text.js +117 -0
- package/dist/migrate-grid-text.js.map +1 -0
- package/dist/migrate-grid-v22.d.ts +12 -0
- package/dist/migrate-grid-v22.d.ts.map +1 -0
- package/dist/migrate-grid-v22.js +166 -0
- package/dist/migrate-grid-v22.js.map +1 -0
- package/dist/migrate-grid-v23.d.ts +10 -0
- package/dist/migrate-grid-v23.d.ts.map +1 -0
- package/dist/migrate-grid-v23.js +31 -0
- package/dist/migrate-grid-v23.js.map +1 -0
- package/dist/migration-notebooks.d.ts +25 -0
- package/dist/migration-notebooks.d.ts.map +1 -0
- package/dist/migration-notebooks.js +131 -0
- package/dist/migration-notebooks.js.map +1 -0
- package/dist/migration-source.d.ts +6 -0
- package/dist/migration-source.d.ts.map +1 -0
- package/dist/migration-source.js +37 -0
- package/dist/migration-source.js.map +1 -0
- package/dist/migration-timeline.d.ts +36 -0
- package/dist/migration-timeline.d.ts.map +1 -0
- package/dist/migration-timeline.js +187 -0
- package/dist/migration-timeline.js.map +1 -0
- package/dist/migration-validation.d.ts +12 -0
- package/dist/migration-validation.d.ts.map +1 -0
- package/dist/migration-validation.js +68 -0
- package/dist/migration-validation.js.map +1 -0
- package/dist/migration.d.ts.map +1 -1
- package/dist/migration.js +220 -119
- package/dist/migration.js.map +1 -1
- package/dist/model-cache-paths.d.ts +2 -0
- package/dist/model-cache-paths.d.ts.map +1 -0
- package/dist/model-cache-paths.js +5 -0
- package/dist/model-cache-paths.js.map +1 -0
- package/dist/model-checksums.json +338 -0
- package/dist/model-file-resolver.d.ts +30 -0
- package/dist/model-file-resolver.d.ts.map +1 -0
- package/dist/model-file-resolver.js +304 -0
- package/dist/model-file-resolver.js.map +1 -0
- package/dist/model-identity.d.ts +13 -0
- package/dist/model-identity.d.ts.map +1 -0
- package/dist/model-identity.js +44 -0
- package/dist/model-identity.js.map +1 -0
- package/dist/model-worker-errors.d.ts +3 -0
- package/dist/model-worker-errors.d.ts.map +1 -0
- package/dist/model-worker-errors.js +12 -0
- package/dist/model-worker-errors.js.map +1 -0
- package/dist/model-worker-pool.d.ts +32 -0
- package/dist/model-worker-pool.d.ts.map +1 -0
- package/dist/model-worker-pool.js +269 -0
- package/dist/model-worker-pool.js.map +1 -0
- package/dist/model-worker-protocol.d.ts +42 -0
- package/dist/model-worker-protocol.d.ts.map +1 -0
- package/dist/model-worker-protocol.js +2 -0
- package/dist/model-worker-protocol.js.map +1 -0
- package/dist/model-worker.d.ts +2 -0
- package/dist/model-worker.d.ts.map +1 -0
- package/dist/model-worker.js +91 -0
- package/dist/model-worker.js.map +1 -0
- package/dist/mvp-contract-fixtures.js +1 -1
- package/dist/mvp-contract-fixtures.js.map +1 -1
- package/dist/mvp-contracts.d.ts +32 -8
- package/dist/mvp-contracts.d.ts.map +1 -1
- package/dist/mvp-contracts.js +1 -1
- package/dist/mvp-contracts.js.map +1 -1
- package/dist/notebook/types.d.ts +1 -29
- package/dist/notebook/types.d.ts.map +1 -1
- package/dist/notebook-grid.d.ts +46 -0
- package/dist/notebook-grid.d.ts.map +1 -0
- package/dist/notebook-grid.js +187 -0
- package/dist/notebook-grid.js.map +1 -0
- package/dist/notebook-media-artifact.d.ts +23 -0
- package/dist/notebook-media-artifact.d.ts.map +1 -0
- package/dist/notebook-media-artifact.js +67 -0
- package/dist/notebook-media-artifact.js.map +1 -0
- package/dist/notebook-mentions.d.ts +20 -0
- package/dist/notebook-mentions.d.ts.map +1 -0
- package/dist/notebook-mentions.js +54 -0
- package/dist/notebook-mentions.js.map +1 -0
- package/dist/runtime-services.js +4 -9
- package/dist/runtime-services.js.map +1 -1
- package/dist/schema.d.ts +4 -19
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +66 -92
- package/dist/schema.js.map +1 -1
- package/dist/search-provider-access.d.ts +11 -0
- package/dist/search-provider-access.d.ts.map +1 -0
- package/dist/search-provider-access.js +42 -0
- package/dist/search-provider-access.js.map +1 -0
- package/dist/similarity.d.ts +60 -1
- package/dist/similarity.d.ts.map +1 -1
- package/dist/similarity.js +174 -154
- package/dist/similarity.js.map +1 -1
- package/dist/status.js +8 -10
- package/dist/status.js.map +1 -1
- package/dist/store.d.ts +16 -2
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +171 -17
- package/dist/store.js.map +1 -1
- package/dist/temporal-index-cache.d.ts +13 -0
- package/dist/temporal-index-cache.d.ts.map +1 -0
- package/dist/temporal-index-cache.js +59 -0
- package/dist/temporal-index-cache.js.map +1 -0
- package/dist/temporal-model-manifests.d.ts +17 -0
- package/dist/temporal-model-manifests.d.ts.map +1 -0
- package/dist/temporal-model-manifests.js +33 -0
- package/dist/temporal-model-manifests.js.map +1 -0
- package/dist/temporal-models.d.ts +20 -35
- package/dist/temporal-models.d.ts.map +1 -1
- package/dist/temporal-models.js +23 -257
- package/dist/temporal-models.js.map +1 -1
- package/dist/temporal-search.d.ts +6 -3
- package/dist/temporal-search.d.ts.map +1 -1
- package/dist/temporal-search.js +438 -122
- package/dist/temporal-search.js.map +1 -1
- package/dist/temporal-vector-index.d.ts +46 -0
- package/dist/temporal-vector-index.d.ts.map +1 -0
- package/dist/temporal-vector-index.js +220 -0
- package/dist/temporal-vector-index.js.map +1 -0
- package/dist/third-party/@huggingface-jinja.LICENSE +21 -0
- package/dist/third-party/@huggingface-tokenizers.LICENSE +201 -0
- package/dist/third-party/@huggingface-transformers.LICENSE +202 -0
- package/dist/third-party/onnxruntime-common.LICENSE +21 -0
- package/dist/third-party/versions.json +23 -0
- package/dist/transformers-runtime.d.ts +2 -0
- package/dist/transformers-runtime.d.ts.map +1 -0
- package/dist/transformers-runtime.js +33014 -0
- package/dist/transformers-runtime.js.LEGAL.txt +12 -0
- package/dist/transformers-runtime.js.map +7 -0
- package/docs/doltlite-staging.md +69 -0
- package/docs/edit-performance.md +83 -0
- package/docs/engine-layout.md +56 -50
- package/docs/media-limits.md +57 -0
- package/docs/model-download-policy.md +15 -0
- package/docs/model-integrity.md +72 -0
- package/docs/model-isolation.md +72 -0
- package/docs/model-revisions.md +54 -0
- package/docs/mvp-prd.md +2 -2
- package/docs/release-evidence.md +300 -0
- package/docs/search-provider-consent.md +67 -0
- package/docs/semantic-durability.md +55 -0
- package/docs/temporal-search-performance.md +260 -0
- package/docs/v4-migration.md +83 -0
- package/fixtures/v5/contract-fixtures.json +4 -4
- package/package.json +31 -13
- package/dist/artifact-names.d.ts +0 -6
- package/dist/artifact-names.d.ts.map +0 -1
- package/dist/artifact-names.js +0 -56
- package/dist/artifact-names.js.map +0 -1
- package/dist/resolver.d.ts +0 -15
- package/dist/resolver.d.ts.map +0 -1
- package/dist/resolver.js +0 -81
- package/dist/resolver.js.map +0 -1
package/dist/domain.js
CHANGED
|
@@ -2,8 +2,9 @@ import { ok } from "./engine-types.js";
|
|
|
2
2
|
import { normalizeSearchLocation } from "./mvp-time.js";
|
|
3
3
|
import { resultOf, syncResultOf } from "./context.js";
|
|
4
4
|
import { assertUuidV7, newUuidV7 } from "./ids.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { LEGACY_NOTEBOOK_CELL_TYPE_ALIASES, NOTEBOOK_CELL_TYPES, } from "./schema.js";
|
|
6
|
+
import { firstEmptyNotebookGridSlots, isNotebookGridSlot, NOTEBOOK_GRID_ADDRESS_RANGE, } from "./notebook-grid.js";
|
|
7
|
+
import { canonicalJson, commitDateIso, parseCommitMessage, parseJson, } from "./store.js";
|
|
7
8
|
import { EngineFault } from "./store.js";
|
|
8
9
|
const NOTEBOOK_CELL_TYPE_SET = new Set(NOTEBOOK_CELL_TYPES);
|
|
9
10
|
export function createEntitiesApi(context) {
|
|
@@ -28,7 +29,9 @@ export function createNotebooksApi(context) {
|
|
|
28
29
|
}),
|
|
29
30
|
list: () => listNotebooks(context),
|
|
30
31
|
read: (notebookId) => syncResultOf(() => requiredNotebook(context, notebookId)),
|
|
31
|
-
write: (notebook) => writeNotebook(context, notebook),
|
|
32
|
+
write: (notebook, options) => writeNotebook(context, notebook, options),
|
|
33
|
+
cellHistory: (notebookId, cellId, options) => cellHistory(context, notebookId, cellId, options),
|
|
34
|
+
executionHistory: (notebookId, cellId, options) => executionHistory(context, notebookId, cellId, options),
|
|
32
35
|
insertCell: (notebookId, cell) => insertNotebookCell(context, notebookId, cell),
|
|
33
36
|
updateCell: (notebookId, cell) => updateNotebookCell(context, notebookId, cell),
|
|
34
37
|
moveCell: (notebookId, cellId, slot) => moveNotebookCell(context, notebookId, cellId, slot),
|
|
@@ -149,13 +152,13 @@ function listNotebooks(context) {
|
|
|
149
152
|
.all();
|
|
150
153
|
return rows.map((row) => notebookFromRows(context, row));
|
|
151
154
|
}
|
|
152
|
-
async function writeNotebook(context, notebook) {
|
|
155
|
+
async function writeNotebook(context, notebook, options) {
|
|
153
156
|
return resultOf(async () => {
|
|
154
157
|
assertUuidV7(notebook.id, "Notebook ID");
|
|
155
158
|
requiredNotebook(context, notebook.id);
|
|
156
159
|
validateNotebook(context, notebook);
|
|
157
160
|
const mutation = await context.store.semantic({
|
|
158
|
-
operation: "write_notebook",
|
|
161
|
+
operation: options?.operation ?? "write_notebook",
|
|
159
162
|
tables: [
|
|
160
163
|
"notebooks",
|
|
161
164
|
"notebook_fields",
|
|
@@ -163,13 +166,12 @@ async function writeNotebook(context, notebook) {
|
|
|
163
166
|
"notebook_cell_executions",
|
|
164
167
|
"notebook_generation_plans",
|
|
165
168
|
"notebook_run_plans",
|
|
166
|
-
"notebook_transcript_edits",
|
|
167
|
-
"notebook_transcript_attachments",
|
|
168
169
|
"edges",
|
|
169
170
|
"cell_references",
|
|
170
171
|
"pinned_search_results",
|
|
171
172
|
],
|
|
172
|
-
details: { notebookId: notebook.id },
|
|
173
|
+
details: { notebookId: notebook.id, ...options?.details },
|
|
174
|
+
...(options?.artifactId ? { artifactId: options.artifactId } : {}),
|
|
173
175
|
writeSet: [
|
|
174
176
|
`notebook:${notebook.id}`,
|
|
175
177
|
...notebook.cells.map((cell) => `cell:${notebook.id}:${cell.id}`),
|
|
@@ -185,6 +187,98 @@ async function writeNotebook(context, notebook) {
|
|
|
185
187
|
return ok(revisionFor(context, mutation.revision), mutation.revision);
|
|
186
188
|
});
|
|
187
189
|
}
|
|
190
|
+
function cellHistory(context, notebookId, cellId, options) {
|
|
191
|
+
assertUuidV7(notebookId, "Notebook ID");
|
|
192
|
+
assertUuidV7(cellId, "Cell ID");
|
|
193
|
+
const limit = Math.max(1, Math.min(options?.limit ?? 50, 500));
|
|
194
|
+
const commitMeta = commitMetaByHash(context);
|
|
195
|
+
let rows;
|
|
196
|
+
try {
|
|
197
|
+
rows = context.store.db
|
|
198
|
+
.prepare(`SELECT notebook_id, cell_id, type, label, grid_row, grid_column,
|
|
199
|
+
output_entity_id, prompt, provider, model, operation, tool,
|
|
200
|
+
inputs_json, output_artifact_id, commit_hash, committer, commit_date
|
|
201
|
+
FROM dolt_history_cells
|
|
202
|
+
WHERE notebook_id=? AND cell_id=?
|
|
203
|
+
ORDER BY commit_date DESC
|
|
204
|
+
LIMIT ?`)
|
|
205
|
+
.all(notebookId, cellId, limit);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
rows = context.store.db.doltHistoryOf("cells")
|
|
209
|
+
.filter((row) => row.notebook_id === notebookId && row.cell_id === cellId)
|
|
210
|
+
.sort((left, right) => right.commit_date.localeCompare(left.commit_date))
|
|
211
|
+
.slice(0, limit);
|
|
212
|
+
}
|
|
213
|
+
return rows.map((row) => {
|
|
214
|
+
const meta = commitMeta.get(row.commit_hash);
|
|
215
|
+
return {
|
|
216
|
+
commitHash: row.commit_hash,
|
|
217
|
+
commitDate: commitDateIso(row.commit_date),
|
|
218
|
+
committer: row.committer,
|
|
219
|
+
...(meta?.operation ? { operation: meta.operation } : {}),
|
|
220
|
+
...(meta?.operationId ? { operationId: meta.operationId } : {}),
|
|
221
|
+
...(meta?.artifactId ? { artifactId: meta.artifactId } : {}),
|
|
222
|
+
...(meta?.details ? { details: meta.details } : {}),
|
|
223
|
+
cell: rowToCell(row, [], []),
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function executionHistory(context, notebookId, cellId, options) {
|
|
228
|
+
assertUuidV7(notebookId, "Notebook ID");
|
|
229
|
+
assertUuidV7(cellId, "Cell ID");
|
|
230
|
+
const limit = Math.max(1, Math.min(options?.limit ?? 50, 500));
|
|
231
|
+
const commitMeta = commitMetaByHash(context);
|
|
232
|
+
let rows;
|
|
233
|
+
try {
|
|
234
|
+
rows = context.store.db
|
|
235
|
+
.prepare(`SELECT notebook_id, cell_id, fingerprint, status, output_artifact_id,
|
|
236
|
+
provider_artifact_id, run_id, completed_at, started_at,
|
|
237
|
+
updated_at, tool, error, stale, fixture_baseline,
|
|
238
|
+
commit_hash, committer, commit_date
|
|
239
|
+
FROM dolt_history_notebook_cell_executions
|
|
240
|
+
WHERE notebook_id=? AND cell_id=?
|
|
241
|
+
ORDER BY commit_date DESC
|
|
242
|
+
LIMIT ?`)
|
|
243
|
+
.all(notebookId, cellId, limit);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
rows = context.store.db.doltHistoryOf("notebook_cell_executions")
|
|
247
|
+
.filter((row) => row.notebook_id === notebookId && row.cell_id === cellId)
|
|
248
|
+
.sort((left, right) => right.commit_date.localeCompare(left.commit_date))
|
|
249
|
+
.slice(0, limit);
|
|
250
|
+
}
|
|
251
|
+
return rows.map((row) => {
|
|
252
|
+
const meta = commitMeta.get(row.commit_hash);
|
|
253
|
+
return {
|
|
254
|
+
commitHash: row.commit_hash,
|
|
255
|
+
commitDate: commitDateIso(row.commit_date),
|
|
256
|
+
committer: row.committer,
|
|
257
|
+
notebookId: row.notebook_id,
|
|
258
|
+
cellId: row.cell_id,
|
|
259
|
+
...(meta?.operation ? { operation: meta.operation } : {}),
|
|
260
|
+
...(meta?.operationId ? { operationId: meta.operationId } : {}),
|
|
261
|
+
...(meta?.artifactId ? { artifactId: meta.artifactId } : {}),
|
|
262
|
+
...(meta?.details ? { details: meta.details } : {}),
|
|
263
|
+
execution: executionFromRow(row),
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function commitMetaByHash(context) {
|
|
268
|
+
const map = new Map();
|
|
269
|
+
for (const commit of context.store.db.doltLog()) {
|
|
270
|
+
const parsed = parseCommitMessage(commit.message);
|
|
271
|
+
if (!parsed)
|
|
272
|
+
continue;
|
|
273
|
+
map.set(commit.commit_hash, {
|
|
274
|
+
operation: parsed.operation,
|
|
275
|
+
operationId: parsed.operationId,
|
|
276
|
+
...(parsed.artifactId ? { artifactId: parsed.artifactId } : {}),
|
|
277
|
+
details: parsed.details,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return map;
|
|
281
|
+
}
|
|
188
282
|
async function insertNotebookCell(context, notebookId, cell) {
|
|
189
283
|
return resultOf(async () => {
|
|
190
284
|
assertUuidV7(notebookId, "Notebook ID");
|
|
@@ -194,7 +288,6 @@ async function insertNotebookCell(context, notebookId, cell) {
|
|
|
194
288
|
}
|
|
195
289
|
const prospective = { ...notebook, cells: [...notebook.cells, cell] };
|
|
196
290
|
validateCellFields(context, prospective, cell);
|
|
197
|
-
assertCellSlugFree(context, notebookId, cell);
|
|
198
291
|
assertCellSlotFree(context, notebookId, cell);
|
|
199
292
|
const mutation = await context.store.semantic({
|
|
200
293
|
operation: "insert_cell",
|
|
@@ -223,7 +316,6 @@ async function updateNotebookCell(context, notebookId, cell) {
|
|
|
223
316
|
cells: notebook.cells.map((existing) => existing.id === cell.id ? cell : existing),
|
|
224
317
|
};
|
|
225
318
|
validateCellFields(context, prospective, cell);
|
|
226
|
-
assertCellSlugFree(context, notebookId, cell);
|
|
227
319
|
assertCellSlotFree(context, notebookId, cell);
|
|
228
320
|
const mutation = await context.store.semantic({
|
|
229
321
|
operation: "update_cell",
|
|
@@ -270,6 +362,7 @@ async function removeNotebookCell(context, notebookId, cellId) {
|
|
|
270
362
|
operation: "remove_cell",
|
|
271
363
|
tables: [
|
|
272
364
|
"cells",
|
|
365
|
+
"generations",
|
|
273
366
|
"notebook_cell_executions",
|
|
274
367
|
"notebook_generation_plans",
|
|
275
368
|
"edges",
|
|
@@ -287,15 +380,6 @@ async function removeNotebookCell(context, notebookId, cellId) {
|
|
|
287
380
|
return ok(revisionFor(context, mutation.revision), mutation.revision);
|
|
288
381
|
});
|
|
289
382
|
}
|
|
290
|
-
function assertCellSlugFree(context, notebookId, cell) {
|
|
291
|
-
const found = context.store.db
|
|
292
|
-
.prepare(`SELECT cell_id FROM cells
|
|
293
|
-
WHERE notebook_id=? AND slug=? AND cell_id<>?`)
|
|
294
|
-
.get(notebookId, cell.slug, cell.id);
|
|
295
|
-
if (found) {
|
|
296
|
-
throw new Error(`Duplicate cell slug: ${cell.slug}`);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
383
|
function assertCellSlotFree(context, notebookId, cell) {
|
|
300
384
|
const found = context.store.db
|
|
301
385
|
.prepare(`SELECT cell_id FROM cells
|
|
@@ -305,13 +389,6 @@ function assertCellSlotFree(context, notebookId, cell) {
|
|
|
305
389
|
throw new Error(`Cell slot is occupied: ${cell.slot.row}:${cell.slot.column}`);
|
|
306
390
|
}
|
|
307
391
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Repairs grid-slot collisions left behind by a merge (the schema no longer
|
|
310
|
-
* enforces slot uniqueness so two forks can land cells on the same slot).
|
|
311
|
-
* Within each colliding slot the protected cell wins when present, otherwise
|
|
312
|
-
* the lowest cell id; losers keep their column and move to fresh rows below
|
|
313
|
-
* the current grid, in cell-id order.
|
|
314
|
-
*/
|
|
315
392
|
function repairCellSlots(context, notebookId, protectedCellId) {
|
|
316
393
|
const rows = context.store.db
|
|
317
394
|
.prepare(`SELECT cell_id, grid_row, grid_column FROM cells
|
|
@@ -319,67 +396,46 @@ function repairCellSlots(context, notebookId, protectedCellId) {
|
|
|
319
396
|
ORDER BY grid_row, grid_column, cell_id`)
|
|
320
397
|
.all(notebookId);
|
|
321
398
|
const slots = new Map();
|
|
322
|
-
let maxRow = -1;
|
|
323
399
|
for (const row of rows) {
|
|
324
|
-
maxRow = Math.max(maxRow, row.grid_row);
|
|
325
400
|
const key = `${row.grid_row}:${row.grid_column}`;
|
|
326
401
|
const group = slots.get(key) ?? [];
|
|
327
|
-
group.push(
|
|
402
|
+
group.push(row);
|
|
328
403
|
slots.set(key, group);
|
|
329
404
|
}
|
|
330
|
-
|
|
331
|
-
const
|
|
405
|
+
const occupied = [];
|
|
406
|
+
const losers = [];
|
|
332
407
|
for (const group of slots.values()) {
|
|
333
|
-
if (group.length < 2)
|
|
334
|
-
continue;
|
|
335
408
|
const winner = protectedCellId && group.some((row) => row.cell_id === protectedCellId)
|
|
336
409
|
? protectedCellId
|
|
337
410
|
: group[0].cell_id;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
411
|
+
const winnerRow = group.find((row) => row.cell_id === winner);
|
|
412
|
+
occupied.push({
|
|
413
|
+
row: winnerRow.grid_row,
|
|
414
|
+
column: winnerRow.grid_column,
|
|
415
|
+
});
|
|
416
|
+
losers.push(...group
|
|
417
|
+
.filter((row) => row.cell_id !== winner)
|
|
418
|
+
.map((row) => row.cell_id));
|
|
344
419
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
* its current one — same type prefix, so the slug/type CHECK holds — and
|
|
352
|
-
* the upsert pass then assigns the final slugs.
|
|
353
|
-
*/
|
|
354
|
-
function evacuateChangedCellSlugs(context, notebook) {
|
|
355
|
-
const existing = context.store.db
|
|
356
|
-
.prepare("SELECT cell_id, slug FROM cells WHERE notebook_id=?")
|
|
357
|
-
.all(notebook.id);
|
|
358
|
-
if (existing.length === 0)
|
|
359
|
-
return;
|
|
360
|
-
const incomingSlugs = new Map(notebook.cells.map((cell) => [
|
|
361
|
-
cell.id,
|
|
362
|
-
normalizeCellForWrite(cell).slug ?? "",
|
|
363
|
-
]));
|
|
364
|
-
const evacuate = context.store.db.prepare("UPDATE cells SET slug=? WHERE notebook_id=? AND cell_id=?");
|
|
365
|
-
for (const row of existing) {
|
|
366
|
-
const nextSlug = incomingSlugs.get(row.cell_id);
|
|
367
|
-
if (nextSlug === undefined || nextSlug === row.slug)
|
|
368
|
-
continue;
|
|
369
|
-
evacuate.run(`${row.slug}-evac-${newUuidV7().replace(/-/g, "")}`, notebook.id, row.cell_id);
|
|
420
|
+
const destinations = firstEmptyNotebookGridSlots(occupied, losers.length);
|
|
421
|
+
const move = context.store.db.prepare(`UPDATE cells SET grid_row=?, grid_column=?
|
|
422
|
+
WHERE notebook_id=? AND cell_id=?`);
|
|
423
|
+
for (const [index, cellId] of losers.entries()) {
|
|
424
|
+
const slot = destinations[index];
|
|
425
|
+
move.run(slot.row, slot.column, notebookId, cellId);
|
|
370
426
|
}
|
|
371
427
|
}
|
|
372
428
|
function upsertNotebookCell(context, notebookId, cell) {
|
|
373
429
|
const normalized = normalizeCellForWrite(cell);
|
|
374
430
|
context.store.db
|
|
375
431
|
.prepare(`INSERT INTO cells(
|
|
376
|
-
notebook_id, cell_id, type,
|
|
432
|
+
notebook_id, cell_id, type, label, grid_row, grid_column,
|
|
377
433
|
output_entity_id, prompt, provider, model, operation, tool,
|
|
378
434
|
inputs_json, output_artifact_id
|
|
379
435
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
380
436
|
ON CONFLICT(notebook_id, cell_id) DO UPDATE SET
|
|
381
437
|
type=excluded.type,
|
|
382
|
-
|
|
438
|
+
label=excluded.label,
|
|
383
439
|
grid_row=excluded.grid_row,
|
|
384
440
|
grid_column=excluded.grid_column,
|
|
385
441
|
output_entity_id=excluded.output_entity_id,
|
|
@@ -390,7 +446,7 @@ function upsertNotebookCell(context, notebookId, cell) {
|
|
|
390
446
|
tool=excluded.tool,
|
|
391
447
|
inputs_json=excluded.inputs_json,
|
|
392
448
|
output_artifact_id=excluded.output_artifact_id`)
|
|
393
|
-
.run(notebookId, normalized.id, normalized.type,
|
|
449
|
+
.run(notebookId, normalized.id, normalized.type, normalized.label?.trim() || null, normalized.slot.row, normalized.slot.column, normalized.outputEntityId ?? null, normalized.prompt ?? null, normalized.provider ?? null, normalized.model ?? null, normalized.operation ?? null, normalized.tool ?? null, canonicalJson(normalized.inputs ?? {}), normalized.outputArtifactId ?? null);
|
|
394
450
|
synchronizeCellReferences(context, notebookId, normalized);
|
|
395
451
|
synchronizePinnedResults(context, notebookId, normalized);
|
|
396
452
|
}
|
|
@@ -404,11 +460,10 @@ async function deleteNotebook(context, notebookId) {
|
|
|
404
460
|
"notebooks",
|
|
405
461
|
"notebook_fields",
|
|
406
462
|
"cells",
|
|
463
|
+
"generations",
|
|
407
464
|
"notebook_cell_executions",
|
|
408
465
|
"notebook_generation_plans",
|
|
409
466
|
"notebook_run_plans",
|
|
410
|
-
"notebook_transcript_edits",
|
|
411
|
-
"notebook_transcript_attachments",
|
|
412
467
|
"edges",
|
|
413
468
|
"runs",
|
|
414
469
|
"cell_references",
|
|
@@ -485,7 +540,7 @@ function notebookFromRows(context, row) {
|
|
|
485
540
|
ORDER BY field`)
|
|
486
541
|
.all(row.notebook_id);
|
|
487
542
|
const cells = context.store.db
|
|
488
|
-
.prepare(`SELECT cell_id, type,
|
|
543
|
+
.prepare(`SELECT cell_id, type, label, grid_row, grid_column, output_entity_id,
|
|
489
544
|
prompt, provider, model, operation, tool,
|
|
490
545
|
inputs_json, output_artifact_id
|
|
491
546
|
FROM cells WHERE notebook_id=?
|
|
@@ -529,16 +584,6 @@ function notebookFromRows(context, row) {
|
|
|
529
584
|
FROM notebook_run_plans
|
|
530
585
|
WHERE notebook_id=? ORDER BY created_at, plan_id`)
|
|
531
586
|
.all(row.notebook_id);
|
|
532
|
-
const transcriptEdits = context.store.db
|
|
533
|
-
.prepare(`SELECT action_id, kind, restored, payload_json
|
|
534
|
-
FROM notebook_transcript_edits
|
|
535
|
-
WHERE notebook_id=? ORDER BY action_id`)
|
|
536
|
-
.all(row.notebook_id);
|
|
537
|
-
const transcriptAttachments = context.store.db
|
|
538
|
-
.prepare(`SELECT attachment_id, payload_json
|
|
539
|
-
FROM notebook_transcript_attachments
|
|
540
|
-
WHERE notebook_id=? ORDER BY attachment_id`)
|
|
541
|
-
.all(row.notebook_id);
|
|
542
587
|
const field = new Map(fields.map((item) => [
|
|
543
588
|
item.field,
|
|
544
589
|
parseJson(item.value_json, null),
|
|
@@ -558,16 +603,6 @@ function notebookFromRows(context, row) {
|
|
|
558
603
|
...(typeof field.get("analysis_revision") === "string"
|
|
559
604
|
? { analysisRevision: field.get("analysis_revision") }
|
|
560
605
|
: {}),
|
|
561
|
-
...(isRecord(field.get("audio_spine"))
|
|
562
|
-
? {
|
|
563
|
-
audioSpine: field.get("audio_spine"),
|
|
564
|
-
}
|
|
565
|
-
: {}),
|
|
566
|
-
...(isRecord(field.get("current_selection"))
|
|
567
|
-
? {
|
|
568
|
-
currentSelection: field.get("current_selection"),
|
|
569
|
-
}
|
|
570
|
-
: {}),
|
|
571
606
|
...(isRecord(field.get("fixture"))
|
|
572
607
|
? { fixture: field.get("fixture") }
|
|
573
608
|
: {}),
|
|
@@ -577,8 +612,6 @@ function notebookFromRows(context, row) {
|
|
|
577
612
|
])),
|
|
578
613
|
generationPlans: generationPlans.map(generationPlanFromRow),
|
|
579
614
|
notebookRunPlans: runPlans.map(runPlanFromRow),
|
|
580
|
-
transcriptEdits: transcriptEdits.map(transcriptEditFromRow),
|
|
581
|
-
transcriptAttachments: transcriptAttachments.map(transcriptAttachmentFromRow),
|
|
582
615
|
cells: cells.map((cell) => rowToCell(cell, references.filter((reference) => reference.cell_id === cell.cell_id), pinnedResults.filter((result) => result.cell_id === cell.cell_id))),
|
|
583
616
|
edges: edges.map(rowToEdge),
|
|
584
617
|
createdAt: new Date(row.created_at).toISOString(),
|
|
@@ -586,16 +619,11 @@ function notebookFromRows(context, row) {
|
|
|
586
619
|
}
|
|
587
620
|
function validateNotebook(context, notebook) {
|
|
588
621
|
const cellIds = new Set();
|
|
589
|
-
const cellSlugs = new Set();
|
|
590
622
|
const occupiedSlots = new Set();
|
|
591
623
|
for (const cell of notebook.cells) {
|
|
592
624
|
if (cellIds.has(cell.id))
|
|
593
625
|
throw new Error(`Duplicate cell ID: ${cell.id}`);
|
|
594
626
|
cellIds.add(cell.id);
|
|
595
|
-
if (cellSlugs.has(cell.slug)) {
|
|
596
|
-
throw new Error(`Duplicate cell slug: ${cell.slug}`);
|
|
597
|
-
}
|
|
598
|
-
cellSlugs.add(cell.slug);
|
|
599
627
|
const slot = `${cell.slot.row}:${cell.slot.column}`;
|
|
600
628
|
if (occupiedSlots.has(slot))
|
|
601
629
|
throw new Error(`Duplicate cell slot: ${slot}`);
|
|
@@ -625,14 +653,8 @@ function validateCellFields(context, notebook, cell) {
|
|
|
625
653
|
if (!NOTEBOOK_CELL_TYPE_SET.has(cell.type)) {
|
|
626
654
|
throw new Error(`Invalid cell type: ${cell.type}`);
|
|
627
655
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
throw new Error(`Invalid ${cell.type} cell slug: ${cell.slug}`);
|
|
631
|
-
}
|
|
632
|
-
if (!Number.isInteger(cell.slot.row) ||
|
|
633
|
-
cell.slot.row < 0 ||
|
|
634
|
-
!Number.isInteger(cell.slot.column)) {
|
|
635
|
-
throw new Error(`Cell slot row must be nonnegative and column must be an integer: ${cell.id}`);
|
|
656
|
+
if (!isNotebookGridSlot(cell.slot)) {
|
|
657
|
+
throw new Error(`Cell slot must be within ${NOTEBOOK_GRID_ADDRESS_RANGE}: ${cell.id}`);
|
|
636
658
|
}
|
|
637
659
|
if (cell.outputEntityId) {
|
|
638
660
|
assertUuidV7(cell.outputEntityId, "Cell output entity ID");
|
|
@@ -648,7 +670,6 @@ function validateCellFields(context, notebook, cell) {
|
|
|
648
670
|
function synchronizeNotebookChildren(context, notebook) {
|
|
649
671
|
deleteMissing(context, "edges", "edge_id", notebook.id, notebook.edges.map((edge) => edge.id));
|
|
650
672
|
deleteMissing(context, "cells", "cell_id", notebook.id, notebook.cells.map((cell) => cell.id));
|
|
651
|
-
evacuateChangedCellSlugs(context, notebook);
|
|
652
673
|
for (const cell of notebook.cells) {
|
|
653
674
|
upsertNotebookCell(context, notebook.id, cell);
|
|
654
675
|
}
|
|
@@ -669,8 +690,6 @@ function synchronizeNotebookState(context, notebook) {
|
|
|
669
690
|
synchronizeCellExecutions(context, notebook);
|
|
670
691
|
synchronizeGenerationPlans(context, notebook);
|
|
671
692
|
synchronizeRunPlans(context, notebook);
|
|
672
|
-
synchronizeTranscriptEdits(context, notebook);
|
|
673
|
-
synchronizeTranscriptAttachments(context, notebook);
|
|
674
693
|
}
|
|
675
694
|
function synchronizeNotebookFields(context, notebook) {
|
|
676
695
|
const values = new Map();
|
|
@@ -689,12 +708,6 @@ function synchronizeNotebookFields(context, notebook) {
|
|
|
689
708
|
if (notebook.analysisRevision !== undefined) {
|
|
690
709
|
values.set("analysis_revision", notebook.analysisRevision);
|
|
691
710
|
}
|
|
692
|
-
if (notebook.audioSpine !== undefined) {
|
|
693
|
-
values.set("audio_spine", notebook.audioSpine);
|
|
694
|
-
}
|
|
695
|
-
if (notebook.currentSelection !== undefined) {
|
|
696
|
-
values.set("current_selection", notebook.currentSelection);
|
|
697
|
-
}
|
|
698
711
|
if (notebook.fixture !== undefined) {
|
|
699
712
|
values.set("fixture", notebook.fixture);
|
|
700
713
|
}
|
|
@@ -785,34 +798,6 @@ function synchronizeRunPlans(context, notebook) {
|
|
|
785
798
|
upsert.run(notebook.id, requiredText(plan.planId, "Notebook run plan ID"), requiredText(plan.status, "Notebook run plan status"), canonicalJson(plan.plan), canonicalJson(plan.paidCellIds), canonicalJson(plan.cellDefinitionFingerprints), nonNegativeFinite(plan.knownCostUsd, "Notebook run plan known cost"), nonNegativeInteger(plan.unknownCostCount, "Notebook run plan unknown cost count"), requiredText(plan.createdAt, "Notebook run plan created time"), requiredText(plan.updatedAt, "Notebook run plan updated time"), plan.runId ?? null, plan.outputs === undefined ? null : canonicalJson(plan.outputs), plan.error ?? null);
|
|
786
799
|
}
|
|
787
800
|
}
|
|
788
|
-
function synchronizeTranscriptEdits(context, notebook) {
|
|
789
|
-
const edits = notebook.transcriptEdits ?? [];
|
|
790
|
-
assertUnique(edits.map((edit) => edit.actionId), "transcript edit action ID");
|
|
791
|
-
deleteMissingNotebookRows(context, "notebook_transcript_edits", "action_id", notebook.id, edits.map((edit) => edit.actionId));
|
|
792
|
-
const upsert = context.store.db.prepare(`INSERT INTO notebook_transcript_edits(
|
|
793
|
-
notebook_id, action_id, kind, restored, payload_json
|
|
794
|
-
) VALUES (?, ?, ?, ?, ?)
|
|
795
|
-
ON CONFLICT(notebook_id, action_id) DO UPDATE SET
|
|
796
|
-
kind=excluded.kind,
|
|
797
|
-
restored=excluded.restored,
|
|
798
|
-
payload_json=excluded.payload_json`);
|
|
799
|
-
for (const edit of edits) {
|
|
800
|
-
upsert.run(notebook.id, requiredText(edit.actionId, "Transcript edit action ID"), requiredText(edit.kind, "Transcript edit kind"), edit.restored === true ? 1 : 0, canonicalJson(edit));
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
function synchronizeTranscriptAttachments(context, notebook) {
|
|
804
|
-
const attachments = notebook.transcriptAttachments ?? [];
|
|
805
|
-
assertUnique(attachments.map((attachment) => attachment.id), "transcript attachment ID");
|
|
806
|
-
deleteMissingNotebookRows(context, "notebook_transcript_attachments", "attachment_id", notebook.id, attachments.map((attachment) => attachment.id));
|
|
807
|
-
const upsert = context.store.db.prepare(`INSERT INTO notebook_transcript_attachments(
|
|
808
|
-
notebook_id, attachment_id, payload_json
|
|
809
|
-
) VALUES (?, ?, ?)
|
|
810
|
-
ON CONFLICT(notebook_id, attachment_id) DO UPDATE SET
|
|
811
|
-
payload_json=excluded.payload_json`);
|
|
812
|
-
for (const attachment of attachments) {
|
|
813
|
-
upsert.run(notebook.id, requiredText(attachment.id, "Transcript attachment ID"), canonicalJson(attachment));
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
801
|
function deleteMissingNotebookRows(context, table, idColumn, notebookId, ids) {
|
|
817
802
|
if (ids.length === 0) {
|
|
818
803
|
context.store.db
|
|
@@ -1015,7 +1000,7 @@ function rowToCell(row, references, pinnedResults) {
|
|
|
1015
1000
|
return {
|
|
1016
1001
|
id: row.cell_id,
|
|
1017
1002
|
type: notebookCellType(row.type),
|
|
1018
|
-
|
|
1003
|
+
...(row.label ? { label: row.label } : {}),
|
|
1019
1004
|
slot: { row: row.grid_row, column: row.grid_column },
|
|
1020
1005
|
...(row.output_entity_id ? { outputEntityId: row.output_entity_id } : {}),
|
|
1021
1006
|
...(row.prompt ? { prompt: row.prompt } : {}),
|
|
@@ -1032,10 +1017,11 @@ function rowToCell(row, references, pinnedResults) {
|
|
|
1032
1017
|
};
|
|
1033
1018
|
}
|
|
1034
1019
|
function notebookCellType(type) {
|
|
1035
|
-
|
|
1020
|
+
const resolved = LEGACY_NOTEBOOK_CELL_TYPE_ALIASES[type] ?? type;
|
|
1021
|
+
if (!NOTEBOOK_CELL_TYPE_SET.has(resolved)) {
|
|
1036
1022
|
throw new Error(`Invalid cell type: ${type}`);
|
|
1037
1023
|
}
|
|
1038
|
-
return
|
|
1024
|
+
return resolved;
|
|
1039
1025
|
}
|
|
1040
1026
|
function normalizeCellForWrite(cell) {
|
|
1041
1027
|
const inputs = { ...(cell.inputs ?? {}) };
|
|
@@ -1158,22 +1144,6 @@ function runPlanFromRow(row) {
|
|
|
1158
1144
|
...(row.error ? { error: row.error } : {}),
|
|
1159
1145
|
};
|
|
1160
1146
|
}
|
|
1161
|
-
function transcriptEditFromRow(row) {
|
|
1162
|
-
const payload = parseJson(row.payload_json, {});
|
|
1163
|
-
return {
|
|
1164
|
-
...payload,
|
|
1165
|
-
actionId: row.action_id,
|
|
1166
|
-
kind: row.kind,
|
|
1167
|
-
...(row.restored === 1 ? { restored: true } : {}),
|
|
1168
|
-
};
|
|
1169
|
-
}
|
|
1170
|
-
function transcriptAttachmentFromRow(row) {
|
|
1171
|
-
const payload = parseJson(row.payload_json, {});
|
|
1172
|
-
return {
|
|
1173
|
-
...payload,
|
|
1174
|
-
id: row.attachment_id,
|
|
1175
|
-
};
|
|
1176
|
-
}
|
|
1177
1147
|
function assertUnique(values, label) {
|
|
1178
1148
|
const unique = new Set(values);
|
|
1179
1149
|
if (unique.size !== values.length) {
|