@dbx-tools/appkit-mastra 0.5.1 → 0.6.0

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.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Which Databricks identity a chat turn's workspace calls run as.
3
+ *
4
+ * Every Databricks call a turn makes - the `/serving-endpoints` catalogue the
5
+ * model picker reads, Genie suggestions, `ask_genie`, and the Statement
6
+ * Execution fetch behind a `[data:<id>]` embed - goes through the workspace
7
+ * client on the ambient AppKit execution context. That context is user-scoped
8
+ * (OBO) whenever the plugin enters `asUser(req)` and the app's service principal
9
+ * otherwise, so ONE decision - do we enter that scope for this request - moves
10
+ * every call site together. This module owns that decision.
11
+ *
12
+ * Why the option exists: OBO requires the caller to be a member of the
13
+ * WORKSPACE, not merely of the Databricks account. An app shared with an
14
+ * account-level group can therefore be opened by someone whose OBO token is
15
+ * perfectly valid but whose every workspace call fails with `Unauthorized
16
+ * access to Org: <workspace-id>`, and granting workspace membership is not
17
+ * always available - a workspace caps membership far below the size of a large
18
+ * account's user group. The app's own service principal already holds the Genie
19
+ * / warehouse / serving / Unity Catalog grants the app was deployed with, and
20
+ * works for every caller.
21
+ *
22
+ * The two modes, from `config.genieIdentity` (env: {@link IDENTITY_ENV}):
23
+ *
24
+ * - `"user"` (default): always OBO. Calls are attributed per user and Genie /
25
+ * Unity Catalog row filters apply per user. Correct whenever every caller is
26
+ * a workspace member. This is the historical behavior, so the option is
27
+ * purely additive - an app that never sets it is unchanged.
28
+ * - `"service-principal"`: always the app service principal. Needs no OBO
29
+ * scopes and works for any caller who can open the app, at the cost of
30
+ * per-user attribution in Genie / Unity Catalog.
31
+ *
32
+ * What `"service-principal"` does NOT change is WHO the turn belongs to. The
33
+ * memory thread's `resourceId`, the per-user cache namespace, and the user
34
+ * metadata on traces still come from the forwarded request headers, so two
35
+ * account users sharing the service principal's data access still get separate
36
+ * conversations and cannot read each other's threads or cached charts. Only the
37
+ * Databricks credential is shared.
38
+ *
39
+ * @module
40
+ */
41
+ import { ConfigurationError } from "@databricks/appkit";
42
+ import { string } from "@dbx-tools/shared-core";
43
+ /** Environment fallback for `config.genieIdentity`. */
44
+ export const IDENTITY_ENV = "MASTRA_GENIE_IDENTITY";
45
+ /** Every accepted {@link MastraIdentityMode}. */
46
+ export const IDENTITY_MODES = ["user", "service-principal"];
47
+ /**
48
+ * Default mode. `"user"` keeps OBO the only identity unless an app opts in, so
49
+ * adopting this option can never silently widen an existing app's data access.
50
+ */
51
+ export const DEFAULT_IDENTITY_MODE = "user";
52
+ /**
53
+ * Resolve the configured mode: explicit plugin config, then {@link IDENTITY_ENV},
54
+ * then {@link DEFAULT_IDENTITY_MODE}.
55
+ *
56
+ * An unrecognized value throws rather than falling back, since falling back
57
+ * would silently keep serving OBO - and the 500s it produces - to exactly the
58
+ * callers the option was set to accommodate.
59
+ */
60
+ export function resolveIdentityMode(configured) {
61
+ const raw = string.trimToNull(configured) ?? string.trimToNull(process.env[IDENTITY_ENV]);
62
+ if (raw === null)
63
+ return DEFAULT_IDENTITY_MODE;
64
+ const mode = raw.toLowerCase();
65
+ if (!IDENTITY_MODES.includes(mode)) {
66
+ throw new ConfigurationError(`genieIdentity must be one of ${IDENTITY_MODES.join(" | ")} (env: ${IDENTITY_ENV})`, { context: { field: "genieIdentity", envVar: IDENTITY_ENV, received: raw } });
67
+ }
68
+ return mode;
69
+ }
70
+ /** Header Databricks Apps forward the signed-in user's id on. */
71
+ export const USER_ID_HEADER = "x-forwarded-user";
72
+ /** Header Databricks Apps forward the signed-in user's email on. */
73
+ export const USER_EMAIL_HEADER = "x-forwarded-email";
74
+ /**
75
+ * The forwarded user id on `req`, or `undefined`. Used to attribute a turn to
76
+ * the real caller in `service-principal` mode, where the Databricks client is
77
+ * the app SP but memory / cache / traces must still key off the user.
78
+ */
79
+ export function requestUserId(req) {
80
+ return string.trimToNull(req.header(USER_ID_HEADER)) ?? undefined;
81
+ }
82
+ /** The forwarded user email on `req`, or `undefined`. */
83
+ export function requestUserEmail(req) {
84
+ return string.trimToNull(req.header(USER_EMAIL_HEADER)) ?? undefined;
85
+ }
86
+ /**
87
+ * Whether this request should run its Databricks calls as the app service
88
+ * principal rather than OBO. `"service-principal"` always does; `"user"` never
89
+ * does. The request is accepted for symmetry and to leave room for
90
+ * request-scoped policy later; it is unused today.
91
+ */
92
+ export function useServicePrincipal(mode, _req) {
93
+ return mode === "service-principal";
94
+ }
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWRlbnRpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaWRlbnRpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVDRztBQUVILE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQU1oRCx1REFBdUQ7QUFDdkQsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLHVCQUF1QixDQUFDO0FBRXBELGlEQUFpRDtBQUNqRCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQWtDLENBQUMsTUFBTSxFQUFFLG1CQUFtQixDQUFDLENBQUM7QUFFM0Y7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQXVCLE1BQU0sQ0FBQztBQUVoRTs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLFVBQThCO0lBQ2hFLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDMUYsSUFBSSxHQUFHLEtBQUssSUFBSTtRQUFFLE9BQU8scUJBQXFCLENBQUM7SUFDL0MsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLFdBQVcsRUFBd0IsQ0FBQztJQUNyRCxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ25DLE1BQU0sSUFBSSxrQkFBa0IsQ0FDMUIsZ0NBQWdDLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsWUFBWSxHQUFHLEVBQ25GLEVBQUUsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUM3RSxDQUFDO0lBQ0osQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVELGlFQUFpRTtBQUNqRSxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsa0JBQWtCLENBQUM7QUFFakQsb0VBQW9FO0FBQ3BFLE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLG1CQUFtQixDQUFDO0FBRXJEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLEdBQW9CO0lBQ2hELE9BQU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLElBQUksU0FBUyxDQUFDO0FBQ3BFLENBQUM7QUFFRCx5REFBeUQ7QUFDekQsTUFBTSxVQUFVLGdCQUFnQixDQUFDLEdBQW9CO0lBQ25ELE9BQU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsSUFBSSxTQUFTLENBQUM7QUFDdkUsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLElBQXdCLEVBQUUsSUFBc0I7SUFDbEYsT0FBTyxJQUFJLEtBQUssbUJBQW1CLENBQUM7QUFDdEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogV2hpY2ggRGF0YWJyaWNrcyBpZGVudGl0eSBhIGNoYXQgdHVybidzIHdvcmtzcGFjZSBjYWxscyBydW4gYXMuXG4gKlxuICogRXZlcnkgRGF0YWJyaWNrcyBjYWxsIGEgdHVybiBtYWtlcyAtIHRoZSBgL3NlcnZpbmctZW5kcG9pbnRzYCBjYXRhbG9ndWUgdGhlXG4gKiBtb2RlbCBwaWNrZXIgcmVhZHMsIEdlbmllIHN1Z2dlc3Rpb25zLCBgYXNrX2dlbmllYCwgYW5kIHRoZSBTdGF0ZW1lbnRcbiAqIEV4ZWN1dGlvbiBmZXRjaCBiZWhpbmQgYSBgW2RhdGE6PGlkPl1gIGVtYmVkIC0gZ29lcyB0aHJvdWdoIHRoZSB3b3Jrc3BhY2VcbiAqIGNsaWVudCBvbiB0aGUgYW1iaWVudCBBcHBLaXQgZXhlY3V0aW9uIGNvbnRleHQuIFRoYXQgY29udGV4dCBpcyB1c2VyLXNjb3BlZFxuICogKE9CTykgd2hlbmV2ZXIgdGhlIHBsdWdpbiBlbnRlcnMgYGFzVXNlcihyZXEpYCBhbmQgdGhlIGFwcCdzIHNlcnZpY2UgcHJpbmNpcGFsXG4gKiBvdGhlcndpc2UsIHNvIE9ORSBkZWNpc2lvbiAtIGRvIHdlIGVudGVyIHRoYXQgc2NvcGUgZm9yIHRoaXMgcmVxdWVzdCAtIG1vdmVzXG4gKiBldmVyeSBjYWxsIHNpdGUgdG9nZXRoZXIuIFRoaXMgbW9kdWxlIG93bnMgdGhhdCBkZWNpc2lvbi5cbiAqXG4gKiBXaHkgdGhlIG9wdGlvbiBleGlzdHM6IE9CTyByZXF1aXJlcyB0aGUgY2FsbGVyIHRvIGJlIGEgbWVtYmVyIG9mIHRoZVxuICogV09SS1NQQUNFLCBub3QgbWVyZWx5IG9mIHRoZSBEYXRhYnJpY2tzIGFjY291bnQuIEFuIGFwcCBzaGFyZWQgd2l0aCBhblxuICogYWNjb3VudC1sZXZlbCBncm91cCBjYW4gdGhlcmVmb3JlIGJlIG9wZW5lZCBieSBzb21lb25lIHdob3NlIE9CTyB0b2tlbiBpc1xuICogcGVyZmVjdGx5IHZhbGlkIGJ1dCB3aG9zZSBldmVyeSB3b3Jrc3BhY2UgY2FsbCBmYWlscyB3aXRoIGBVbmF1dGhvcml6ZWRcbiAqIGFjY2VzcyB0byBPcmc6IDx3b3Jrc3BhY2UtaWQ+YCwgYW5kIGdyYW50aW5nIHdvcmtzcGFjZSBtZW1iZXJzaGlwIGlzIG5vdFxuICogYWx3YXlzIGF2YWlsYWJsZSAtIGEgd29ya3NwYWNlIGNhcHMgbWVtYmVyc2hpcCBmYXIgYmVsb3cgdGhlIHNpemUgb2YgYSBsYXJnZVxuICogYWNjb3VudCdzIHVzZXIgZ3JvdXAuIFRoZSBhcHAncyBvd24gc2VydmljZSBwcmluY2lwYWwgYWxyZWFkeSBob2xkcyB0aGUgR2VuaWVcbiAqIC8gd2FyZWhvdXNlIC8gc2VydmluZyAvIFVuaXR5IENhdGFsb2cgZ3JhbnRzIHRoZSBhcHAgd2FzIGRlcGxveWVkIHdpdGgsIGFuZFxuICogd29ya3MgZm9yIGV2ZXJ5IGNhbGxlci5cbiAqXG4gKiBUaGUgdHdvIG1vZGVzLCBmcm9tIGBjb25maWcuZ2VuaWVJZGVudGl0eWAgKGVudjoge0BsaW5rIElERU5USVRZX0VOVn0pOlxuICpcbiAqICAgLSBgXCJ1c2VyXCJgIChkZWZhdWx0KTogYWx3YXlzIE9CTy4gQ2FsbHMgYXJlIGF0dHJpYnV0ZWQgcGVyIHVzZXIgYW5kIEdlbmllIC9cbiAqICAgICBVbml0eSBDYXRhbG9nIHJvdyBmaWx0ZXJzIGFwcGx5IHBlciB1c2VyLiBDb3JyZWN0IHdoZW5ldmVyIGV2ZXJ5IGNhbGxlciBpc1xuICogICAgIGEgd29ya3NwYWNlIG1lbWJlci4gVGhpcyBpcyB0aGUgaGlzdG9yaWNhbCBiZWhhdmlvciwgc28gdGhlIG9wdGlvbiBpc1xuICogICAgIHB1cmVseSBhZGRpdGl2ZSAtIGFuIGFwcCB0aGF0IG5ldmVyIHNldHMgaXQgaXMgdW5jaGFuZ2VkLlxuICogICAtIGBcInNlcnZpY2UtcHJpbmNpcGFsXCJgOiBhbHdheXMgdGhlIGFwcCBzZXJ2aWNlIHByaW5jaXBhbC4gTmVlZHMgbm8gT0JPXG4gKiAgICAgc2NvcGVzIGFuZCB3b3JrcyBmb3IgYW55IGNhbGxlciB3aG8gY2FuIG9wZW4gdGhlIGFwcCwgYXQgdGhlIGNvc3Qgb2ZcbiAqICAgICBwZXItdXNlciBhdHRyaWJ1dGlvbiBpbiBHZW5pZSAvIFVuaXR5IENhdGFsb2cuXG4gKlxuICogV2hhdCBgXCJzZXJ2aWNlLXByaW5jaXBhbFwiYCBkb2VzIE5PVCBjaGFuZ2UgaXMgV0hPIHRoZSB0dXJuIGJlbG9uZ3MgdG8uIFRoZVxuICogbWVtb3J5IHRocmVhZCdzIGByZXNvdXJjZUlkYCwgdGhlIHBlci11c2VyIGNhY2hlIG5hbWVzcGFjZSwgYW5kIHRoZSB1c2VyXG4gKiBtZXRhZGF0YSBvbiB0cmFjZXMgc3RpbGwgY29tZSBmcm9tIHRoZSBmb3J3YXJkZWQgcmVxdWVzdCBoZWFkZXJzLCBzbyB0d29cbiAqIGFjY291bnQgdXNlcnMgc2hhcmluZyB0aGUgc2VydmljZSBwcmluY2lwYWwncyBkYXRhIGFjY2VzcyBzdGlsbCBnZXQgc2VwYXJhdGVcbiAqIGNvbnZlcnNhdGlvbnMgYW5kIGNhbm5vdCByZWFkIGVhY2ggb3RoZXIncyB0aHJlYWRzIG9yIGNhY2hlZCBjaGFydHMuIE9ubHkgdGhlXG4gKiBEYXRhYnJpY2tzIGNyZWRlbnRpYWwgaXMgc2hhcmVkLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBDb25maWd1cmF0aW9uRXJyb3IgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBzdHJpbmcgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgZXhwcmVzcyBmcm9tIFwiZXhwcmVzc1wiO1xuXG4vKiogSWRlbnRpdHkgYSBjaGF0IHR1cm4ncyBEYXRhYnJpY2tzIGNhbGxzIHJ1biBhcy4gU2VlIHRoZSBtb2R1bGUgZG9jcy4gKi9cbmV4cG9ydCB0eXBlIE1hc3RyYUlkZW50aXR5TW9kZSA9IFwidXNlclwiIHwgXCJzZXJ2aWNlLXByaW5jaXBhbFwiO1xuXG4vKiogRW52aXJvbm1lbnQgZmFsbGJhY2sgZm9yIGBjb25maWcuZ2VuaWVJZGVudGl0eWAuICovXG5leHBvcnQgY29uc3QgSURFTlRJVFlfRU5WID0gXCJNQVNUUkFfR0VOSUVfSURFTlRJVFlcIjtcblxuLyoqIEV2ZXJ5IGFjY2VwdGVkIHtAbGluayBNYXN0cmFJZGVudGl0eU1vZGV9LiAqL1xuZXhwb3J0IGNvbnN0IElERU5USVRZX01PREVTOiByZWFkb25seSBNYXN0cmFJZGVudGl0eU1vZGVbXSA9IFtcInVzZXJcIiwgXCJzZXJ2aWNlLXByaW5jaXBhbFwiXTtcblxuLyoqXG4gKiBEZWZhdWx0IG1vZGUuIGBcInVzZXJcImAga2VlcHMgT0JPIHRoZSBvbmx5IGlkZW50aXR5IHVubGVzcyBhbiBhcHAgb3B0cyBpbiwgc29cbiAqIGFkb3B0aW5nIHRoaXMgb3B0aW9uIGNhbiBuZXZlciBzaWxlbnRseSB3aWRlbiBhbiBleGlzdGluZyBhcHAncyBkYXRhIGFjY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfSURFTlRJVFlfTU9ERTogTWFzdHJhSWRlbnRpdHlNb2RlID0gXCJ1c2VyXCI7XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgY29uZmlndXJlZCBtb2RlOiBleHBsaWNpdCBwbHVnaW4gY29uZmlnLCB0aGVuIHtAbGluayBJREVOVElUWV9FTlZ9LFxuICogdGhlbiB7QGxpbmsgREVGQVVMVF9JREVOVElUWV9NT0RFfS5cbiAqXG4gKiBBbiB1bnJlY29nbml6ZWQgdmFsdWUgdGhyb3dzIHJhdGhlciB0aGFuIGZhbGxpbmcgYmFjaywgc2luY2UgZmFsbGluZyBiYWNrXG4gKiB3b3VsZCBzaWxlbnRseSBrZWVwIHNlcnZpbmcgT0JPIC0gYW5kIHRoZSA1MDBzIGl0IHByb2R1Y2VzIC0gdG8gZXhhY3RseSB0aGVcbiAqIGNhbGxlcnMgdGhlIG9wdGlvbiB3YXMgc2V0IHRvIGFjY29tbW9kYXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUlkZW50aXR5TW9kZShjb25maWd1cmVkOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBNYXN0cmFJZGVudGl0eU1vZGUge1xuICBjb25zdCByYXcgPSBzdHJpbmcudHJpbVRvTnVsbChjb25maWd1cmVkKSA/PyBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudltJREVOVElUWV9FTlZdKTtcbiAgaWYgKHJhdyA9PT0gbnVsbCkgcmV0dXJuIERFRkFVTFRfSURFTlRJVFlfTU9ERTtcbiAgY29uc3QgbW9kZSA9IHJhdy50b0xvd2VyQ2FzZSgpIGFzIE1hc3RyYUlkZW50aXR5TW9kZTtcbiAgaWYgKCFJREVOVElUWV9NT0RFUy5pbmNsdWRlcyhtb2RlKSkge1xuICAgIHRocm93IG5ldyBDb25maWd1cmF0aW9uRXJyb3IoXG4gICAgICBgZ2VuaWVJZGVudGl0eSBtdXN0IGJlIG9uZSBvZiAke0lERU5USVRZX01PREVTLmpvaW4oXCIgfCBcIil9IChlbnY6ICR7SURFTlRJVFlfRU5WfSlgLFxuICAgICAgeyBjb250ZXh0OiB7IGZpZWxkOiBcImdlbmllSWRlbnRpdHlcIiwgZW52VmFyOiBJREVOVElUWV9FTlYsIHJlY2VpdmVkOiByYXcgfSB9LFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIG1vZGU7XG59XG5cbi8qKiBIZWFkZXIgRGF0YWJyaWNrcyBBcHBzIGZvcndhcmQgdGhlIHNpZ25lZC1pbiB1c2VyJ3MgaWQgb24uICovXG5leHBvcnQgY29uc3QgVVNFUl9JRF9IRUFERVIgPSBcIngtZm9yd2FyZGVkLXVzZXJcIjtcblxuLyoqIEhlYWRlciBEYXRhYnJpY2tzIEFwcHMgZm9yd2FyZCB0aGUgc2lnbmVkLWluIHVzZXIncyBlbWFpbCBvbi4gKi9cbmV4cG9ydCBjb25zdCBVU0VSX0VNQUlMX0hFQURFUiA9IFwieC1mb3J3YXJkZWQtZW1haWxcIjtcblxuLyoqXG4gKiBUaGUgZm9yd2FyZGVkIHVzZXIgaWQgb24gYHJlcWAsIG9yIGB1bmRlZmluZWRgLiBVc2VkIHRvIGF0dHJpYnV0ZSBhIHR1cm4gdG9cbiAqIHRoZSByZWFsIGNhbGxlciBpbiBgc2VydmljZS1wcmluY2lwYWxgIG1vZGUsIHdoZXJlIHRoZSBEYXRhYnJpY2tzIGNsaWVudCBpc1xuICogdGhlIGFwcCBTUCBidXQgbWVtb3J5IC8gY2FjaGUgLyB0cmFjZXMgbXVzdCBzdGlsbCBrZXkgb2ZmIHRoZSB1c2VyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWVzdFVzZXJJZChyZXE6IGV4cHJlc3MuUmVxdWVzdCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBzdHJpbmcudHJpbVRvTnVsbChyZXEuaGVhZGVyKFVTRVJfSURfSEVBREVSKSkgPz8gdW5kZWZpbmVkO1xufVxuXG4vKiogVGhlIGZvcndhcmRlZCB1c2VyIGVtYWlsIG9uIGByZXFgLCBvciBgdW5kZWZpbmVkYC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1ZXN0VXNlckVtYWlsKHJlcTogZXhwcmVzcy5SZXF1ZXN0KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHN0cmluZy50cmltVG9OdWxsKHJlcS5oZWFkZXIoVVNFUl9FTUFJTF9IRUFERVIpKSA/PyB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGlzIHJlcXVlc3Qgc2hvdWxkIHJ1biBpdHMgRGF0YWJyaWNrcyBjYWxscyBhcyB0aGUgYXBwIHNlcnZpY2VcbiAqIHByaW5jaXBhbCByYXRoZXIgdGhhbiBPQk8uIGBcInNlcnZpY2UtcHJpbmNpcGFsXCJgIGFsd2F5cyBkb2VzOyBgXCJ1c2VyXCJgIG5ldmVyXG4gKiBkb2VzLiBUaGUgcmVxdWVzdCBpcyBhY2NlcHRlZCBmb3Igc3ltbWV0cnkgYW5kIHRvIGxlYXZlIHJvb20gZm9yXG4gKiByZXF1ZXN0LXNjb3BlZCBwb2xpY3kgbGF0ZXI7IGl0IGlzIHVudXNlZCB0b2RheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZVNlcnZpY2VQcmluY2lwYWwobW9kZTogTWFzdHJhSWRlbnRpdHlNb2RlLCBfcmVxPzogZXhwcmVzcy5SZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiBtb2RlID09PSBcInNlcnZpY2UtcHJpbmNpcGFsXCI7XG59XG4iXX0=
@@ -103,6 +103,12 @@ export declare class MastraPlugin extends Plugin<MastraPluginConfig> {
103
103
  * {@link buildAgentAndServer} and registered on the Mastra instance.
104
104
  */
105
105
  private mcp;
106
+ /**
107
+ * Resolved {@link MastraIdentityMode}: the identity the chat path's Databricks
108
+ * calls run as. Read once at setup so an invalid `genieIdentity` fails the app
109
+ * boot rather than the first request, and so every request agrees.
110
+ */
111
+ private identityMode;
106
112
  /**
107
113
  * Dedicated service-principal Lakebase pool backing Mastra memory /
108
114
  * storage. Built once in {@link buildAgentAndServer} (outside any
@@ -112,6 +118,22 @@ export declare class MastraPlugin extends Plugin<MastraPluginConfig> {
112
118
  */
113
119
  private servicePrincipalPool;
114
120
  setup(): Promise<void>;
121
+ /**
122
+ * The plugin instance the chat path's Databricks calls should run through for
123
+ * `req`, honoring {@link identityMode}.
124
+ *
125
+ * In `"user"` mode (the default) this is `this.asUser(req)` - AppKit's own
126
+ * proxy that runs every call inside `runInUserContext`, so `getExecutionContext()`
127
+ * returns the caller's OBO client, exactly as before this option existed. In
128
+ * `"service-principal"` mode it is `this` unwrapped, so the same methods run in
129
+ * the ambient service context and `getExecutionContext()` returns the app
130
+ * service principal's client - the same "just don't enter `asUser`" pattern
131
+ * AppKit's own service-context calls use. One helper covers every workspace
132
+ * call the chat path makes (serving catalogue, Genie suggestions, `ask_genie`
133
+ * via the dispatched agent turn, statement fetch, feedback), so the identity
134
+ * decision lives in one place.
135
+ */
136
+ private scopedSelf;
115
137
  /**
116
138
  * When the `lakebase` plugin is registered, auto-enable `storage`
117
139
  * and `memory` unless the caller opted out explicitly (`false` or a