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.
@@ -1,10 +1,19 @@
1
1
  import {
2
2
  MINDOODB_APP_VALUE_TAG,
3
+ MindooDBAppEmbedValidationError,
3
4
  assertValidMindooDBCreateIds,
4
5
  mindooDBAppComponentFieldsMatch,
6
+ mindooDBAppComponentSupports,
7
+ normalizeMindooDBAppInspectAnchor,
8
+ normalizeMindooDBAppInspectRequest,
9
+ normalizeMindooDBAppInspection,
10
+ normalizeMindooDBAppIssues,
5
11
  pageUsers,
6
- releaseMindooDBAppBridgeSessions
7
- } from "../chunk-P7SOHCEQ.js";
12
+ performMindooDBAppEmbeddingSave,
13
+ releaseMindooDBAppBridgeSessions,
14
+ resolveMindooDBAppEmbedValidation,
15
+ validateMindooDBAppDefinition
16
+ } from "../chunk-UFP7O4OJ.js";
8
17
 
9
18
  // src/testing/index.ts
10
19
  import * as Automerge from "@automerge/automerge";
@@ -469,6 +478,13 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
469
478
  let nextSaveError = null;
470
479
  let embeddingDirty;
471
480
  let saveRequestHandler = null;
481
+ let inspectionProvider = null;
482
+ let showIssuesHandler = null;
483
+ let revealHandler = null;
484
+ const embeddingValidations = [];
485
+ let embeddingSaveCount = 0;
486
+ const beforeSaveHandlers = /* @__PURE__ */ new Map();
487
+ const savedListeners = /* @__PURE__ */ new Set();
472
488
  let embedCounter = 0;
473
489
  let embeddingFinish = null;
474
490
  const accessRequests = [];
@@ -529,7 +545,10 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
529
545
  rect: mockRect(input),
530
546
  visible: input.visible !== false,
531
547
  active: false,
532
- agentTools: null
548
+ agentTools: null,
549
+ supports: [...component.supports ?? []],
550
+ beforeSave: null,
551
+ requests: []
533
552
  });
534
553
  setActive(embedId);
535
554
  return embedId;
@@ -582,6 +601,7 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
582
601
  handles.get(embedId)?.settle(event);
583
602
  handles.delete(embedId);
584
603
  toolNames.delete(embedId);
604
+ beforeSaveHandlers.delete(embedId);
585
605
  closedListeners.forEach((listener) => listener(event));
586
606
  notifyChange();
587
607
  }
@@ -604,6 +624,40 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
604
624
  closed;
605
625
  dirty = void 0;
606
626
  dirtyListeners = /* @__PURE__ */ new Set();
