wizards 0.2.16 → 0.2.18

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.
Files changed (90) hide show
  1. package/apps/runtime/dist/agents/project-assistant.js +20 -2
  2. package/apps/runtime/dist/authoring/guide.js +6 -3
  3. package/apps/runtime/dist/credits/estimate.js +14 -8
  4. package/apps/runtime/dist/db/migrations/tenant/0008_run_event_note.sql +1 -0
  5. package/apps/runtime/dist/db/migrations/tenant/0009_knowledge.sql +104 -0
  6. package/apps/runtime/dist/db/migrations/tenant/meta/0008_snapshot.json +2019 -0
  7. package/apps/runtime/dist/db/migrations/tenant/meta/0009_snapshot.json +2837 -0
  8. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +14 -0
  9. package/apps/runtime/dist/db/schema.js +162 -8
  10. package/apps/runtime/dist/engine/events.js +14 -2
  11. package/apps/runtime/dist/engine/prepare.js +5 -2
  12. package/apps/runtime/dist/engine/requirements.js +108 -0
  13. package/apps/runtime/dist/engine/runner.js +2 -2
  14. package/apps/runtime/dist/engine/steps.js +21 -21
  15. package/apps/runtime/dist/engine/template.js +13 -10
  16. package/apps/runtime/dist/env.js +2 -0
  17. package/apps/runtime/dist/files/storage.js +15 -0
  18. package/apps/runtime/dist/models.js +38 -0
  19. package/apps/runtime/dist/plugins/loader.js +2 -0
  20. package/apps/runtime/dist/routes/studio.js +149 -8
  21. package/apps/runtime/dist/services/cloud.js +59 -1
  22. package/apps/runtime/dist/services/knowledge-model.js +558 -0
  23. package/apps/runtime/dist/services/knowledge.js +721 -0
  24. package/apps/runtime/dist/services/marketplace.js +2 -2
  25. package/apps/runtime/dist/services/project-files.js +114 -6
  26. package/apps/runtime/dist/services/project-index.js +632 -94
  27. package/apps/runtime/dist/services/relevance.js +90 -0
  28. package/apps/runtime/dist/services/space-categories.js +882 -0
  29. package/apps/runtime/dist/services/space-data.js +466 -38
  30. package/apps/runtime/dist/services/space-origin.js +164 -0
  31. package/apps/runtime/dist/services/spaces.js +155 -1
  32. package/apps/runtime/dist/tools/browser.js +12 -6
  33. package/apps/runtime/dist/tools/index.js +12 -6
  34. package/apps/runtime/dist/tools/mail.js +5 -2
  35. package/apps/runtime/dist/tools/pages.js +28 -23
  36. package/apps/runtime/dist/tools/project.js +132 -39
  37. package/apps/runtime/dist/tools/store.js +4 -4
  38. package/apps/runtime/dist/widgets/step.js +10 -4
  39. package/apps/web/dist/assets/{Account-BE_W101C.js → Account-Cp1cgqjV.js} +1 -1
  40. package/apps/web/dist/assets/{ChangelogDialog-DjKQJAos.js → ChangelogDialog-Chke1qUe.js} +1 -1
  41. package/apps/web/dist/assets/ChatPanel-DWrwewr6.js +1 -0
  42. package/apps/web/dist/assets/CreditsDialog-Ckema8Ss.js +1 -0
  43. package/apps/web/dist/assets/EditorPage-XX6pfHk5.js +2 -0
  44. package/apps/web/dist/assets/{FlowPreview-DK4RZqTW.js → FlowPreview-DS545n78.js} +1 -1
  45. package/apps/web/dist/assets/{Harness-DcI94f1U.js → Harness-H3yXP-2L.js} +2 -2
  46. package/apps/web/dist/assets/{HomePage-BBNFgryu.js → HomePage-Bds84ShK.js} +1 -1
  47. package/apps/web/dist/assets/{ImportWizard-BoYqovdl.js → ImportWizard-0_NkA8aS.js} +1 -1
  48. package/apps/web/dist/assets/LocalRuntime-DnABzTOe.js +1 -0
  49. package/apps/web/dist/assets/{NewWizardPage-tKV2S4eK.js → NewWizardPage-BqP75V9K.js} +2 -2
  50. package/apps/web/dist/assets/ProjectPage-DbOvwOdZ.js +5 -0
  51. package/apps/web/dist/assets/PublicRunner-CtZ7vxl_.js +1 -0
  52. package/apps/web/dist/assets/RunnerView-xV5bWclu.js +70 -0
  53. package/apps/web/dist/assets/SettingsPage-DKt55zFh.js +1 -0
  54. package/apps/web/dist/assets/{SetupPage-qxHvlf87.js → SetupPage-c6mMD9zN.js} +1 -1
  55. package/apps/web/dist/assets/SharePage-DTKIbMj-.js +1 -0
  56. package/apps/web/dist/assets/{api-t9_w1XNe.js → api-CVG-xDEn.js} +2 -2
  57. package/apps/web/dist/assets/changelog-CXXT0zsp.js +1 -0
  58. package/apps/web/dist/assets/{esm-D0YVMTdo.js → esm-DLM3jdbm.js} +1 -1
  59. package/apps/web/dist/assets/index-1gmaxDSk.js +10 -0
  60. package/apps/web/dist/assets/index-Bwyehu0k.css +1 -0
  61. package/apps/web/dist/assets/{meta-BJHYbMh7.js → meta-m947x6uG.js} +1 -1
  62. package/apps/web/dist/assets/{settings-menu-BqqUAvIY.js → settings-menu-DUY6__C3.js} +1 -1
  63. package/apps/web/dist/assets/ui-BPY2pIh0.js +1 -0
  64. package/apps/web/dist/index.html +4 -4
  65. package/apps/web/dist/mcp/flow.html +54 -54
  66. package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +164 -0
  67. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +10 -0
  68. package/node_modules/@engenty-wizards/shared/dist/definition.js +25 -0
  69. package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +199 -0
  70. package/node_modules/@engenty-wizards/shared/dist/knowledge.js +68 -0
  71. package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +1 -16
  72. package/node_modules/@engenty-wizards/shared/dist/projects.js +1 -1
  73. package/node_modules/@engenty-wizards/shared/dist/run.d.ts +149 -0
  74. package/node_modules/@engenty-wizards/shared/dist/run.js +77 -1
  75. package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +20 -0
  76. package/node_modules/@engenty-wizards/shared/dist/space-data.js +2 -1
  77. package/package.json +1 -1
  78. package/apps/web/dist/assets/ChatPanel-BWrcDs4s.js +0 -1
  79. package/apps/web/dist/assets/CreditsDialog-DUjR5xkl.js +0 -1
  80. package/apps/web/dist/assets/EditorPage-CrOqikP2.js +0 -2
  81. package/apps/web/dist/assets/LocalRuntime-BD8zGN8w.js +0 -1
  82. package/apps/web/dist/assets/ProjectPage-voR0hvzy.js +0 -4
  83. package/apps/web/dist/assets/PublicRunner-CYZE_hSi.js +0 -1
  84. package/apps/web/dist/assets/RunnerView-D_C7hn81.js +0 -70
  85. package/apps/web/dist/assets/SettingsPage-DguoPF_3.js +0 -1
  86. package/apps/web/dist/assets/SharePage-Cf3i7KB-.js +0 -1
  87. package/apps/web/dist/assets/changelog-kz0DmHY4.js +0 -1
  88. package/apps/web/dist/assets/index-BPpKz65x.css +0 -1
  89. package/apps/web/dist/assets/index-D5w3fW1p.js +0 -10
  90. package/apps/web/dist/assets/ui-BHXO_e0e.js +0 -1
