@dbx-tools/appkit-mastra 0.5.0 → 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.
- package/README.md +22 -7
- package/index.ts +4 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +3 -1
- package/lib/src/config.d.ts +33 -0
- package/lib/src/config.js +6 -1
- package/lib/src/identity.d.ts +80 -0
- package/lib/src/identity.js +95 -0
- package/lib/src/plugin.d.ts +22 -0
- package/lib/src/plugin.js +40 -8
- package/lib/src/server.d.ts +20 -2
- package/lib/src/server.js +32 -13
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/config.ts +39 -0
- package/src/identity.ts +110 -0
- package/src/plugin.ts +40 -7
- package/src/server.ts +50 -12
package/src/server.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
type MastraPluginConfig,
|
|
30
30
|
type User,
|
|
31
31
|
} from "./config.ts";
|
|
32
|
+
import { requestUserEmail, requestUserId } from "./identity.ts";
|
|
32
33
|
import { resolveFeedbackEnabled } from "./mlflow.ts";
|
|
33
34
|
|
|
34
35
|
import {
|
|
@@ -44,6 +45,21 @@ import {
|
|
|
44
45
|
*/
|
|
45
46
|
const INVALID_TRACE_ID = "0".repeat(32);
|
|
46
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Who a turn is ATTRIBUTED to, independent of which Databricks credential runs
|
|
50
|
+
* its calls. Supplied by the HTTP middleware from the forwarded user headers so
|
|
51
|
+
* that in `service-principal` mode - where every request shares the app SP's
|
|
52
|
+
* client - the memory thread, per-user cache namespace, and trace metadata
|
|
53
|
+
* still key off the real caller. Ignored in an OBO (user) context, whose own
|
|
54
|
+
* user id / email are authoritative.
|
|
55
|
+
*/
|
|
56
|
+
export interface AttributedIdentity {
|
|
57
|
+
/** Forwarded `x-forwarded-user` id, used when the client is the service principal. */
|
|
58
|
+
userId?: string | undefined;
|
|
59
|
+
/** Forwarded `x-forwarded-email`, used for trace metadata under the service principal. */
|
|
60
|
+
email?: string | undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
/**
|
|
48
64
|
* Stamp the AppKit user (plus the resource id and trace metadata) onto
|
|
49
65
|
* `requestContext`.
|
|
@@ -56,27 +72,43 @@ const INVALID_TRACE_ID = "0".repeat(32);
|
|
|
56
72
|
* callers build a context with {@link createRequestContext} instead of a
|
|
57
73
|
* request.
|
|
58
74
|
*
|
|
75
|
+
* The Databricks credential always comes from the ambient execution context;
|
|
76
|
+
* `attributed` only changes WHO the turn is attributed to when that context is
|
|
77
|
+
* the service principal (see {@link AttributedIdentity}).
|
|
78
|
+
*
|
|
59
79
|
* Idempotent: returns immediately when the user and resource id are already
|
|
60
80
|
* present, so the middleware can call it over a context another layer stamped.
|
|
61
81
|
*/
|
|
62
|
-
export async function stampRequestContextUser(
|
|
82
|
+
export async function stampRequestContextUser(
|
|
83
|
+
requestContext: RequestContext,
|
|
84
|
+
attributed: AttributedIdentity = {},
|
|
85
|
+
): Promise<void> {
|
|
63
86
|
if ([MASTRA_USER_KEY, MASTRA_RESOURCE_ID_KEY].every((key) => requestContext.get(key))) return;
|
|
64
87
|
const executionContext = getExecutionContext();
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
const isUserContext = "isUserContext" in executionContext;
|
|
89
|
+
// The Databricks CREDENTIAL is always the ambient execution context's client
|
|
90
|
+
// (OBO in a user context, the service principal otherwise). WHO the turn is
|
|
91
|
+
// attributed to can differ: in `service-principal` mode every request shares
|
|
92
|
+
// the SP client, but the forwarded user id must still key the memory thread
|
|
93
|
+
// and the per-user cache namespace so two callers don't share a conversation.
|
|
94
|
+
// Prefer the OBO context's own user id, then the forwarded id, then the SP id.
|
|
95
|
+
const id =
|
|
96
|
+
(isUserContext ? executionContextUserId(executionContext) : attributed.userId) ??
|
|
97
|
+
executionContextUserId(executionContext);
|
|
98
|
+
const user: User = { id, executionContext };
|
|
69
99
|
requestContext.set(MASTRA_USER_KEY, user);
|
|
70
100
|
requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id);
|
|
71
101
|
// AppKit's `UserContext` surfaces display name / email only on
|
|
72
102
|
// OBO requests. Service-context calls (background tasks, server
|
|
73
103
|
// start-up) leave these undefined and we skip the stamp so
|
|
74
|
-
// downstream trace metadata stays absent rather than empty.
|
|
104
|
+
// downstream trace metadata stays absent rather than empty. In
|
|
105
|
+
// `service-principal` mode the forwarded email still identifies the caller,
|
|
106
|
+
// so it is used for trace metadata even though the client is the SP.
|
|
75
107
|
let userName: string | undefined;
|
|
76
|
-
let email: string | undefined;
|
|
77
|
-
if (
|
|
108
|
+
let email: string | undefined = attributed.email;
|
|
109
|
+
if (isUserContext) {
|
|
78
110
|
userName = executionContext.userName;
|
|
79
|
-
email = executionContext.userEmail;
|
|
111
|
+
email = executionContext.userEmail ?? email;
|
|
80
112
|
} else if (process.env.NODE_ENV === "development") {
|
|
81
113
|
const currentUser = await executionContext.client.currentUser.me();
|
|
82
114
|
userName = currentUser?.userName;
|
|
@@ -142,7 +174,7 @@ export class MastraServer extends MastraServerExpress {
|
|
|
142
174
|
super.registerAuthMiddleware();
|
|
143
175
|
this.app.use(async (req, res, next) => {
|
|
144
176
|
const requestContext = res.locals.requestContext! as RequestContext;
|
|
145
|
-
await this.configureRequestContextUser(requestContext);
|
|
177
|
+
await this.configureRequestContextUser(req, requestContext);
|
|
146
178
|
this.configureRequestContextThreadId(req, res, requestContext);
|
|
147
179
|
this.configureRequestContextModelOverride(req, requestContext);
|
|
148
180
|
this.configureRequestContextRequestId(req, res, requestContext);
|
|
@@ -167,8 +199,14 @@ export class MastraServer extends MastraServerExpress {
|
|
|
167
199
|
});
|
|
168
200
|
}
|
|
169
201
|
|
|
170
|
-
async configureRequestContextUser(requestContext: RequestContext) {
|
|
171
|
-
|
|
202
|
+
async configureRequestContextUser(req: express.Request, requestContext: RequestContext) {
|
|
203
|
+
// Pass the forwarded caller identity so `service-principal` mode still keys
|
|
204
|
+
// memory / cache / traces per user even though the client is the app SP.
|
|
205
|
+
// In an OBO context these are ignored in favor of the context's own user.
|
|
206
|
+
await stampRequestContextUser(requestContext, {
|
|
207
|
+
userId: requestUserId(req),
|
|
208
|
+
email: requestUserEmail(req),
|
|
209
|
+
});
|
|
172
210
|
}
|
|
173
211
|
|
|
174
212
|
/**
|