627
+ savedListeners = /* @__PURE__ */ new Set();
628
+ get supports() {
629
+ return embeds.get(this.embedId)?.supports ?? [];
630
+ }
631
+ async inspect(request) {
632
+ return await inspectEmbed(this.embedId, request);
633
+ }
634
+ onBeforeSave(handler, options2) {
635
+ setBeforeSave(this.embedId, handler, options2?.inspect);
636
+ return () => {
637
+ if (beforeSaveHandlers.get(this.embedId) === handler) {
638
+ setBeforeSave(this.embedId, null);
639
+ }
640
+ };
641
+ }
642
+ onAfterSave(listener) {
643
+ this.savedListeners.add(listener);
644
+ return () => {
645
+ this.savedListeners.delete(listener);
646
+ };
647
+ }
648
+ notifySaved() {
649
+ const event = { embedId: this.embedId };
650
+ this.savedListeners.forEach((listener) => listener(event));
651
+ }
652
+ async showIssues(issues) {
653
+ await showEmbedIssues(this.embedId, issues);
654
+ }
655
+ async reveal(anchor) {
656
+ await revealInEmbed(this.embedId, anchor);
657
+ }
658
+ async callTool(name, input) {
659
+ return await callEmbedTool(this.embedId, name, input ?? {});
660
+ }
607
661
  onDirtyChange(listener) {
608
662
  this.dirtyListeners.add(listener);
609
663
  return () => {
@@ -703,7 +757,8 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
703
757
  notifyChange();
704
758
  }
705
759
  async function saveEmbed(embedId) {
706
- if (!embeds.has(embedId)) {
760
+ const entry = embeds.get(embedId);
761
+ if (!entry) {
707
762
  throw new Error("Unknown embed.");
708
763
  }
709
764
  const error = nextSaveError;
@@ -711,7 +766,117 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
711
766
  if (error) {
712
767
  throw new Error(error);
713
768
  }
769
+ if (mindooDBAppComponentSupports(entry.supports, "validate")) {
770
+ const validation = await validateEmbed(embedId);
771
+ if (!validation.ok) {
772
+ throw new MindooDBAppEmbedValidationError(validation.issues);
773
+ }
774
+ }
714
775
  setEmbedDirty(embedId, false);
776
+ notifyEmbedSaved(embedId);
777
+ }
778
+ function entryOf(embedId) {
779
+ const entry = embeds.get(embedId);
780
+ if (!entry) {
781
+ throw new Error("Unknown embed.");
782
+ }
783
+ return entry;
784
+ }
785
+ function unsupported(message) {
786
+ return Object.assign(new Error(message), { name: "unsupported" });
787
+ }
788
+ async function inspectEmbed(embedId, request) {
789
+ const entry = entryOf(embedId);
790
+ const inspect = normalizeMindooDBAppInspectRequest(request);
791
+ entry.requests.push({ request: "inspect", inspect });
792
+ if (!options.embedInspection || !mindooDBAppComponentSupports(entry.supports, "inspect")) {
793
+ throw unsupported("The component cannot describe its document.");
794
+ }
795
+ return normalizeMindooDBAppInspection(await options.embedInspection(structuredClone(entry), inspect));
796
+ }
797
+ function setBeforeSave(embedId, handler, inspect) {
798
+ const entry = entryOf(embedId);
799
+ if (handler) {
800
+ beforeSaveHandlers.set(embedId, handler);
801
+ entry.beforeSave = { inspect: normalizeMindooDBAppInspectRequest(inspect) };
802
+ } else {
803
+ beforeSaveHandlers.delete(embedId);
804
+ entry.beforeSave = null;
805
+ }
806
+ notifyChange();
807
+ }
808
+ async function validateEmbed(embedId, validateOptions = {}) {
809
+ const entry = entryOf(embedId);
810
+ const handler = beforeSaveHandlers.get(embedId);
811
+ if (!handler) {
812
+ return { ok: true, issues: [] };
813
+ }
814
+ let inspection = null;
815
+ if (options.embedInspection && mindooDBAppComponentSupports(entry.supports, "inspect")) {
816
+ inspection = normalizeMindooDBAppInspection(
817
+ await options.embedInspection(structuredClone(entry), entry.beforeSave?.inspect ?? {})
818
+ );
819
+ }
820
+ const root = await getDatabase(entry.databaseId).documents.get(entry.docId);
821
+ const answer = await handler({
822
+ embedId,
823
+ inspection,
824
+ root: root ? JSON.parse(JSON.stringify(root.data)) : null
825
+ });
826
+ return await resolveMindooDBAppEmbedValidation(
827
+ normalizeMindooDBAppIssues(answer?.issues),
828
+ validateOptions.interactive !== false,
829
+ options.confirmSaveWarnings ?? (() => true)
830
+ );
831
+ }
832
+ function notifyEmbedSaved(embedId) {
833
+ if (!embeds.has(embedId)) {
834
+ return;
835
+ }
836
+ handles.get(embedId)?.notifySaved();
837
+ savedListeners.forEach((listener) => listener({ embedId }));
838
+ }
839
+ async function showEmbedIssues(embedId, issues) {
840
+ const entry = entryOf(embedId);
841
+ entry.requests.push({ request: "showIssues", issues: normalizeMindooDBAppIssues(issues) });
842
+ if (!mindooDBAppComponentSupports(entry.supports, "issues")) {
843
+ throw unsupported("The component cannot show issues.");
844
+ }
845
+ }
846
+ async function revealInEmbed(embedId, anchor) {
847
+ const entry = entryOf(embedId);
848
+ const normalized = normalizeMindooDBAppInspectAnchor(anchor);
849
+ if (!normalized) {
850
+ throw new Error("Invalid anchor.");
851
+ }
852
+ entry.requests.push({ request: "reveal", anchor: normalized });
853
+ if (!mindooDBAppComponentSupports(entry.supports, "reveal")) {
854
+ throw unsupported("The component cannot reveal places.");
855
+ }
856
+ }
857
+ async function callEmbedTool(embedId, name, input) {
858
+ const entry = entryOf(embedId);
859
+ const prefix = `${toolPrefix(entry.component)}_`;
860
+ const bare = name.startsWith(prefix) ? name.slice(prefix.length) : name;
861
+ entry.requests.push({ request: "callTool", name: bare, input: structuredClone(input) });
862
+ if (!options.embedTools) {
863
+ throw unsupported(`The component has no tool "${bare}".`);
864
+ }
865
+ return structuredClone(await options.embedTools(structuredClone(entry), bare, structuredClone(input)));
866
+ }
867
+ async function validateEmbedding(validateOptions = {}) {
868
+ const interactive = validateOptions.interactive !== false;
869
+ const raw = await options.embeddingValidation?.({ interactive }) ?? { ok: true, issues: [] };
870
+ const result = {
871
+ ok: raw.ok !== false,
872
+ issues: normalizeMindooDBAppIssues(raw.issues),
873
+ ...raw.timedOut ? { timedOut: true } : {}
874
+ };
875
+ embeddingValidations.push({ interactive, result: structuredClone(result) });
876
+ return result;
877
+ }
878
+ function unsupportedHandler() {
879
+ throw unsupported("unsupported");
715
880
  }
716
881
  function setVisible(embedId, visible) {
717
882
  const entry = embeds.get(embedId);
@@ -723,7 +888,7 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
723
888
  return {
724
889
  components: {
725
890
  async list(query) {
726
- return components.filter((entry) => !query?.intent || entry.intents.includes(query.intent)).filter((entry) => !query?.document || mindooDBAppComponentFieldsMatch(entry.match, query.document)).map((entry) => structuredClone(entry));
891
+ return components.filter((entry) => !query?.intent || entry.intents.includes(query.intent)).filter((entry) => (query?.requires ?? []).every((requirement) => mindooDBAppComponentSupports(entry.supports, requirement))).filter((entry) => !query?.document || mindooDBAppComponentFieldsMatch(entry.match, query.document)).map((entry) => structuredClone(entry));
727
892
  }
728
893
  },
729
894
  embeds: {
@@ -758,6 +923,36 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
758
923
  saveRequestHandler = null;
759
924
  }
760
925
  };
926
+ },
927
+ provideInspection(provider) {
928
+ inspectionProvider = provider;
929
+ return () => {
930
+ if (inspectionProvider === provider) inspectionProvider = null;
931
+ };
932
+ },
933
+ onShowIssues(handler) {
934
+ showIssuesHandler = handler;
935
+ return () => {
936
+ if (showIssuesHandler === handler) showIssuesHandler = null;
937
+ };
938
+ },
939
+ onReveal(handler) {
940
+ revealHandler = handler;
941
+ return () => {
942
+ if (revealHandler === handler) revealHandler = null;
943
+ };
944
+ },
945
+ validate: validateEmbedding,
946
+ async save(flush, saveOptions) {
947
+ return await performMindooDBAppEmbeddingSave({
948
+ validate: () => validateEmbedding(saveOptions),
949
+ provider: inspectionProvider,
950
+ showIssues: showIssuesHandler,
951
+ flush,
952
+ saved: () => {
953
+ embeddingSaveCount += 1;
954
+ }
955
+ });
761
956
  }
762
957
  },
763
958
  openEmbed,
@@ -821,6 +1016,44 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
821
1016
  },