@@ -5,7 +5,7 @@ import { searchEntries } from "@engenty-wizards/shared/marketplace-search";
5
5
  import { and, eq, inArray, notInArray } from "drizzle-orm";
6
6
  import { formulaEstimate } from "../credits/estimate.js";
7
7
  import { control, controlDb, db, schema, withTenant } from "../db/client.js";
8
- import { missingCapabilities, optionalCapabilities } from "../engine/requirements.js";
8
+ import { missingCapabilities, optionalCapabilities, stepsWithoutModel, } from "../engine/requirements.js";
9
9
  import { env } from "../env.js";
10
10
  import { managed } from "../manage.js";
11
11
  import { classCatalog, imageCostUsd, tokenCostUsd, videoCostUsd, WEB_SEARCH_COST_USD, } from "../models.js";
@@ -212,7 +212,7 @@ function listPrices() {
212
212
  /** What a run costs: at the gateway's prices where there is one, else at list prices. */
213
213
  async function priced(definition) {
214
214
  const catalog = await classCatalog().catch(() => null);
215
- const price = formulaEstimate(definition, catalog ?? listPrices());
215
+ const price = formulaEstimate(definition, catalog ?? listPrices(), await stepsWithoutModel(definition));
216
216
  return { credits: Math.round(price.credits), high: price.high };
217
217
  }
218
218
  /** An entry in a language with its wizard read against this app; null where there is none. */
@@ -3,13 +3,15 @@ import { generateText } from "ai";
3
3
  import { and, asc, count, eq, max } from "drizzle-orm";
4
4
  import { db, schema } from "../db/client.js";
5
5
  import { documentMime, UnreadableDocument } from "../documents/parse.js";
6
- import { loadAsset, removeAsset, saveAsset } from "../files/storage.js";
7
- import { textModel } from "../models.js";
6
+ import { loadAsset, removeAsset, replaceAsset, saveAsset } from "../files/storage.js";
7
+ import { embeddingModel, textModel } from "../models.js";
8
8
  import { spaceFileChanged } from "../plugins/events.js";
9
9
  import { dropLinks, putLink } from "../tenants/control.js";
10
10
  import { requireWritableProject } from "./access.js";
11
11
  import { notFound, ServiceError } from "./errors.js";
12
- import { dropIndex, indexDocument } from "./project-index.js";
12
+ import { convertDocument, fillCategories } from "./knowledge-model.js";
13
+ import { dropIndex, keepText, queueIndex } from "./project-index.js";
14
+ import { setItemCategories } from "./space-categories.js";
13
15
  /** Reading a file takes seconds to a few minutes; a row still `pending` after this was cut off. */
14
16
  const STALE_MS = 15 * 60_000;
15
17
  const SEEN_BY_MODEL = ["image/png", "image/jpeg", "image/webp", "image/gif"];
@@ -177,7 +179,30 @@ async function describeDocument(row, text) {
177
179
  });
