mindoodb-app-sdk 0.0.63 → 0.0.65

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/TESTING.md CHANGED
@@ -108,6 +108,24 @@ Each database entry can provide:
108
108
  - `methods.attachments`
109
109
  - `fulltextSetup` — the initial config returned by `db.getFulltextSetup()`; `db.setFulltextSetup()` overwrites it for the lifetime of the handle. Use this to test your app's full-text bootstrap logic. Note the mock evaluates `text` query clauses regardless of this config.
110
110
  - `summarySetup` — the initial config returned by `db.getSummarySetup()`; `db.setSummarySetup()` overwrites it for the lifetime of the handle. The mock's `query()` reads seeded documents directly and ignores this config; use it to test your app's summary bootstrap logic.
111
+ - `automerge: true` — back every document with a real Automerge document, as Haven does (off by default: plain JSON with `mock-head-N` heads). `create`/`update` then return real Automerge heads, `update` applies `set`/`unset`, `json` (with `Automerge.changeAt(json.baseHeads)` when given) and `text` patches as Automerge changes with Haven's rules (missing parents and lists are created, `unset` is idempotent, `counterIncrement` needs a counter, an empty `json` patch is rejected), and `get`/`list`/`query` return the plain projection (atomic strings as strings, counters as numbers, timestamps as ISO strings). `richText` snapshots replace the value at their path and `richTextSteps` are spliced into the text without marks. Seeds are built with a fixed actor, so two mocks from the same seed have identical heads. `mockDatabasesFromDefinition(definition, seed, { automerge: true })` and the test host URL setting `automerge=1` turn it on, too.
112
+
113
+ #### Concurrent edits from another device
114
+
115
+ `applyRemoteUpdate(databaseId, docId, input, { actor? })` on the controller (`createMockMindooDBAppSession`, `createFakeBridgeHost`, the browser test host and `window.__havenTestHost`) writes `input` as another device and syncs it in; live queries update as after any write. With `automerge: true` the device holds the history up to `input.json.baseHeads` (plus its own earlier changes) and writes as its own Automerge actor, so its edit truly merges with an app save at the same heads:
116
+
117
+ ```ts
118
+ const doc = await database.documents.get("sheet-1"); // heads H
119
+ await mock.applyRemoteUpdate("main", "sheet-1", { // device B, at H
120
+ json: { baseHeads: doc!.heads, listInsert: [{ path: ["rows"], index: 1, values: ["remote"] }] },
121
+ });
122
+ const saved = await database.documents.update("sheet-1", { // the app, also at H
123
+ json: { baseHeads: doc!.heads, listInsert: [{ path: ["rows"], index: 1, values: ["local"] }] },
124
+ });
125
+ // saved.data.rows keeps both entries; saved.heads has two heads
126
+ ```
127
+
128
+ The relative order of concurrent inserts at the same index follows Automerge's op ids, as in Haven. Without `automerge`, `applyRemoteUpdate` is a plain update.
111
129
 
112
130
  ### Evaluating VirtualViews
113
131
 
@@ -344,6 +362,7 @@ The page shows the app next to a control panel:
344
362
  - **Databases**: one checkbox per capability for every mapped database, plus **Enforce capabilities**. Changing a capability relaunches the app, as Haven does after a permission change. With enforcement on, the mock rejects every call the database was not granted with a `forbidden` error (and `documents.canCreate()` and friends answer `allowed: false`), so you can check the app's hints for missing rights.
345
363
  - **Directory**: fills the tenant directory with 0 to 500 generated users (`CN=Test User 001/O=Test`, …) for recipient pickers and paging.
346
364
  - **Scanner**: what `attachments.scan()` returns — cancel, a generated sample page, or a file you choose. The file is written to the document's attachments like Haven's scanner does, so the app can read it back.
365
+ - **Agent tools**: the tools the app declared with `session.agent.registerTools()` (with the prefix agents see, `read-only` and `asks first` tags, description and input schema), a form to call one with a JSON input as an agent would, and the result as the agent gets it (images in the result are shown). Tools marked `consequentialHint` go through a confirm, like Haven's consent dialog. A checkbox switches agent access off. **Agent files** imports files for the app (each gets a `fileRef` for `takeFile`) and lists the files the app handed over with `provideFile` for download. **Agent context** shows what the app last passed to `setContext`.
347
366
  - A live log of notifications, attachment previews, scans and every RPC request. Click a request for its parameters, its result or error, and how long it took; binary values show as size plus a hex preview.