822
1017
  setSaveRequestHandler(handler) {
823
1018
  saveRequestHandler = handler;
1019
+ },
1020
+ inspectEmbed,
1021
+ setBeforeSave,
1022
+ validateEmbed,
1023
+ notifyEmbedSaved,
1024
+ onSaved(listener) {
1025
+ savedListeners.add(listener);
1026
+ return () => {
1027
+ savedListeners.delete(listener);
1028
+ };
1029
+ },
1030
+ showEmbedIssues,
1031
+ revealInEmbed,
1032
+ callEmbedTool,
1033
+ getEmbedRequests(embedId) {
1034
+ return structuredClone(embeds.get(embedId)?.requests ?? []);
1035
+ },
1036
+ async requestEmbeddingInspection(request) {
1037
+ if (!inspectionProvider) unsupportedHandler();
1038
+ return normalizeMindooDBAppInspection(await inspectionProvider(normalizeMindooDBAppInspectRequest(request)));
1039
+ },
1040
+ async requestEmbeddingShowIssues(issues) {
1041
+ if (!showIssuesHandler) unsupportedHandler();
1042
+ await showIssuesHandler(normalizeMindooDBAppIssues(issues));
1043
+ },
1044
+ async requestEmbeddingReveal(anchor) {
1045
+ if (!revealHandler) unsupportedHandler();
1046
+ await revealHandler(anchor);
1047
+ },
1048
+ getEmbeddingValidations() {
1049
+ return structuredClone(embeddingValidations);
1050
+ },
1051
+ getEmbeddingSaveCount() {
1052
+ return embeddingSaveCount;
1053
+ },
1054
+ validateEmbedding,
1055
+ recordEmbeddingSaved() {
1056
+ embeddingSaveCount += 1;
824
1057
  }