178
180
  return result.text.trim().slice(0, 600);
179
181
  }
180
- /** Reads a new file: a document goes into the index, and a file nobody described is described. */
182
+ /**
183
+ * What a document became gets its Kategorien from a model, where the space has some: the first
184
+ * page or table it was read into, else the file itself.
185
+ */
186
+ async function categorize(row, items, text) {
187
+ const first = items[0];
188
+ const ref = first?.startsWith("p:")
189
+ ? { pageId: first.slice(2) }
190
+ : first?.startsWith("t:")
191
+ ? { tableId: first.slice(2) }
192
+ : { fileId: row.id };
193
+ const changed = await fillCategories(row.projectId, ref, text || row.description, row.name).catch((err) => {
194
+ console.error("[project-file] Kategorien", row.name, err);
195
+ return false;
196
+ });
197
+ if (changed) {
198
+ queueIndex(first ? `${first[0] === "p" ? "P" : "t"}:${first.slice(2)}` : `f:${row.id}`);
199
+ }
200
+ }
201
+ /**
202
+ * Reads a new file. A document is read into Wissen — a page, a page with sub-pages, a table per
203
+ * sheet — and stays as the original behind it; one that reads into nothing stays a file, found
204
+ * by its name and description. A file nobody described is described.
205
+ */
181
206
  async function prepare(row) {
182
207
  await slot(async () => {
183
208
  const set = (values) => db
@@ -196,9 +221,18 @@ async function prepare(row) {
196
221
  spaceFileChanged("space.file.ready", row);
197
222
  return;
198
223
  }
199
- const { text, ...indexed } = await indexDocument(row, data);
224
+ const { text, items, ...read } = await convertDocument(row, data);
200
225
  const description = row.description || (text ? await describeDocument(row, text).catch(() => "") : "");
201
- await set({ ...indexed, status: "ready", error: null, description });
226
+ const embeddings = Boolean(await embeddingModel().catch(() => null));
227
+ await set({
228
+ ...read,
229
+ indexed: embeddings ? "embeddings" : "keywords",
230
+ status: "ready",
231
+ error: null,
232
+ description,
233
+ });
234
+ queueIndex(`f:${row.id}`);
235
+ await categorize({ ...row, description }, items, text);
202
236
  spaceFileChanged("space.file.ready", row);
203
237
  }
204
238
  catch (err) {
@@ -257,6 +291,9 @@ export async function orderProjectFiles(projectId, kind, ids) {
257
291
  }
258
292
  async function removeRow(row) {
259
293
  await dropIndex(row.id);
294
+ // What it was read into goes with it; what a person changed since stays.
295
+ const { dropConverted } = await import("./knowledge-model.js");
296
+ await dropConverted(row.id);
260
297
  await db.delete(schema.projectFile).where(eq(schema.projectFile.id, row.id));
261
298
  await removeAsset(row.id);
262
299
  if (row.kind === "logo") {
@@ -274,3 +311,74 @@ export async function removeProjectFiles(projectId) {
274
311
  await removeRow(row);
275
312
  }
276
313
  }
314
+ // --- what plugins keep as files ----------------------------------------------------
315
+ /**
316
+ * A plugin's file of Wissen (`server.spaceData.putFile`, or the original of a page it wrote):
317
+ * a document of the space under the plugin's key. The same key again replaces it. `text`: what
318
+ * a step reads of it; without one only its name and description are found.
319
+ */
320
+ export async function putOriginFile(origin, input) {
321
+ await requireWritableProject(input.space);
322
+ const key = input.key.trim().slice(0, 300);
323
+ const existing = await db.query.projectFile.findFirst({
324
+ where: and(eq(schema.projectFile.projectId, input.space), eq(schema.projectFile.origin, origin), eq(schema.projectFile.originKey, key)),
325
+ });
326
+ const mime = documentMime(input.name, input.mime) || "application/octet-stream";
327
+ if (!input.data.byteLength || input.data.byteLength > projectFileLimit("document", mime)) {
328
+ throw new ServiceError("invalid", `"${input.name}" is empty or larger than a document may be.`);
329
+ }
330
+ const name = input.name.slice(0, 120) || "datei";
331
+ const values = {
332
+ name,
333
+ mime,
334
+ size: input.data.byteLength,
335
+ description: input.description?.trim().slice(0, 600) ?? existing?.description ?? "",
336
+ originLabel: input.label?.trim().slice(0, 120) || null,
337
+ status: "ready",
338
+ error: null,
339
+ textHash: input.text ? await keepText(input.text) : null,
340
+ chars: input.text?.length ?? null,
341
+ updatedAt: new Date(),
342
+ };
343
+ let id = existing?.id;
344
+ if (existing) {
345
+ // New content under the id it has: pages that name it as their original keep it.
346
+ await replaceAsset(existing.id, { mime, name, data: input.data });
347
+ await db.update(schema.projectFile).set(values).where(eq(schema.projectFile.id, existing.id));
348
+ }
349
+ else {
350
+ const [{ n, last }] = await db
351
+ .select({ n: count(), last: max(schema.projectFile.position) })
352
+ .from(schema.projectFile)
353
+ .where(and(eq(schema.projectFile.projectId, input.space), eq(schema.projectFile.kind, "document")));
354
+ if (n >= PROJECT_LIMITS.files.document) {
355
+ throw new ServiceError("refused", `A space keeps at most ${PROJECT_LIMITS.files.document} documents.`);
356
+ }
357
+ const ref = await saveAsset({ kind: "project", mime, name, data: input.data });
358
+ id = ref.id;
359
+ await db.insert(schema.projectFile).values({
360
+ id: ref.id,
361
+ projectId: input.space,
362
+ kind: "document",
363
+ position: (last ?? -1) + 1,
364
+ origin,
365
+ originKey: key,
366
+ ...values,
367
+ });
368
+ }
369
+ if (input.categories) {
370
+ await setItemCategories(input.space, { fileId: id }, input.categories, "origin");
371
+ }
372
+ queueIndex(`f:${id}`);
373
+ return id;
374
+ }
375
+ /** Takes out a plugin's files, by key or all of them in the space; returns how many went. */
376
+ export async function removeOriginFiles(origin, projectId, key) {
377
+ const rows = await db.query.projectFile.findMany({
378
+ where: and(eq(schema.projectFile.projectId, projectId), eq(schema.projectFile.origin, origin), key === undefined ? undefined : eq(schema.projectFile.originKey, key)),
379
+ });
380
+ for (const row of rows) {
381
+ await removeRow(row);
382
+ }
383
+ return rows.length;
384
+ }