@dbx-tools/appkit-mastra 0.1.75 → 0.1.76
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 +3 -0
- package/dist/index.js +129 -38
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -117,6 +117,9 @@ management (registered alongside `/route/history`):
|
|
|
117
117
|
- `DELETE /route/threads` - delete the targeted thread (id from the
|
|
118
118
|
thread-selection header). Ownership is enforced server-side: a thread
|
|
119
119
|
is only removed when it belongs to the caller.
|
|
120
|
+
- `PATCH /route/threads` - rename the targeted thread (id from the
|
|
121
|
+
thread-selection header) to the `{ title }` in the JSON body. Same
|
|
122
|
+
ownership enforcement; existing thread metadata is preserved.
|
|
120
123
|
|
|
121
124
|
Each thread is auto-titled from its opening turn (Mastra's
|
|
122
125
|
`generateTitle`), but titling runs on the **small / fast chat tier**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChartSchema, ChartTypeSchema, DEFAULT_COMMENT_NAME, DEFAULT_FEEDBACK_NAME, MASTRA_ROUTES, MLFLOW_TRACE_ID_HEADER, MODEL_OVERRIDE_BODY_FIELDS, MODEL_OVERRIDE_HEADER, MODEL_OVERRIDE_QUERY, MastraFeedbackRequestSchema, THREAD_ID_HEADER, THREAD_ID_QUERY } from "@dbx-tools/appkit-mastra-shared";
|
|
1
|
+
import { ChartSchema, ChartTypeSchema, DEFAULT_COMMENT_NAME, DEFAULT_FEEDBACK_NAME, MASTRA_ROUTES, MLFLOW_TRACE_ID_HEADER, MODEL_OVERRIDE_BODY_FIELDS, MODEL_OVERRIDE_HEADER, MODEL_OVERRIDE_QUERY, MastraFeedbackRequestSchema, MastraUpdateThreadRequestSchema, THREAD_ID_HEADER, THREAD_ID_QUERY } from "@dbx-tools/appkit-mastra-shared";
|
|
2
2
|
import { DEFAULT_FUZZY_THRESHOLD, DEFAULT_MODEL_CACHE_TTL_MS, FALLBACK_MODEL_IDS, ModelClass, ModelClass as ModelClass$1, clearServingEndpointsCache, listServingEndpoints, parseModelClass, selectModel } from "@dbx-tools/model";
|
|
3
3
|
import { apiUtils, appkitUtils, commonUtils, httpUtils, logUtils, netUtils, projectUtils, stringUtils } from "@dbx-tools/shared";
|
|
4
4
|
import { Agent } from "@mastra/core/agent";
|
|
@@ -226,8 +226,8 @@ const SERVING_ENDPOINTS_PATH_PREFIX = "/serving-endpoints/";
|
|
|
226
226
|
*
|
|
227
227
|
* Safe to call from any hot path: {@link commonUtils.memoize} ensures
|
|
228
228
|
* the wrapper is installed at most once per process, so subsequent
|
|
229
|
-
* calls
|
|
230
|
-
*
|
|
229
|
+
* calls are a no-op even when {@link buildModel} fires on every agent
|
|
230
|
+
* step.
|
|
231
231
|
*/
|
|
232
232
|
const setupFetchInterceptor = commonUtils.memoize(() => {
|
|
233
233
|
const log = logUtils.logger("mastra/llm");
|
|
@@ -3788,6 +3788,26 @@ function attachRoutePatchMiddleware(app) {
|
|
|
3788
3788
|
|
|
3789
3789
|
//#endregion
|
|
3790
3790
|
//#region packages/appkit-mastra/src/threads.ts
|
|
3791
|
+
/**
|
|
3792
|
+
* Conversation-thread listing exposed as a Mastra custom API route.
|
|
3793
|
+
*
|
|
3794
|
+
* Backed entirely by native Mastra: looks up the active agent by id,
|
|
3795
|
+
* asks its `Memory` instance to `listThreads` filtered to the caller's
|
|
3796
|
+
* resource, and shapes each into the JSON-safe {@link MastraThread}
|
|
3797
|
+
* wire type. A sibling `DELETE` removes a single named thread.
|
|
3798
|
+
*
|
|
3799
|
+
* A sibling `DELETE` removes a single named thread; a `PATCH` renames
|
|
3800
|
+
* one ({@link renameThread}).
|
|
3801
|
+
*
|
|
3802
|
+
* Like {@link historyRoute} this registers through Mastra's
|
|
3803
|
+
* `registerApiRoute` so it shares the `MastraServer` auth-middleware
|
|
3804
|
+
* pipeline (in `./server.ts`), which has already stamped the resource
|
|
3805
|
+
* id (`MASTRA_RESOURCE_ID_KEY`) and the targeted thread id
|
|
3806
|
+
* (`MASTRA_THREAD_ID_KEY`, resolved from the thread-selection header /
|
|
3807
|
+
* cookie) on `RequestContext` by the time a handler runs. Resource
|
|
3808
|
+
* scoping lives here so a caller can only ever see, rename, or delete
|
|
3809
|
+
* its own threads; no cookie or user lookups happen in this module.
|
|
3810
|
+
*/
|
|
3791
3811
|
const log = logUtils.logger("mastra/threads");
|
|
3792
3812
|
/** Default threads page size. */
|
|
3793
3813
|
const DEFAULT_PER_PAGE = 30;
|
|
@@ -3882,7 +3902,47 @@ async function deleteThread(opts) {
|
|
|
3882
3902
|
return { deleted: true };
|
|
3883
3903
|
}
|
|
3884
3904
|
/**
|
|
3885
|
-
*
|
|
3905
|
+
* Rename a single thread, returning the updated wire thread.
|
|
3906
|
+
*
|
|
3907
|
+
* Ownership is enforced the same way {@link deleteThread} enforces it:
|
|
3908
|
+
* the title is only changed when the thread belongs to the calling
|
|
3909
|
+
* resource, so a client can't rename another user's conversation by
|
|
3910
|
+
* guessing its id. Existing thread `metadata` is preserved untouched
|
|
3911
|
+
* (Mastra's `updateThread` replaces the row, so it must be passed back
|
|
3912
|
+
* in). Returns `null` when the thread doesn't exist, isn't owned by the
|
|
3913
|
+
* caller, or the agent has no memory configured, letting the route map
|
|
3914
|
+
* that to a 404.
|
|
3915
|
+
*/
|
|
3916
|
+
async function renameThread(opts) {
|
|
3917
|
+
const memory = await opts.agent.getMemory();
|
|
3918
|
+
if (!memory) {
|
|
3919
|
+
log.debug("rename:no-memory", { agentId: opts.agent.id });
|
|
3920
|
+
return null;
|
|
3921
|
+
}
|
|
3922
|
+
const existing = await memory.getThreadById({ threadId: opts.threadId });
|
|
3923
|
+
if (!existing || existing.resourceId !== opts.resourceId) {
|
|
3924
|
+
log.debug("rename:not-owned", {
|
|
3925
|
+
agentId: opts.agent.id,
|
|
3926
|
+
threadId: opts.threadId,
|
|
3927
|
+
found: existing !== null
|
|
3928
|
+
});
|
|
3929
|
+
return null;
|
|
3930
|
+
}
|
|
3931
|
+
const startedAt = Date.now();
|
|
3932
|
+
const updated = await memory.updateThread({
|
|
3933
|
+
id: opts.threadId,
|
|
3934
|
+
title: opts.title,
|
|
3935
|
+
metadata: existing.metadata ?? {}
|
|
3936
|
+
});
|
|
3937
|
+
log.info("rename:done", {
|
|
3938
|
+
agentId: opts.agent.id,
|
|
3939
|
+
threadId: opts.threadId,
|
|
3940
|
+
elapsedMs: Date.now() - startedAt
|
|
3941
|
+
});
|
|
3942
|
+
return toWireThread(updated);
|
|
3943
|
+
}
|
|
3944
|
+
/**
|
|
3945
|
+
* Register the `<path>` Mastra custom API route. Handles three methods
|
|
3886
3946
|
* on the same mount:
|
|
3887
3947
|
*
|
|
3888
3948
|
* - `GET`: a page of the resource's conversation threads
|
|
@@ -3892,6 +3952,10 @@ async function deleteThread(opts) {
|
|
|
3892
3952
|
* `RequestContext` (the auth middleware resolves it the same way it
|
|
3893
3953
|
* does for streaming and history), so the client deletes any of its
|
|
3894
3954
|
* threads by stamping the target id - no separate path param.
|
|
3955
|
+
* - `PATCH`: rename the thread named by the thread-selection header /
|
|
3956
|
+
* `?threadId=` query to the `{ title }` in the JSON body
|
|
3957
|
+
* ({@link renameThread}). Targets a thread the same way `DELETE`
|
|
3958
|
+
* does; 404s when the thread isn't owned by the caller.
|
|
3895
3959
|
*
|
|
3896
3960
|
* Follows the `@mastra/ai-sdk` agent-binding convention: pass `agent`
|
|
3897
3961
|
* for a fixed-agent mount, or include `:agentId` in the path for
|
|
@@ -3918,40 +3982,67 @@ function threadsRoute(options) {
|
|
|
3918
3982
|
resourceId
|
|
3919
3983
|
};
|
|
3920
3984
|
};
|
|
3921
|
-
return [
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3985
|
+
return [
|
|
3986
|
+
registerApiRoute(path, {
|
|
3987
|
+
method: "GET",
|
|
3988
|
+
handler: async (c) => {
|
|
3989
|
+
const ctx = resolveContext(c);
|
|
3990
|
+
if ("error" in ctx) return ctx.error;
|
|
3991
|
+
const payload = await listThreads({
|
|
3992
|
+
agent: ctx.agent,
|
|
3993
|
+
resourceId: ctx.resourceId,
|
|
3994
|
+
page: parseIntParam(c.req.query("page")),
|
|
3995
|
+
perPage: parseIntParam(c.req.query("perPage"))
|
|
3996
|
+
});
|
|
3997
|
+
return c.json(payload);
|
|
3998
|
+
}
|
|
3999
|
+
}),
|
|
4000
|
+
registerApiRoute(path, {
|
|
4001
|
+
method: "DELETE",
|
|
4002
|
+
handler: async (c) => {
|
|
4003
|
+
const ctx = resolveContext(c);
|
|
4004
|
+
if ("error" in ctx) return ctx.error;
|
|
4005
|
+
const threadId = ctx.requestContext.get(MASTRA_THREAD_ID_KEY);
|
|
4006
|
+
if (!threadId) return c.json({ error: "thread id missing from request context" }, 400);
|
|
4007
|
+
const { deleted } = await deleteThread({
|
|
4008
|
+
agent: ctx.agent,
|
|
4009
|
+
threadId,
|
|
4010
|
+
resourceId: ctx.resourceId
|
|
4011
|
+
});
|
|
4012
|
+
const payload = {
|
|
4013
|
+
ok: true,
|
|
4014
|
+
agentId: ctx.agentId,
|
|
4015
|
+
threadId,
|
|
4016
|
+
deleted
|
|
4017
|
+
};
|
|
4018
|
+
return c.json(payload);
|
|
4019
|
+
}
|
|
4020
|
+
}),
|
|
4021
|
+
registerApiRoute(path, {
|
|
4022
|
+
method: "PATCH",
|
|
4023
|
+
handler: async (c) => {
|
|
4024
|
+
const ctx = resolveContext(c);
|
|
4025
|
+
if ("error" in ctx) return ctx.error;
|
|
4026
|
+
const threadId = ctx.requestContext.get(MASTRA_THREAD_ID_KEY);
|
|
4027
|
+
if (!threadId) return c.json({ error: "thread id missing from request context" }, 400);
|
|
4028
|
+
const body = MastraUpdateThreadRequestSchema.safeParse(await c.req.json());
|
|
4029
|
+
if (!body.success) return c.json({ error: body.error.message }, 400);
|
|
4030
|
+
const thread = await renameThread({
|
|
4031
|
+
agent: ctx.agent,
|
|
4032
|
+
threadId,
|
|
4033
|
+
resourceId: ctx.resourceId,
|
|
4034
|
+
title: body.data.title
|
|
4035
|
+
});
|
|
4036
|
+
if (!thread) return c.json({ error: `Unknown thread "${threadId}"` }, 404);
|
|
4037
|
+
const payload = {
|
|
4038
|
+
ok: true,
|
|
4039
|
+
agentId: ctx.agentId,
|
|
4040
|
+
thread
|
|
4041
|
+
};
|
|
4042
|
+
return c.json(payload);
|
|
4043
|
+
}
|
|
4044
|
+
})
|
|
4045
|
+
];
|
|
3955
4046
|
}
|
|
3956
4047
|
/** Coerce a Mastra `StorageThreadType` into the JSON-safe wire shape. */
|
|
3957
4048
|
function toWireThread(thread) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dbx-tools/appkit-mastra",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.76",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@databricks/sdk-experimental": "^0.17",
|
|
6
|
-
"@dbx-tools/appkit-mastra-shared": "0.1.
|
|
7
|
-
"@dbx-tools/genie": "0.1.
|
|
8
|
-
"@dbx-tools/genie-shared": "0.1.
|
|
9
|
-
"@dbx-tools/model": "0.1.
|
|
10
|
-
"@dbx-tools/shared": "0.1.
|
|
6
|
+
"@dbx-tools/appkit-mastra-shared": "0.1.76",
|
|
7
|
+
"@dbx-tools/genie": "0.1.76",
|
|
8
|
+
"@dbx-tools/genie-shared": "0.1.76",
|
|
9
|
+
"@dbx-tools/model": "0.1.76",
|
|
10
|
+
"@dbx-tools/shared": "0.1.76",
|
|
11
11
|
"@mastra/ai-sdk": "^1",
|
|
12
12
|
"@mastra/core": "^1",
|
|
13
13
|
"@mastra/express": "^1",
|