825
1058
  };
826
1059
  }
@@ -2383,6 +2616,84 @@ Allow?`),
2383
2616
  return testHost;
2384
2617
  }
2385
2618
 
2619
+ // src/testing/agentManifest.ts
2620
+ function localeKeys(map) {
2621
+ return map ? Object.keys(map).sort().join(",") : "";
2622
+ }
2623
+ function findGuideProblems(name, text, prefix, registered, ignore) {
2624
+ const problems = /* @__PURE__ */ new Set();
2625
+ const prefixed = new RegExp(`(?<![A-Za-z0-9_])${prefix}_([a-z0-9_]+)(?![A-Za-z0-9_*<])`, "g");
2626
+ for (const match of text.matchAll(prefixed)) {
2627
+ const full = match[0];
2628
+ const bare = match[1].replace(/_+$/, "");
2629
+ if (!bare || ignore.has(full) || ignore.has(bare) || registered.has(bare)) continue;
2630
+ problems.add(`${name} names \`${full}\`, which the app does not register.`);
2631
+ }
2632
+ const families = new Set([...registered].filter((tool) => tool.includes("_")).map((tool) => tool.split("_")[0]));
2633
+ for (const match of text.matchAll(/`([a-z][a-z0-9]*_[a-z0-9_]*[a-z0-9])(?:\(\))?`/g)) {
2634
+ const bare = match[1];
2635
+ if (bare.startsWith("haven_") || bare.startsWith(`${prefix}_`)) continue;
2636
+ if (registered.has(bare) || ignore.has(bare) || !families.has(bare.split("_")[0])) continue;
2637
+ problems.add(`${name} names \`${bare}\`, which looks like a tool but the app does not register it.`);
2638
+ }
2639
+ return [...problems];
2640
+ }
2641
+ function checkAgentManifest(options) {
2642
+ const errors = [];
2643
+ const warnings = [];
2644
+ const validation = validateMindooDBAppDefinition(options.definition);
2645
+ errors.push(...validation.errors);
2646
+ const definition = validation.definition;
2647
+ if (!definition) {
2648
+ return { errors, warnings };
2649
+ }
2650
+ const agent = definition.agent;
2651
+ if (!agent) {
2652
+ errors.push("haven-app.json has no agent block.");
2653
+ return { errors, warnings };
2654
+ }
2655
+ const prefix = options.toolPrefix ?? mockAgentToolPrefix(definition.appId, definition.agentToolPrefix);
2656
+ const registered = new Set(options.tools.map((tool) => typeof tool === "string" ? tool : tool.name));
2657
+ const ignore = new Set(options.ignore ?? []);
2658
+ const covered = /* @__PURE__ */ new Set();
2659
+ for (const capability of agent.capabilities) {
2660
+ for (const tool of capability.tools) {
2661
+ covered.add(tool);
2662
+ if (!registered.has(tool)) {
2663
+ const hint = tool.startsWith(`${prefix}_`) ? " Name it without the prefix." : "";
2664
+ errors.push(`Capability "${capability.id}" names the tool "${tool}", which the app does not register.${hint}`);
2665
+ }
2666
+ }
2667
+ }
2668
+ const internal = new Set(options.internalTools ?? []);
2669
+ for (const tool of registered) {
2670
+ if (!covered.has(tool) && !internal.has(tool)) {
2671
+ warnings.push(`The tool "${tool}" belongs to no capability.`);
2672
+ }
2673
+ }
2674
+ const summaryLocales = localeKeys(agent.summary);
2675
+ const mismatched = [
2676
+ ...agent.capabilities.map((capability) => [`capability "${capability.id}" title`, localeKeys(capability.title)]),
2677
+ ...agent.examples ? [["examples", localeKeys(agent.examples)]] : []
2678
+ ].filter(([, locales]) => locales !== summaryLocales);
2679
+ for (const [what, locales] of mismatched) {
2680
+ errors.push(`The agent ${what} has the locales ${locales || "(none)"}, the summary ${summaryLocales}.`);
2681
+ }
2682
+ const texts = Array.isArray(options.guideTexts) ? options.guideTexts.map((text, index) => [`guide text #${index}`, text]) : Object.entries(options.guideTexts ?? {});
2683
+ for (const [name, text] of texts) {
2684
+ errors.push(...findGuideProblems(name, text, prefix, registered, ignore));
2685
+ }
2686
+ return { errors, warnings };
2687
+ }
2688
+ function assertAgentManifest(options) {
2689
+ const { errors, warnings } = checkAgentManifest(options);
2690
+ if (errors.length) {
2691
+ throw new Error(`The agent profile does not match the app's tools:
2692
+ - ${errors.join("\n- ")}`);
2693
+ }
2694
+ return warnings;
2695
+ }
2696
+
2386
2697
  // src/testing/index.ts