348
367
 
349
368
  `mockDatabasesFromDefinition` gives every database an in-memory attachment store (`attachments: "none"` restores the stateless default) and takes overrides for testing other mappings than the definition requests:
@@ -363,7 +382,7 @@ mountHavenTestHost({
363
382
  });
364
383
  ```
365
384
 
366
- The panel keeps its settings in the page URL, so a scenario can be linked or opened by Playwright directly: `/__haven-test/?db=main:read,attachments&db=archive:none&enforce=1&users=120&locale=de-DE&theme=dark` (`db=<id>:none` unmaps a database; URL settings win over the options). The same controls are scriptable as `window.__havenTestHost`:
385
+ The panel keeps its settings in the page URL, so a scenario can be linked or opened by Playwright directly: `/__haven-test/?db=main:read,attachments&db=archive:none&enforce=1&users=120&locale=de-DE&theme=dark` (`db=<id>:none` unmaps a database; `automerge=1` backs all databases with Automerge documents; URL settings win over the options). The same controls are scriptable as `window.__havenTestHost`:
367
386
 
368
387
  ```ts
369
388
  await page.goto("/__haven-test/?enforce=1");
@@ -375,8 +394,26 @@ await page.evaluate(() => window.__havenTestHost!.setLocale("de-DE"));
375
394
  await page.evaluate(() => window.__havenTestHost!.setNextScan({ fileName: "receipt.pdf", mimeType: "application/pdf", size: 1024 }));
376
395
  await app.getByRole("button", { name: "Scan" }).click();
377
396
  expect(await page.evaluate(() => window.__havenTestHost!.log.scans)).toHaveLength(1);
