mindoodb-app-sdk 0.0.70 → 0.0.72
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 +106 -1
- package/dist/{chunk-P7SOHCEQ.js → chunk-UFP7O4OJ.js} +746 -36
- package/dist/index.d.ts +3 -55
- package/dist/index.js +61 -1
- package/dist/testing/index.d.ts +136 -2
- package/dist/testing/index.js +422 -18
- package/dist/{types-7oOzrSr5.d.ts → types-DN-E0X34.d.ts} +542 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -400,6 +400,42 @@ In tests, `host.setEmbedAgentTools(embedId, ["text_insert"])` acts as if the com
|
|
|
400
400
|
registered tools, and an app under test launched with `launchContext.embed` offers only
|
|
401
401
|
its document tools, as in Haven.
|
|
402
402
|
|
|
403
|
+
#### Agent profile: what agents learn before opening the app
|
|
404
|
+
|
|
405
|
+
Agents only see an app's tools while it runs. To pick the right app first, they call Haven's `haven_apps_describe`, which answers from the `agent` block of `haven-app.json`:
|
|
406
|
+
|
|
407
|
+
```json
|
|
408
|
+
"agent": {
|
|
409
|
+
"summary": { "en": "Mind maps whose nodes are also tasks; the same nodes as Kanban, Gantt and spreadsheet.", "de": "…" },
|
|
410
|
+
"capabilities": [
|
|
411
|
+
{ "id": "maps", "title": { "en": "Find, open and create maps", "de": "…" }, "tools": ["maps_list", "map_get", "map_create", "map_open"] },
|
|
412
|
+
{ "id": "nodes", "title": { "en": "Edit nodes and task fields", "de": "…" }, "tools": ["nodes_add", "nodes_update", "ops_guide"] }
|
|
413
|
+
],
|
|
414
|
+
"examples": { "en": ["Turn these meeting notes into a mind map"], "de": ["…"] },
|
|
415
|
+
"limits": { "en": ["Maps are trees: a node has one parent"], "de": ["…"] },
|
|
416
|
+
"guide": { "en": "agent/agent.en.md" }
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
- **`summary`**: neutral, 1-3 sentences, at most 400 characters per locale; `en` is required.
|
|
421
|
+
- **`capabilities`**: 1-8 entries; `tools` names the tools as in `registerTools` (no prefix, no `haven_*`). Together they should cover every tool.
|
|
422
|
+
- **`examples`**, **`limits`**: up to 8 strings per locale.
|
|
423
|
+
- **`guide`**: Markdown how-to per locale, a path relative to `haven-app.json` (at most 8 KB): typical steps, where ids come from, pitfalls. Parameter tables belong in the tools (or `ops_guide`), not here.
|
|
424
|
+
|
|
425
|
+
Keep the profile honest with a unit test: `checkAgentManifest` from `mindoodb-app-sdk/testing` compares it with the registered tools and fails when a capability or the guide names a tool that does not exist (`assertAgentManifest` throws instead):
|
|
426
|
+
|
|
427
|
+
```ts
|
|
428
|
+
import { assertAgentManifest } from "mindoodb-app-sdk/testing";
|
|
429
|
+
|
|
430
|
+
const tools = createMyAgentTools(deps);
|
|
431
|
+
const warnings = assertAgentManifest({
|
|
432
|
+
definition: JSON.parse(readFileSync("public/haven-app.json", "utf8")),
|
|
433
|
+
tools,
|
|
434
|
+
guideTexts: { "agent.en.md": readFileSync("public/agent/agent.en.md", "utf8") },
|
|
435
|
+
});
|
|
436
|
+
expect(warnings).toEqual([]); // every tool belongs to a capability
|
|
437
|
+
```
|
|
438
|
+
|
|
403
439
|
`session.agent` is absent on hosts without agent tools, so check for it. Test tools by calling `execute` directly in unit tests; the reference implementation is `src/features/agent/` in [mindoodb-app-vega](https://github.com/klehmann/mindoodb-app-vega). How to design tools that agents use well is in the [best practices guide](https://github.com/klehmann/MindooDB/blob/main/docs/best-practices.md) (section "Offer operations to AI agents").
|
|
404
440
|
|
|
405
441
|
### Host-owned drag
|
|
@@ -489,9 +525,12 @@ only database. The launch context then carries `embed` (`docId`, `databaseId`,
|
|
|
489
525
|
`intent`, `hostAppLabel`): open that document, hide "New"/"Open", and finish with
|
|
490
526
|
|
|
491
527
|
```ts
|
|
492
|
-
await session.embedding.complete({
|
|
528
|
+
await session.embedding.complete({ subject, summary, stats: { words } }); // or session.embedding.cancel()
|
|
493
529
|
```
|
|
494
530
|
|
|
531
|
+
`complete` takes plain JSON; `MindooDBAppEmbeddingResult` (`subject`, optional
|
|
532
|
+
`summary`, `thumbnail` as a small data URL, `stats`) is the shape hosts expect.
|
|
533
|
+
|
|
495
534
|
Haven writes every change back to the host's database as it happens and only lets the
|
|
496
535
|
component create documents that are children of the root.
|
|
497
536
|
|
|
@@ -592,6 +631,72 @@ never does is closed without asking; `embed.onDirtyChange` lets the host mark it
|
|
|
592
631
|
dot in its tab). `embed.save()` rejects with `unsupported` when the component has no save
|
|
593
632
|
handler.
|
|
594
633
|
|
|
634
|
+
**Checking before saving.** A component can tell hosts more about itself in
|
|
635
|
+
`supports`, and hosts filter on it:
|
|
636
|
+
|
|
637
|
+
```json
|
|
638
|
+
"supports": ["inspect:mindoo.inspect.document@1", "validate", "issues", "reveal"]
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
```ts
|
|
642
|
+
const [letterEditor] = await session.components.list({ requires: ["inspect:mindoo.inspect.document@1", "validate"] });
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
- `inspect:<contract>`: the component describes its document in a shared shape:
|
|
646
|
+
`mindoo.inspect.document@1` (Word/Markdown: subject, outline with anchors, open
|
|
647
|
+
placeholders and MERGEFIELDs, open comments and tracked changes, word count, text on
|
|
648
|
+
request), `mindoo.inspect.spreadsheet@1` (sheets, named ranges, requested cells,
|
|
649
|
+
formula errors with address), `mindoo.inspect.slides@1` (slide count, titles, empty
|
|
650
|
+
placeholders). Anchors: `{ kind: "heading", id }`, `{ kind: "cell", ref: "Sheet1!B3" }`,
|
|
651
|
+
`{ kind: "slide", index }`.
|
|
652
|
+
- `validate`: it asks before it saves, so the host can stop a save.
|
|
653
|
+
- `issues` / `reveal`: it shows a host's findings and scrolls to an anchor.
|
|
654
|
+
|
|
655
|
+
Changing `supports` does not ask users again; it grants no access.
|
|
656
|
+
|
|
657
|
+
```ts
|
|
658
|
+
// host
|
|
659
|
+
const letter = await embed.inspect<MindooDBAppDocumentInspection>(); // { outline, placeholders, … }
|
|
660
|
+
const rules = defineDocumentRules<MindooDBAppDocumentInspection>({
|
|
661
|
+
contract: MINDOODB_INSPECT_DOCUMENT,
|
|
662
|
+
rules: [mindooDBAppInspectRules.noOpenPlaceholders(), mindooDBAppInspectRules.noOpenTrackedChanges("warning")],
|
|
663
|
+
});
|
|
664
|
+
rules.attach(embed); // = embed.onBeforeSave(rules.beforeSave, { inspect: rules.request })
|
|
665
|
+
embed.onAfterSave(() => refreshTree());
|
|
666
|
+
await embed.showIssues(rules.checkRoot(doc.data)); // the root summary, see below
|
|
667
|
+
await embed.reveal({ kind: "heading", id: "h-3" });
|
|
668
|
+
await embed.callTool("text_insert", { text: "…" }); // any of its document agent tools
|
|
669
|
+
|
|
670
|
+
// component
|
|
671
|
+
session.embedding.provideInspection((request) => describeDocument(request));
|
|
672
|
+
session.embedding.onShowIssues((issues) => showIssuesPanel(issues));
|
|
673
|
+
session.embedding.onReveal((anchor) => scrollTo(anchor));
|
|
674
|
+
await session.embedding.save(async ({ inspection }) => {
|
|
675
|
+
await db.documents.update({ docId, set: { ...changes, ...(inspection ? { inspection } : {}) } });
|
|
676
|
+
}); // throws MindooDBAppEmbedValidationError (with .issues) when the host's check stopped it
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Haven never holds writes back: the component asks first (`embedding.validate`, which
|
|
680
|
+
`embedding.save` calls), Haven fetches the inspection the host asked for, passes it with
|
|
681
|
+
the root document to the host's `onBeforeSave` and answers the component: an `error`
|
|
682
|
+
stops the save, a `warning` asks the user whether to save anyway, and when the host does
|
|
683
|
+
not answer within about 5 s the component saves (`timedOut`). This covers saves the
|
|
684
|
+
user, the host (`embed.save()`) and agents start; an agent tool saves with
|
|
685
|
+
`save(flush, { interactive: false })`, where warnings do not stop it, and reports the
|
|
686
|
+
error's issues as its tool error. Standalone, `validate` answers `ok` at once.
|
|
687
|
+
|
|
688
|
+
`save` also hands `flush` a small summary of the inspection (at most 8 KiB, lists and
|
|
689
|
+
text shortened, counts exact) as an atomic value for the root's `inspection` field, so
|
|
690
|
+
hosts can check documents they do not have open: `rules.checkRoot(root)`, or
|
|
691
|
+
`readMindooDBAppInspectionSummary(root)`. Write it in standalone saves too.
|
|
692
|
+
|
|
693
|
+
In tests, the mock plays the components with `embedInspection`, `embedTools` and
|
|
694
|
+
`confirmSaveWarnings`, and records `getEmbedRequests(embedId)`; `validateEmbed(embedId)`
|
|
695
|
+
runs the host's check as if the component was about to save. For an app under test that
|
|
696
|
+
is a component, `embeddingValidation` plays the host, and `requestEmbeddingInspection`,
|
|
697
|
+
`requestEmbeddingShowIssues`, `requestEmbeddingReveal`, `getEmbeddingValidations` and
|
|
698
|
+
`getEmbeddingSaveCount` drive and observe it.
|
|
699
|
+
|
|
595
700
|
Havens that predate this lay the component over the container instead, above the host's
|
|
596
701
|
frame (`embed.placement === "overlay"`). The host then cannot draw on top of it: hide it
|
|
597
702
|
with `embed.setVisible(false)` while a menu or dialog of the host should be visible.
|