2387
2698
  var PROTOCOL = "mindoodb-app-bridge";
2388
2699
  var MOCK_SIGNING_PUBLIC_KEY_PEM = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAmockmockmockmockmockmockmockmockmockmockmoc=\n-----END PUBLIC KEY-----\n";
@@ -5951,7 +6262,15 @@ function createMockMindooDBAppSession(options = {}) {
5951
6262
  setEmbedAgentTools: (embedId, names, toolOptions) => state.embedHost.setEmbedAgentTools(embedId, names, toolOptions),
5952
6263
  failNextEmbedSave: (message) => state.embedHost.failNextSave(message),
5953
6264
  getEmbeddingDirty: () => state.embedHost.getEmbeddingDirty(),
5954
- requestEmbeddingSave: () => state.embedHost.requestEmbeddingSave()
6265
+ requestEmbeddingSave: () => state.embedHost.requestEmbeddingSave(),
6266
+ validateEmbed: (embedId, validateOptions) => state.embedHost.validateEmbed(embedId, validateOptions),
6267
+ notifyEmbedSaved: (embedId) => state.embedHost.notifyEmbedSaved(embedId),
6268
+ getEmbedRequests: (embedId) => state.embedHost.getEmbedRequests(embedId),
6269
+ requestEmbeddingInspection: (request) => state.embedHost.requestEmbeddingInspection(request),
6270
+ requestEmbeddingShowIssues: (issues) => state.embedHost.requestEmbeddingShowIssues(issues),
6271
+ requestEmbeddingReveal: (anchor) => state.embedHost.requestEmbeddingReveal(anchor),
6272
+ getEmbeddingValidations: () => state.embedHost.getEmbeddingValidations(),
6273
+ getEmbeddingSaveCount: () => state.embedHost.getEmbeddingSaveCount()
5955
6274
  };
5956
6275
  replicaStates.set(controller, state);
5957
6276
  return controller;