397
+
398
+ // with ?automerge=1: another device edits the document the app has open
399
+ await page.evaluate(() => window.__havenTestHost!.applyRemoteUpdate("main", "sheet-1", { set: { title: "Renamed elsewhere" } }));
378
400
  ```
379
401
 
402
+ Agent tools are scriptable through `window.__havenTestHost.agent`, the same controller the Vitest helpers expose as `createFakeBridgeHost().agent`:
403
+
404
+ ```ts
405
+ const agent = () => window.__havenTestHost!.agent;
406
+ const fileRef = await page.evaluate(() =>
407
+ agent().importFile({ name: "logo.png", mimeType: "image/png", data: new Uint8Array([137, 80, 78, 71]) }),
408
+ );
409
+ const added = await page.evaluate((ref) => agent().call("image_add", { fileRef: ref }), fileRef);
410
+ expect(added).toMatchObject({ ok: true });
411
+ const exported = await page.evaluate(() => agent().call("deck_export", { format: "pptx" }));
412
+ const file = await page.evaluate((ref) => agent().getFile(ref)?.name, (exported as any).result.files[0].fileRef);
413
+ ```
414
+
415
+ `call()` takes the tool's own name or the prefixed one and never throws: failures come back as `{ ok: false, error: { code, message, requiredAction } }`, the codes an agent sees. The mock follows Haven: tool declarations are validated (name, at most 64 tools, 2000-character descriptions, an object `inputSchema`), the prefix is the definition's `agentToolPrefix` (pass it as the `agentToolPrefix` option) or derived from the app id, an app can only `takeFile()` what was imported for it, and file refs expire after ten minutes. `setConsent("allow" | "deny" | fn)` answers the consent step in scripts, `setEnabled(false)` switches access off, and `calls()` lists every call with its outcome.
416
+
380
417
  `setNextScan()` decides only the next scan (pass `bytes` to attach real content); `setScanMode()` decides the ones after it. `setDirectoryUsers()` and `setEnforceCapabilities()` apply to the next call.
381
418
 
382
419
  The Level 1 and 2 helpers take the same options: `createMockMindooDBAppSession({ enforceCapabilities: true, directoryUsers: generateDirectoryUsers(120) })`, with `setCapabilities()`, `setEnforceCapabilities()` and `setDirectoryUsers()` on the controller, and `createMemoryAttachments()` for a database's `methods.attachments`. `createFakeBridgeHost({ onResponse })` reports every answer with its duration.
@@ -1,4 +1,4 @@
1
- import { ay as MindooDBAppComponentInfo, bq as MindooDBAppEmbedRect, aU as MindooDBAppCreateViewNavigatorInput, de as MindooDBAppViewNavigator, ad as MindooDBAppBridgeRpcRequest, bC as MindooDBAppHostTheme, av as MindooDBAppCapability, j as MindooDBAppDefinition, J as MindooDBAppAttachmentApi, e as MindooDBAppBridge, cQ as MindooDBAppSession, cg as MindooDBAppProposeAppInput, dm as MindooDBAppViewport, d8 as MindooDBAppUiPreferences, cm as MindooDBAppQueryResult, dl as MindooDBAppViewUpdateStats, a9 as MindooDBAppBridgePortMessage, aV as MindooDBAppDatabaseInfo, bl as MindooDBAppEmbedCloseReason, a4 as MindooDBAppBridgeErrorPayload, bX as MindooDBAppLaunchContext, b2 as MindooDBAppDocumentApi, dg as MindooDBAppViewNavigatorOpenOptions, bD as MindooDBAppIdentityApi, d4 as MindooDBAppTimestampApi, b0 as MindooDBAppDirectoryApi, l as MindooDBAppDocument, bz as MindooDBAppFulltextSetup, by as MindooDBAppExtractionSetup, cY as MindooDBAppSummarySetup, ch as MindooDBAppProposeAppResult, bN as MindooDBAppIncomingSource, c as MindooDBAppDragStartResult, bj as MindooDBAppDragProfile, bM as MindooDBAppIncomingResult } from '../types-BeRUxGKN.js';
1
+ import { ay as MindooDBAppComponentInfo, bq as MindooDBAppEmbedRect, I as MindooDBAppAgentToolDescriptor, f as MindooDBAppAgentToolErrorCode, V as MindooDBAppBridgeAgentResultMessage, U as MindooDBAppBridgeAgentInvokeMessage, aU as MindooDBAppCreateViewNavigatorInput, de as MindooDBAppViewNavigator, ad as MindooDBAppBridgeRpcRequest, bC as MindooDBAppHostTheme, av as MindooDBAppCapability, d9 as MindooDBAppUpdateDocumentInput, l as MindooDBAppDocument, j as MindooDBAppDefinition, J as MindooDBAppAttachmentApi, e as MindooDBAppBridge, cQ as MindooDBAppSession, cg as MindooDBAppProposeAppInput, dm as MindooDBAppViewport, d8 as MindooDBAppUiPreferences, cm as MindooDBAppQueryResult, dl as MindooDBAppViewUpdateStats, a9 as MindooDBAppBridgePortMessage, aV as MindooDBAppDatabaseInfo, bl as MindooDBAppEmbedCloseReason, a4 as MindooDBAppBridgeErrorPayload, bX as MindooDBAppLaunchContext, b2 as MindooDBAppDocumentApi, dg as MindooDBAppViewNavigatorOpenOptions, bD as MindooDBAppIdentityApi, d4 as MindooDBAppTimestampApi, b0 as MindooDBAppDirectoryApi, bz as MindooDBAppFulltextSetup, by as MindooDBAppExtractionSetup, cY as MindooDBAppSummarySetup, ch as MindooDBAppProposeAppResult, bN as MindooDBAppIncomingSource, c as MindooDBAppDragStartResult, bj as MindooDBAppDragProfile, bM as MindooDBAppIncomingResult } from '../types-BeRUxGKN.js';
2
2
  import * as mindoodb from 'mindoodb';
3
3
  import 'mindoodb-view-language';
4
4
 
@@ -21,6 +21,118 @@ interface MockEmbeddingFinish {
21
21
  message?: string;
22
22
  }
23
23
 
24
+ /**
25
+ * Haven's side of agent tools, for tests: what `session.agent` talks to.
26
+ *
27
+ * It accepts the app's tool declarations and context with Haven's validation, keeps
28
+ * the files the app hands over (`provideFile`), lets a test hand the app files the way
29
+ * Haven imports them from the exchange folder (`takeFile`), and calls the app's tools
30
+ * over the bridge port like Haven's broker, including the consent step for tools
31
+ * marked `consequentialHint`.
32
+ */
33
+
34
+ /** A file in the mock exchange: handed over by the app, or imported for it by the test. */
35
+ interface MockAgentFile {
36
+ fileRef: string;
37
+ name: string;
38
+ mimeType: string;
39
+ data: Uint8Array;
40
+ /** `app`: the app produced it (`provideFile`); `host`: imported for the app (`takeFile`). */
41
+ source: "app" | "host";
42
+ createdAt: number;
43
+ expiresAt: number;
44
+ }
45
+ /** How Haven's consent dialog answers a call to a consequential tool. */
46
+ type MockAgentConsent = "allow" | "deny" | ((call: {
47
+ tool: string;
48
+ input: Record<string, unknown>;
49
+ }) => boolean | Promise<boolean>);
50
+ type MockAgentCallResult = {
51
+ ok: true;
52
+ result: unknown;
53
+ durationMs: number;
54
+ } | {
55
+ ok: false;
56
+ error: {
57
+ code: MindooDBAppAgentToolErrorCode | "LOCKED" | string;
58
+ message: string;
59
+ requiredAction?: string;
60
+ };
61
+ durationMs: number;
62
+ };
63
+ /** One tool call as the log records it. */
64
+ interface MockAgentCall {
65
+ callId: string;
66
+ tool: string;
67
+ input: Record<string, unknown>;
68
+ startedAt: number;
69
+ outcome?: MockAgentCallResult;
70
+ }
71
+ interface MockAgentHostOptions {
72
+ /**
73
+ * The prefix agents see in front of the app's tool names (`agentToolPrefix` in
74
+ * `haven-app.json`). Without one it is derived from the app id, as Haven does.
75
+ */
76
+ agentToolPrefix?: string;
77
+ /** Whether the user has agent access on (`registerTools` answers `enabled`). Default true. */
78
+ agentToolsEnabled?: boolean;
79
+ /** Answer of the consent dialog for consequential tools. Default `"allow"`. */
80
+ agentConsent?: MockAgentConsent;
81
+ /** How long a call waits for the app. Default 120 s, Haven's limit. */
82
+ agentInvokeTimeoutMs?: number;
83
+ }
84
+ interface MockAgentHostController {
85
+ /** The app's tools as it declared them (without prefix). */
86
+ tools(): MindooDBAppAgentToolDescriptor[];
87
+ /** The names agents see: `<prefix>_<name>`. */
88
+ exposedNames(): string[];
89
+ readonly prefix: string;
90
+ /** What the app last passed to `setContext`. */
91
+ context(): Record<string, unknown> | null;
92
+ isEnabled(): boolean;
93
+ setEnabled(enabled: boolean): void;
94
+ setConsent(consent: MockAgentConsent): void;
95
+ /**
96
+ * Calls one of the app's tools as an agent would, by its own name or the prefixed
97
+ * one. Never throws: failures come back as `{ ok: false, error }` with the code the
98
+ * agent would see.
99
+ */
100
+ call(tool: string, input?: Record<string, unknown>): Promise<MockAgentCallResult>;
101
+ /** Every call so far, oldest first. */
102
+ calls(): ReadonlyArray<MockAgentCall>;
103
+ /** Puts a file in the exchange for the app, as Haven's `haven_files_import`; returns its fileRef. */
104
+ importFile(file: {
105
+ name: string;
106
+ mimeType?: string;
107
+ data: Uint8Array | ArrayBuffer | Blob | string;
108
+ }): Promise<string>;
109
+ /** A file the app handed over (`provideFile`), or `null` when unknown or expired. */
110
+ getFile(fileRef: string): MockAgentFile | null;
111
+ /** Files in the exchange (both directions), newest first. */
112
+ files(): MockAgentFile[];
113
+ }
114
+ /** Haven's derivation when the app declares no prefix (`agentAppKey`). */
115
+ declare function mockAgentToolPrefix(appId: string, declared?: string): string;
116
+ /** Haven's checks on declared tools (`validateAgentToolDescriptors`). */
117
+ declare function validateMockAgentTools(raw: unknown): MindooDBAppAgentToolDescriptor[];
118
+ interface MockAgentHost {
119
+ controller: MockAgentHostController;
120
+ /** Answers `agent.*` requests; `undefined` for any other method. */
121
+ dispatch(method: string, params: unknown): Promise<{
122
+ result: unknown;
123
+ } | undefined>;
124
+ /** The app's `agent-result` message. */
125
+ handleResult(message: MindooDBAppBridgeAgentResultMessage): void;
126
+ /** Fails pending calls (the app closed or reloaded). */
127
+ reset(reason?: string): void;
128
+ }
129
+ declare function createMockAgentHost(options: MockAgentHostOptions & {
130
+ appId: () => string;
131
+ /** Posts to the app's port; `false` when no app is connected. */
132
+ post(message: MindooDBAppBridgeAgentInvokeMessage): boolean;
133
+ onChange?(): void;
134
+ }): MockAgentHost;
135
+
24
136
  type EvaluatingViewDocument = {
25
137
  origin: string;
26
138
  docId: string;
@@ -105,6 +217,12 @@ interface CreateBrowserTestHostOptions extends CreateFakeBridgeHostOptions {
105
217
  interface BrowserTestHost {
106
218
  host: FakeBridgeHostController;
107
219
  log: BrowserTestHostLog;
220
+ /**
221
+ * Haven's agent-tool side (same as `host.agent`): the app's declared tools and
222
+ * context, `call(tool, input)` as an agent would, `importFile()` to hand the app a
223
+ * file for `takeFile`, and `getFile()` for what it handed over with `provideFile`.
224
+ */
225
+ agent: MockAgentHostController;
108
226
  /**
109
227
  * Decides the outcome of the app's next `attachments.scan()`: a file to "scan", or
110
228
  * `null` to act as if the user cancelled. Later scans follow {@link setScanMode}.
@@ -126,6 +244,14 @@ interface BrowserTestHost {
126
244
  setEnforceCapabilities(enforce: boolean): void;
127
245
  /** Replaces the usernames of the tenant directory (`directory.listUsers()`). */
128
246
  setDirectoryUsers(users: readonly string[]): void;
247
+ /**
248
+ * Another device edits a document and the change syncs in: the app's live queries
249
+ * update. With Automerge-backed databases (`automerge=1` / `automerge: true`) the
250
+ * edit is made at `input.json.baseHeads` by another actor and merged, so it is
251
+ * concurrent to app saves at the same heads. See
252
+ * `MockMindooDBAppSessionController.applyRemoteUpdate`.
253
+ */
254
+ applyRemoteUpdate(databaseId: string, docId: string, input: MindooDBAppUpdateDocumentInput, options?: MockRemoteUpdateOptions): Promise<MindooDBAppDocument>;
129
255
  /** Reloads the app frame. The mock data survives; the app's in-memory state does not. */
130
256
  reloadApp(): void;
131
257
  dispose(): void;
@@ -153,6 +279,8 @@ interface MockDatabasesFromDefinitionOptions {
153
279
  * `"none"`: the mock's stateless default.
154
280
  */
155
281
  attachments?: "memory" | "none";
282
+ /** Back documents with real Automerge documents (`MockMindooDBAppDatabaseDefinition.automerge`). */
283
+ automerge?: boolean;
156
284
  }
157
285
  /**
158
286
  * Mock databases for every database a `haven-app.json` declares, granted as requested
@@ -166,10 +294,13 @@ declare function mockDatabasesFromDefinition(definition: Pick<MindooDBAppDefinit
166
294
  * - `enforce=1` turns the capability checks on
167
295
  * - `users=<count>` fills the directory with generated users
168
296
  * - `locale=<tag>`, `theme=dark|light`
297
+ * - `automerge=1` backs every database with real Automerge documents (concurrent
298
+ * `baseHeads` merges, real heads); `automerge=0` turns it off
169
299
  */
170
300
  interface TestHostUrlSettings {
171
301
  overrides: Record<string, MockDatabaseOverride>;
172
302
  enforceCapabilities?: boolean;
303
+ automerge?: boolean;
173
304
  directoryUserCount?: number;
174
305
  locale?: string;
175
306
  theme?: "dark" | "light";
@@ -187,7 +318,7 @@ interface MountHavenTestHostOptions extends Omit<CreateBrowserTestHostOptions, "
187
318
  label: string;
188
319
  }>;
189
320
  /**
190
- * Read `db=`, `enforce=`, `users=`, `locale=` and `theme=` from the page URL (see
321
+ * Read `db=`, `enforce=`, `users=`, `locale=`, `theme=` and `automerge=` from the page URL (see
191
322
  * {@link readTestHostUrlSettings}) and keep the URL in sync with the panel. Default
192
323
  * true. URL settings win over the options passed here.
193
324
  */
@@ -295,6 +426,22 @@ interface MockMindooDBAppDatabaseDefinition {
295
426
  * results the same way they would in Haven.
296
427
  */
297
428
  summarySetup?: MindooDBAppSummarySetup | null;
429
+ /**
430
+ * Back every document with a real Automerge document, like Haven: `update`
431
+ * applies `set`/`unset`, `json` (at `json.baseHeads`) and `text` patches as
432
+ * Automerge changes, heads are real Automerge heads, and `applyRemoteUpdate`
433
+ * on the controller writes as another device so concurrent edits truly
434
+ * merge. Off by default (plain JSON with `mock-head-N` heads).
435
+ */
436
+ automerge?: boolean;
437
+ }
438
+ /** Options of `applyRemoteUpdate`. */
439
+ interface MockRemoteUpdateOptions {
440
+ /**
441
+ * Automerge actor id (hex) of the simulated device. Defaults to one fixed
442
+ * "remote" actor; pass different ids to simulate several devices.
443
+ */
444
+ actor?: string;
298
445
  }
299
446
  /**
300
447
  * Stands in for the host-owned sealed channel.
@@ -379,6 +526,15 @@ interface MockMindooDBAppSessionController {
379
526
  setEnforceCapabilities(enforce: boolean): void;
380
527
  /** Replaces the directory's usernames (see `directoryUsers`). */
381
528
  setDirectoryUsers(users: readonly string[]): void;
529
+ /**
530
+ * Writes `input` to a document as another device would, then syncs it in:
531
+ * live queries update like after any write. With `automerge: true` on the
532
+ * database the edit is made by a different Automerge actor on the history
533
+ * up to `input.json.baseHeads` (the current state when omitted) and merged,
534
+ * so it is truly concurrent to app writes at the same heads. Without it, it
535
+ * is a plain update. Bypasses capability checks (it is not the app writing).
536
+ */
537
+ applyRemoteUpdate(databaseId: string, docId: string, input: MindooDBAppUpdateDocumentInput, options?: MockRemoteUpdateOptions): Promise<MindooDBAppDocument>;
382
538
  emitThemeChange(theme: MindooDBAppHostTheme): void;
383
539
  emitViewportChange(viewport: MindooDBAppViewport): void;
384
540
  emitUiPreferencesChange(uiPreferences: MindooDBAppUiPreferences): void;
@@ -451,8 +607,10 @@ type FakeBridgeRpcResponse = {
451
607
  error: MindooDBAppBridgeErrorPayload;
452
608
  durationMs: number;
453
609
  };
454
- interface CreateFakeBridgeHostOptions extends CreateMockMindooDBAppSessionOptions {
610
+ interface CreateFakeBridgeHostOptions extends CreateMockMindooDBAppSessionOptions, MockAgentHostOptions {
455
611
  windowMode?: "parent" | "opener";
612
+ /** Called when the app's agent tools, context or exchange files change, and after each tool call. */
613
+ onAgentChange?: () => void;
456
614
  requestHandlers?: Record<string, FakeBridgeRequestHandler>;
457
615
  /** Called for every RPC request the app sends, before it is answered. */
458
616
  onRequest?: (request: MindooDBAppBridgeRpcRequest) => void;
@@ -502,6 +660,8 @@ interface FakeBridgeHostController {
502
660
  /** See {@link CreateMockMindooDBAppSessionOptions.directoryUsers}. */
503
661
  setDirectoryUsers(users: readonly string[]): void;
504
662
  getDirectoryUsers(): string[];
663
+ /** See {@link MockMindooDBAppSessionController.applyRemoteUpdate}. */
664
+ applyRemoteUpdate(databaseId: string, docId: string, input: MindooDBAppUpdateDocumentInput, options?: MockRemoteUpdateOptions): Promise<MindooDBAppDocument>;
505
665
  /** Embeds the app has open (`session.embeds.open`). */
506
666
  listEmbeds(): MockEmbedState[];
507
667
  /** Closes an embed and pushes the `embed-event` to the app. */
@@ -519,7 +679,12 @@ interface FakeBridgeHostController {
519
679
  * over the port and resolves or rejects with the app's answer.
520
680
  */
521
681
  requestEmbeddingSave(): Promise<void>;
682
+ /**
683
+ * Haven's agent-tool side: the tools and context the app declared, files in the
684
+ * exchange, and `call()` to run a tool as an agent would.
685
+ */
686
+ readonly agent: MockAgentHostController;
522
687
  }
523
688
  declare function createFakeBridgeHost(options?: CreateFakeBridgeHostOptions): FakeBridgeHostController;
524
689
 
525
- export { ALL_CAPABILITIES, type BrowserTestHost, type BrowserTestHostLog, type BrowserTestHostScan, type BrowserTestHostScanMode, type CreateBrowserTestHostOptions, type CreateFakeBridgeHostOptions, type CreateMockMindooDBAppSessionOptions, type EvaluatingViewDocument, type FakeBridgeHostController, type FakeBridgePortMessageHandler, type FakeBridgeRequestHandler, type FakeBridgeRpcResponse, type MockDatabaseOverride, type MockDatabasesFromDefinitionOptions, type MockEmbedState, type MockEmbeddingFinish, MockForbiddenError, type MockIncomingContentInput, type MockMindooDBAppDatabaseDefinition, type MockMindooDBAppSessionController, type MockSealedChannelOptions, type MockSeedDocument, type MountHavenTestHostOptions, TEST_HOST_LOCALES, type TestHostUrlSettings, capabilitiesForDefinitionPermissions, createBrowserTestHost, createEvaluatingViewNavigator, createFakeBridgeHost, createMemoryAttachments, createMockMindooDBAppBridge, createMockMindooDBAppSession, generateDirectoryUsers, loadMindoodbForTesting, mockDatabasesFromDefinition, mountHavenTestHost, previewJson, readTestHostUrlSettings };
690
+ export { ALL_CAPABILITIES, type BrowserTestHost, type BrowserTestHostLog, type BrowserTestHostScan, type BrowserTestHostScanMode, type CreateBrowserTestHostOptions, type CreateFakeBridgeHostOptions, type CreateMockMindooDBAppSessionOptions, type EvaluatingViewDocument, type FakeBridgeHostController, type FakeBridgePortMessageHandler, type FakeBridgeRequestHandler, type FakeBridgeRpcResponse, type MockAgentCall, type MockAgentCallResult, type MockAgentConsent, type MockAgentFile, type MockAgentHost, type MockAgentHostController, type MockAgentHostOptions, type MockDatabaseOverride, type MockDatabasesFromDefinitionOptions, type MockEmbedState, type MockEmbeddingFinish, MockForbiddenError, type MockIncomingContentInput, type MockMindooDBAppDatabaseDefinition, type MockMindooDBAppSessionController, type MockRemoteUpdateOptions, type MockSealedChannelOptions, type MockSeedDocument, type MountHavenTestHostOptions, TEST_HOST_LOCALES, type TestHostUrlSettings, capabilitiesForDefinitionPermissions, createBrowserTestHost, createEvaluatingViewNavigator, createFakeBridgeHost, createMemoryAttachments, createMockAgentHost, createMockMindooDBAppBridge, createMockMindooDBAppSession, generateDirectoryUsers, loadMindoodbForTesting, mockAgentToolPrefix, mockDatabasesFromDefinition, mountHavenTestHost, previewJson, readTestHostUrlSettings, validateMockAgentTools };