@@ -5997,8 +6316,25 @@ function createFakeBridgeHost(options = {}) {
5997
6316
  (port) => port.postMessage({ protocol: PROTOCOL, kind: "embed-event", event: { type: "agentTools", ...event } })
5998
6317
  );
5999
6318
  });
6319
+ state.embedHost.onSaved((event) => {
6320
+ connectedPorts.forEach(
6321
+ (port) => port.postMessage({ protocol: PROTOCOL, kind: "embed-event", event: { type: "saved", ...event } })
6322
+ );
6323
+ });
6000
6324
  const embeddingRequests = /* @__PURE__ */ new Map();
6001
6325
  let embeddingRequestCounter = 0;
6326
+ function pushEmbeddingRequest(request, params) {
6327
+ embeddingRequestCounter += 1;
6328
+ const requestId = `embedding-request-${embeddingRequestCounter}`;
6329
+ return new Promise((resolve, reject) => {
6330
+ embeddingRequests.set(requestId, { resolve, reject });
6331
+ connectedPorts.forEach(
6332
+ (port) => port.postMessage({ protocol: PROTOCOL, kind: "embedding-request", requestId, request, ...params ? { params } : {} })
6333
+ );
6334
+ });
6335
+ }
6336
+ const embedRequests = /* @__PURE__ */ new Map();
6337
+ let embedRequestCounter = 0;
6002
6338
  const beforeCloseWaiters = /* @__PURE__ */ new Map();
6003
6339
  let beforeCloseCounter = 0;
6004
6340
  const viewSessions = /* @__PURE__ */ new Map();
@@ -6235,8 +6571,66 @@ function createFakeBridgeHost(options = {}) {
6235
6571
  case "embeds.open": {
6236
6572
  const input = params.input;
6237
6573
  const embedId = await state.embedHost.openEmbed(input);
6238
- return input.placement === "frame" && options.embedFrameUrl ? { embedId, frame: { url: options.embedFrameUrl } } : { embedId };
6574
+ const supports = state.embedHost.listEmbeds().find((entry) => entry.embedId === embedId)?.supports ?? [];
6575
+ return {
6576
+ embedId,
6577
+ ...input.placement === "frame" && options.embedFrameUrl ? { frame: { url: options.embedFrameUrl } } : {},
6578
+ ...supports.length ? { supports } : {}
6579
+ };
6580
+ }
6581
+ case "embeds.inspect":
6582
+ return await state.embedHost.inspectEmbed(
6583
+ String(params.embedId),
6584
+ params.request
6585
+ );
6586
+ case "embeds.setBeforeSave": {
6587
+ const embedId = String(params.embedId);
6588
+ state.embedHost.setBeforeSave(
6589
+ embedId,
6590
+ params.enabled === true ? (input) => {
6591
+ embedRequestCounter += 1;
6592
+ const requestId = `embed-request-${embedRequestCounter}`;
6593
+ return new Promise((resolve) => {
6594
+ embedRequests.set(requestId, (result) => resolve(result));
6595
+ connectedPorts.forEach(
6596
+ (port) => port.postMessage({
6597
+ protocol: PROTOCOL,
6598
+ kind: "embed-request",
6599
+ requestId,
6600
+ embedId,
6601
+ request: "beforeSave",
6602
+ params: { inspection: input.inspection, root: input.root }
6603
+ })
6604
+ );
6605
+ });
6606
+ } : null,
6607
+ params.inspect
6608
+ );
6609
+ return { ok: true };
6239
6610
  }
6611
+ case "embeds.respond": {
6612
+ const resolve = embedRequests.get(String(params.requestId));
6613
+ embedRequests.delete(String(params.requestId));
6614
+ resolve?.(params.ok === true ? params.result : { issues: [] });
6615
+ return { ok: true };
6616
+ }
6617
+ case "embeds.showIssues":
6618
+ await state.embedHost.showEmbedIssues(String(params.embedId), params.issues);
6619
+ return { ok: true };
6620
+ case "embeds.reveal":
6621
+ await state.embedHost.revealInEmbed(String(params.embedId), params.anchor);
6622
+ return { ok: true };
6623
+ case "embeds.callTool":
6624
+ return await state.embedHost.callEmbedTool(
6625
+ String(params.embedId),
6626
+ String(params.name),
6627
+ params.input ?? {}
6628
+ );
6629
+ case "embedding.validate":
6630
+ return await state.embedHost.validateEmbedding({ interactive: params.interactive !== false });
6631
+ case "embedding.saved":
6632
+ state.embedHost.recordEmbeddingSaved();
6633
+ return { ok: true };
6240
6634
  case "embeds.requestAccess":
6241
6635
  return await state.embedHost.embeds.requestAccess(
6242
6636
  params.input ?? { components: [] }
@@ -6269,9 +6663,10 @@ function createFakeBridgeHost(options = {}) {
6269
6663
  const pending = embeddingRequests.get(String(params.requestId));
6270
6664
  embeddingRequests.delete(String(params.requestId));
6271
6665
  if (params.ok === true) {
6272
- pending?.resolve();
6666
+ pending?.resolve(params.result);
6273
6667
  } else {
6274
- pending?.reject(new Error(typeof params.error === "string" ? params.error : "Save failed."));
6668
+ const message = typeof params.error === "string" ? params.error : "Save failed.";
6669
+ pending?.reject(Object.assign(new Error(message), message === "unsupported" ? { name: "unsupported" } : {}));
6275
6670
  }
6276
6671
  return { ok: true };
6277
6672
  }
@@ -6909,16 +7304,23 @@ function createFakeBridgeHost(options = {}) {
6909
7304
  setEmbedAgentTools: (embedId, names, toolOptions) => state.embedHost.setEmbedAgentTools(embedId, names, toolOptions),
6910
7305
  failNextEmbedSave: (message) => state.embedHost.failNextSave(message),
6911
7306
  getEmbeddingDirty: () => state.embedHost.getEmbeddingDirty(),
6912
- requestEmbeddingSave() {
6913
- embeddingRequestCounter += 1;
6914
- const requestId = `embedding-request-${embeddingRequestCounter}`;
6915
- return new Promise((resolve, reject) => {
6916
- embeddingRequests.set(requestId, { resolve, reject });
6917
- connectedPorts.forEach(
6918
- (port) => port.postMessage({ protocol: PROTOCOL, kind: "embedding-request", requestId, request: "save" })
6919
- );
6920
- });
7307
+ async requestEmbeddingSave() {
7308
+ await pushEmbeddingRequest("save");
7309
+ },
7310
+ validateEmbed: (embedId, validateOptions) => state.embedHost.validateEmbed(embedId, validateOptions),
7311
+ notifyEmbedSaved: (embedId) => state.embedHost.notifyEmbedSaved(embedId),
7312
+ getEmbedRequests: (embedId) => state.embedHost.getEmbedRequests(embedId),
7313
+ async requestEmbeddingInspection(request) {
7314
+ return await pushEmbeddingRequest("inspect", { request: request ?? {} });
7315
+ },
7316
+ async requestEmbeddingShowIssues(issues) {
7317
+ await pushEmbeddingRequest("showIssues", { issues });
7318
+ },
7319
+ async requestEmbeddingReveal(anchor) {
7320
+ await pushEmbeddingRequest("reveal", { anchor });
6921
7321
  },
7322
+ getEmbeddingValidations: () => state.embedHost.getEmbeddingValidations(),
7323
+ getEmbeddingSaveCount: () => state.embedHost.getEmbeddingSaveCount(),
6922
7324
  dispose() {
6923
7325
  restoreWindow();
6924
7326
  connectedPorts.forEach((port) => {
@@ -7040,7 +7442,9 @@ export {
7040
7442
  DEFAULT_TEST_HOST_USERS,
7041
7443
  MockForbiddenError,
7042
7444
  TEST_HOST_LOCALES,
7445
+ assertAgentManifest,
7043
7446
  capabilitiesForDefinitionPermissions,
7447
+ checkAgentManifest,
7044
7448
  createBrowserTestHost,
7045
7449
  createEvaluatingViewNavigator,
7046
7450
  createFakeBridgeHost,