@dbx-tools/appkit-mastra 0.3.44 → 0.4.1

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.
Files changed (56) hide show
  1. package/lib/index.d.ts +71 -0
  2. package/lib/index.js +56 -0
  3. package/lib/src/agents.d.ts +347 -0
  4. package/lib/src/agents.js +554 -0
  5. package/lib/src/chart.d.ts +192 -0
  6. package/lib/src/chart.js +638 -0
  7. package/lib/src/config.d.ts +479 -0
  8. package/lib/src/config.js +190 -0
  9. package/lib/src/defaults.d.ts +68 -0
  10. package/lib/src/defaults.js +107 -0
  11. package/lib/src/filesystems.d.ts +208 -0
  12. package/lib/src/filesystems.js +958 -0
  13. package/lib/src/genie.d.ts +166 -0
  14. package/lib/src/genie.js +969 -0
  15. package/lib/src/history.d.ts +97 -0
  16. package/lib/src/history.js +264 -0
  17. package/lib/src/mcp.d.ts +66 -0
  18. package/lib/src/mcp.js +65 -0
  19. package/lib/src/memory.d.ts +111 -0
  20. package/lib/src/memory.js +275 -0
  21. package/lib/src/mlflow.d.ts +63 -0
  22. package/lib/src/mlflow.js +117 -0
  23. package/lib/src/model.d.ts +62 -0
  24. package/lib/src/model.js +168 -0
  25. package/lib/src/observability.d.ts +81 -0
  26. package/lib/src/observability.js +98 -0
  27. package/lib/src/pagination.d.ts +23 -0
  28. package/lib/src/pagination.js +31 -0
  29. package/lib/src/plugin.d.ts +352 -0
  30. package/lib/src/plugin.js +1015 -0
  31. package/lib/src/processors.d.ts +62 -0
  32. package/lib/src/processors.js +162 -0
  33. package/lib/src/rest.d.ts +36 -0
  34. package/lib/src/rest.js +46 -0
  35. package/lib/src/server.d.ts +155 -0
  36. package/lib/src/server.js +336 -0
  37. package/lib/src/serving-sanitize.d.ts +104 -0
  38. package/lib/src/serving-sanitize.js +228 -0
  39. package/lib/src/serving.d.ts +61 -0
  40. package/lib/src/serving.js +78 -0
  41. package/lib/src/statement.d.ts +51 -0
  42. package/lib/src/statement.js +83 -0
  43. package/lib/src/storage-schema.d.ts +14 -0
  44. package/lib/src/storage-schema.js +34 -0
  45. package/lib/src/summarize.d.ts +70 -0
  46. package/lib/src/summarize.js +142 -0
  47. package/lib/src/threads.d.ts +109 -0
  48. package/lib/src/threads.js +301 -0
  49. package/lib/src/validation.d.ts +19 -0
  50. package/lib/src/validation.js +17 -0
  51. package/lib/src/workspaces.d.ts +68 -0
  52. package/lib/src/workspaces.js +246 -0
  53. package/lib/src/writer.d.ts +25 -0
  54. package/lib/src/writer.js +40 -0
  55. package/lib/tsconfig.tsbuildinfo +1 -0
  56. package/package.json +17 -13
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Repairs traffic between Mastra / the AI SDK and Databricks Model Serving's
3
+ * OpenAI-compatible `/chat/completions` route, in both directions.
4
+ *
5
+ * Outbound ({@link rewriteServingBody}), because the transcript Mastra
6
+ * persists is not always a transcript the provider will accept back:
7
+ * Databricks-hosted Claude rejects replayed extended-thinking blocks and reads
8
+ * a trailing assistant message as a prefill request.
9
+ *
10
+ * Inbound ({@link rewriteServingResponseBody}), because Databricks-hosted
11
+ * Gemini answers with its native content-parts array where the OpenAI contract
12
+ * (and therefore the AI SDK's response schema) requires a plain string.
13
+ *
14
+ * Every repair here is a provider quirk rather than a schema violation, so all
15
+ * of them are applied on the wire (see the `globalThis.fetch` wrapper in
16
+ * `model.ts`) rather than by changing what the agent stores or what the UI
17
+ * shows.
18
+ *
19
+ * @module
20
+ */
21
+ import { json, string } from "@dbx-tools/shared-core";
22
+ import { openaiChat, openaiResponses, } from "@dbx-tools/shared-model";
23
+ // Shared with the Responses sanitize path so both wire surfaces agree on what
24
+ // counts as a signed reasoning block.
25
+ const REASONING_PART_TYPES = openaiResponses.REASONING_TYPES;
26
+ /**
27
+ * Parse, sanitize, and re-serialize a `/serving-endpoints/...` POST
28
+ * body. Returns the original string verbatim when the body is not
29
+ * JSON or no rewrite was needed.
30
+ */
31
+ export function rewriteServingBody(body) {
32
+ const parsed = json.parseRecord(body);
33
+ if (!parsed)
34
+ return body;
35
+ // Runs regardless of `messages`: Databricks refuses to parse a body carrying
36
+ // an unknown top-level field, so this failure is not specific to a transcript.
37
+ let changed = openaiChat.stripUnsupportedChatFields(parsed).length > 0;
38
+ if (Array.isArray(parsed.messages)) {
39
+ const messages = parsed.messages;
40
+ // Evaluated eagerly, not short-circuited: one transcript can need both
41
+ // reasoning blocks stripped AND a trailing assistant prefill folded back.
42
+ const stripped = stripReasoningFromServingMessages(messages);
43
+ const repaired = repairAssistantPrefill(messages);
44
+ changed = changed || stripped || repaired;
45
+ }
46
+ return changed ? JSON.stringify(parsed) : body;
47
+ }
48
+ /**
49
+ * Drop extended-thinking / reasoning blocks from a replayed transcript.
50
+ *
51
+ * Hybrid Claude endpoints (e.g. Sonnet 4.5+) may emit `reasoning` content
52
+ * parts on the first turn. Mastra persists and replays them on the next
53
+ * agent step, but Databricks-hosted Claude rejects those blocks on
54
+ * multi-turn tool continuations. The UI already captured reasoning for
55
+ * display; stripping here keeps provider replay compatible without
56
+ * changing what users see in the chat bubble.
57
+ */
58
+ export function stripReasoningFromServingMessages(messages) {
59
+ let changed = false;
60
+ for (let i = messages.length - 1; i >= 0; i--) {
61
+ const msg = messages[i];
62
+ if (!msg)
63
+ continue;
64
+ if (msg.role === "reasoning") {
65
+ messages.splice(i, 1);
66
+ changed = true;
67
+ continue;
68
+ }
69
+ if (msg.reasoning !== undefined) {
70
+ delete msg.reasoning;
71
+ changed = true;
72
+ }
73
+ if (msg.reasoning_content !== undefined) {
74
+ delete msg.reasoning_content;
75
+ changed = true;
76
+ }
77
+ if (!Array.isArray(msg.content))
78
+ continue;
79
+ const filtered = msg.content.filter((part) => {
80
+ const type = part?.type;
81
+ if (typeof type === "string" && REASONING_PART_TYPES.has(type)) {
82
+ changed = true;
83
+ return false;
84
+ }
85
+ return true;
86
+ });
87
+ if (filtered.length !== msg.content.length) {
88
+ msg.content = filtered;
89
+ }
90
+ const hasToolCalls = Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;
91
+ if (msg.role === "assistant" && !hasToolCalls && isEmptyServingContent(msg.content)) {
92
+ messages.splice(i, 1);
93
+ changed = true;
94
+ }
95
+ }
96
+ return changed;
97
+ }
98
+ /**
99
+ * Repair a Mastra/AI SDK message replay that Databricks-hosted Claude
100
+ * rejects with `"This model does not support assistant message
101
+ * prefill. The conversation must end with a user message."`.
102
+ *
103
+ * The bug pattern: when an assistant turn streams text *and* a
104
+ * `tool_call`, the AI SDK persists them as two separate assistant
105
+ * entries (text-only and tool-call-only). On the next agent step the
106
+ * tool-call entry is replayed *before* the tool result and the
107
+ * text entry is replayed *after* it, so the conversation ends with a
108
+ * trailing assistant text message. Anthropic interprets that as a
109
+ * prefill request and rejects it on Databricks (the upstream Bedrock
110
+ * route disallows prefill).
111
+ *
112
+ * Fix: when the last message is an assistant text with no `tool_calls`
113
+ * and the chain immediately before it is `assistant(tool_calls=...)`
114
+ * followed only by `tool(...)` results, fold the trailing text back
115
+ * into the `content` of that opening assistant and drop the duplicate.
116
+ */
117
+ export function repairAssistantPrefill(messages) {
118
+ if (messages.length < 2)
119
+ return false;
120
+ const last = messages[messages.length - 1];
121
+ if (!last || last.role !== "assistant" || (last.tool_calls && last.tool_calls.length > 0)) {
122
+ return false;
123
+ }
124
+ let i = messages.length - 2;
125
+ while (i >= 0 && messages[i]?.role === "tool")
126
+ i--;
127
+ if (i < 0)
128
+ return false;
129
+ const opener = messages[i];
130
+ if (!opener ||
131
+ opener.role !== "assistant" ||
132
+ !opener.tool_calls ||
133
+ opener.tool_calls.length === 0) {
134
+ return false;
135
+ }
136
+ const merged = [
137
+ string.trimToNull(textFromServingContent(opener.content)),
138
+ string.trimToNull(textFromServingContent(last.content)),
139
+ ]
140
+ .filter((s) => s !== null)
141
+ .join("\n\n");
142
+ opener.content = merged;
143
+ messages.pop();
144
+ return true;
145
+ }
146
+ /**
147
+ * Flatten content to the prose a human would read: text parts only, separated
148
+ * by blank lines, since the result is spliced into another turn's message body.
149
+ */
150
+ function textFromServingContent(content) {
151
+ return openaiChat.chatContentToText(content, { separator: "\n\n", types: ["text"] });
152
+ }
153
+ /**
154
+ * Whether a turn carries nothing worth replaying. Deliberately stricter than
155
+ * "has no text": a part of any other type (an image, a cache marker) counts as
156
+ * content, so a message holding one is kept even though it has no prose.
157
+ */
158
+ function isEmptyServingContent(content) {
159
+ if (content === undefined)
160
+ return true;
161
+ if (typeof content === "string")
162
+ return content.trim().length === 0;
163
+ if (!Array.isArray(content))
164
+ return true;
165
+ return content.every((part) => {
166
+ if (part?.type === "text") {
167
+ return typeof part.text !== "string" || part.text.trim().length === 0;
168
+ }
169
+ return false;
170
+ });
171
+ }
172
+ /**
173
+ * Parse, sanitize, and re-serialize a `/serving-endpoints/...` non-streaming
174
+ * JSON RESPONSE body. Returns the original string verbatim when the body is
175
+ * not JSON or no rewrite was needed, mirroring
176
+ * {@link rewriteServingBody} on the request side.
177
+ */
178
+ export function rewriteServingResponseBody(body) {
179
+ const parsed = json.parseRecord(body);
180
+ if (!parsed)
181
+ return body;
182
+ return flattenChoiceMessageContent(parsed) ? JSON.stringify(parsed) : body;
183
+ }
184
+ /**
185
+ * Collapse a structured `choices[].message.content` array to the plain string
186
+ * the OpenAI Chat Completions contract specifies.
187
+ *
188
+ * Databricks-hosted Gemini answers a non-streaming `/chat/completions` call
189
+ * with the Gemini-native parts shape:
190
+ *
191
+ * ```json
192
+ * "content": [{ "type": "text", "text": "...", "thoughtSignature": "..." }]
193
+ * ```
194
+ *
195
+ * `@ai-sdk/openai-compatible` validates the response against the OpenAI
196
+ * schema, where `content` is a nullable string, so it throws
197
+ * `Type validation failed: ... expected string, received array` and the whole
198
+ * call fails (`AI_APICallError: Invalid JSON response` on an HTTP 200). Mastra
199
+ * uses `doGenerate` for its side calls, so the visible symptom is
200
+ * `Error generating title` - every thread keeps its placeholder name.
201
+ *
202
+ * Flattening on the wire keeps the repair in one place: the streaming path is
203
+ * unaffected (deltas already carry string content), and neither the agent's
204
+ * stored transcript nor the UI has to know the provider emitted parts. Any
205
+ * non-text part (a `thoughtSignature`-only entry, an inline image) contributes
206
+ * nothing, matching {@link openaiChat.chatContentToText}, and an all-parts-empty
207
+ * message flattens to `""` rather than being dropped, so `finish_reason` and
208
+ * `usage` still round-trip.
209
+ */
210
+ export function flattenChoiceMessageContent(payload) {
211
+ if (!Array.isArray(payload.choices))
212
+ return false;
213
+ let changed = false;
214
+ for (const choice of payload.choices) {
215
+ if (!choice || typeof choice !== "object")
216
+ continue;
217
+ const message = choice.message;
218
+ if (!message || typeof message !== "object")
219
+ continue;
220
+ const target = message;
221
+ if (!Array.isArray(target.content))
222
+ continue;
223
+ target.content = openaiChat.chatContentToText(target.content, { types: ["text"] });
224
+ changed = true;
225
+ }
226
+ return changed;
227
+ }
228
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmluZy1zYW5pdGl6ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aW5nLXNhbml0aXplLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBRUgsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBR0wsVUFBVSxFQUNWLGVBQWUsR0FDaEIsTUFBTSx5QkFBeUIsQ0FBQztBQWVqQyw4RUFBOEU7QUFDOUUsc0NBQXNDO0FBQ3RDLE1BQU0sb0JBQW9CLEdBQUcsZUFBZSxDQUFDLGVBQWUsQ0FBQztBQUU3RDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQixDQUFDLElBQVk7SUFDN0MsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0QyxJQUFJLENBQUMsTUFBTTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBRXpCLDZFQUE2RTtJQUM3RSwrRUFBK0U7SUFDL0UsSUFBSSxPQUFPLEdBQUcsVUFBVSxDQUFDLDBCQUEwQixDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFFdkUsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQ25DLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFnQyxDQUFDO1FBQ3pELHVFQUF1RTtRQUN2RSwwRUFBMEU7UUFDMUUsTUFBTSxRQUFRLEdBQUcsaUNBQWlDLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDN0QsTUFBTSxRQUFRLEdBQUcsc0JBQXNCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbEQsT0FBTyxHQUFHLE9BQU8sSUFBSSxRQUFRLElBQUksUUFBUSxDQUFDO0lBQzVDLENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNB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QU8sS0FBSyxDQUFDO0lBQ2xELElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNwQixLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNyQyxJQUFJLENBQUMsTUFBTSxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVE7WUFBRSxTQUFTO1FBQ3BELE1BQU0sT0FBTyxHQUFJLE1BQWdDLENBQUMsT0FBTyxDQUFDO1FBQzFELElBQUksQ0FBQyxPQUFPLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUTtZQUFFLFNBQVM7UUFDdEQsTUFBTSxNQUFNLEdBQUcsT0FBZ0MsQ0FBQztRQUNoRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO1lBQUUsU0FBUztRQUM3QyxNQUFNLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLE9BQU8sR0FBRyxJQUFJLENBQUM7SUFDakIsQ0FBQztJQUNELE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJlcGFpcnMgdHJhZmZpYyBiZXR3ZWVuIE1hc3RyYSAvIHRoZSBBSSBTREsgYW5kIERhdGFicmlja3MgTW9kZWwgU2VydmluZydzXG4gKiBPcGVuQUktY29tcGF0aWJsZSBgL2NoYXQvY29tcGxldGlvbnNgIHJvdXRlLCBpbiBib3RoIGRpcmVjdGlvbnMuXG4gKlxuICogT3V0Ym91bmQgKHtAbGluayByZXdyaXRlU2VydmluZ0JvZHl9KSwgYmVjYXVzZSB0aGUgdHJhbnNjcmlwdCBNYXN0cmFcbiAqIHBlcnNpc3RzIGlzIG5vdCBhbHdheXMgYSB0cmFuc2NyaXB0IHRoZSBwcm92aWRlciB3aWxsIGFjY2VwdCBiYWNrOlxuICogRGF0YWJyaWNrcy1ob3N0ZWQgQ2xhdWRlIHJlamVjdHMgcmVwbGF5ZWQgZXh0ZW5kZWQtdGhpbmtpbmcgYmxvY2tzIGFuZCByZWFkc1xuICogYSB0cmFpbGluZyBhc3Npc3RhbnQgbWVzc2FnZSBhcyBhIHByZWZpbGwgcmVxdWVzdC5cbiAqXG4gKiBJbmJvdW5kICh7QGxpbmsgcmV3cml0ZVNlcnZpbmdSZXNwb25zZUJvZHl9KSwgYmVjYXVzZSBEYXRhYnJpY2tzLWhvc3RlZFxuICogR2VtaW5pIGFuc3dlcnMgd2l0aCBpdHMgbmF0aXZlIGNvbnRlbnQtcGFydHMgYXJyYXkgd2hlcmUgdGhlIE9wZW5BSSBjb250cmFjdFxuICogKGFuZCB0aGVyZWZvcmUgdGhlIEFJIFNESydzIHJlc3BvbnNlIHNjaGVtYSkgcmVxdWlyZXMgYSBwbGFpbiBzdHJpbmcuXG4gKlxuICogRXZlcnkgcmVwYWlyIGhlcmUgaXMgYSBwcm92aWRlciBxdWlyayByYXRoZXIgdGhhbiBhIHNjaGVtYSB2aW9sYXRpb24sIHNvIGFsbFxuICogb2YgdGhlbSBhcmUgYXBwbGllZCBvbiB0aGUgd2lyZSAoc2VlIHRoZSBgZ2xvYmFsVGhpcy5mZXRjaGAgd3JhcHBlciBpblxuICogYG1vZGVsLnRzYCkgcmF0aGVyIHRoYW4gYnkgY2hhbmdpbmcgd2hhdCB0aGUgYWdlbnQgc3RvcmVzIG9yIHdoYXQgdGhlIFVJXG4gKiBzaG93cy5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsganNvbiwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7XG4gIHR5cGUgQ2hhdE1lc3NhZ2UsXG4gIHR5cGUgQ2hhdFJvbGUsXG4gIG9wZW5haUNoYXQsXG4gIG9wZW5haVJlc3BvbnNlcyxcbn0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsXCI7XG5cbi8qKlxuICogQSBjaGF0IG1lc3NhZ2UgYXMgaXQgYXJyaXZlcyBvbiB0aGUgc2VydmluZyB3aXJlLCBwbHVzIHRoZSBleHRlbmRlZC10aGlua2luZ1xuICogZmllbGRzIERhdGFicmlja3MtaG9zdGVkIENsYXVkZSBhZGRzLiBUaGUgT3BlbkFJLXN0YW5kYXJkIHBhcnQgb2YgdGhlIHNoYXBlXG4gKiBpcyB7QGxpbmsgQ2hhdE1lc3NhZ2V9IGZyb20gYEBkYngtdG9vbHMvc2hhcmVkLW1vZGVsYDsgb25seSB0aGUgcHJvdmlkZXJcbiAqIGV4dGVuc2lvbnMgdGhpcyBtb2R1bGUgc3RyaXBzIGFyZSBkZWNsYXJlZCBoZXJlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZpbmdDaGF0TWVzc2FnZSBleHRlbmRzIENoYXRNZXNzYWdlIHtcbiAgLyoqIE5hcnJvd2VkIHRvIHRoZSByb2xlcyB0aGlzIHJlcGFpciBwYXNzIHJlYXNvbnMgYWJvdXQsIHBsdXMgQ2xhdWRlJ3MgYHJlYXNvbmluZ2AgdHVybi4gKi9cbiAgcm9sZTogQ2hhdFJvbGUgfCBcInJlYXNvbmluZ1wiO1xuICByZWFzb25pbmc/OiB1bmtub3duO1xuICByZWFzb25pbmdfY29udGVudD86IHVua25vd247XG59XG5cbi8vIFNoYXJlZCB3aXRoIHRoZSBSZXNwb25zZXMgc2FuaXRpemUgcGF0aCBzbyBib3RoIHdpcmUgc3VyZmFjZXMgYWdyZWUgb24gd2hhdFxuLy8gY291bnRzIGFzIGEgc2lnbmVkIHJlYXNvbmluZyBibG9jay5cbmNvbnN0IFJFQVNPTklOR19QQVJUX1RZUEVTID0gb3BlbmFpUmVzcG9uc2VzLlJFQVNPTklOR19UWVBFUztcblxuLyoqXG4gKiBQYXJzZSwgc2FuaXRpemUsIGFuZCByZS1zZXJpYWxpemUgYSBgL3NlcnZpbmctZW5kcG9pbnRzLy4uLmAgUE9TVFxuICogYm9keS4gUmV0dXJucyB0aGUgb3JpZ2luYWwgc3RyaW5nIHZlcmJhdGltIHdoZW4gdGhlIGJvZHkgaXMgbm90XG4gKiBKU09OIG9yIG5vIHJld3JpdGUgd2FzIG5lZWRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJld3JpdGVTZXJ2aW5nQm9keShib2R5OiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBwYXJzZWQgPSBqc29uLnBhcnNlUmVjb3JkKGJvZHkpO1xuICBpZiAoIXBhcnNlZCkgcmV0dXJuIGJvZHk7XG5cbiAgLy8gUnVucyByZWdhcmRsZXNzIG9mIGBtZXNzYWdlc2A6IERhdGFicmlja3MgcmVmdXNlcyB0byBwYXJzZSBhIGJvZHkgY2FycnlpbmdcbiAgLy8gYW4gdW5rbm93biB0b3AtbGV2ZWwgZmllbGQsIHNvIHRoaXMgZmFpbHVyZSBpcyBub3Qgc3BlY2lmaWMgdG8gYSB0cmFuc2NyaXB0LlxuICBsZXQgY2hhbmdlZCA9IG9wZW5haUNoYXQuc3RyaXBVbnN1cHBvcnRlZENoYXRGaWVsZHMocGFyc2VkKS5sZW5ndGggPiAwO1xuXG4gIGlmIChBcnJheS5pc0FycmF5KHBhcnNlZC5tZXNzYWdlcykpIHtcbiAgICBjb25zdCBtZXNzYWdlcyA9IHBhcnNlZC5tZXNzYWdlcyBhcyBTZXJ2aW5nQ2hhdE1lc3NhZ2VbXTtcbiAgICAvLyBFdmFsdWF0ZWQgZWFnZXJseSwgbm90IHNob3J0LWNpcmN1aXRlZDogb25lIHRyYW5zY3JpcHQgY2FuIG5lZWQgYm90aFxuICAgIC8vIHJlYXNvbmluZyBibG9ja3Mgc3RyaXBwZWQgQU5EIGEgdHJhaWxpbmcgYXNzaXN0YW50IHByZWZpbGwgZm9sZGVkIGJhY2suXG4gICAgY29uc3Qgc3RyaXBwZWQgPSBzdHJpcFJlYXNvbmluZ0Zyb21TZXJ2aW5nTWVzc2FnZXMobWVzc2FnZXMpO1xuICAgIGNvbnN0IHJlcGFpcmVkID0gcmVwYWlyQXNzaXN0YW50UHJlZmlsbChtZXNzYWdlcyk7XG4gICAgY2hhbmdlZCA9IGNoYW5nZWQgfHwgc3RyaXBwZWQgfHwgcmVwYWlyZWQ7XG4gIH1cblxuICByZXR1cm4gY2hhbmdlZCA/IEpTT04uc3RyaW5naWZ5KHBhcnNlZCkgOiBib2R5O1xufVxuXG4vKipcbiAqIERyb3AgZXh0ZW5kZWQtdGhpbmtpbmcgLyByZWFzb25pbmcgYmxvY2tzIGZyb20gYSByZXBsYXllZCB0cmFuc2NyaXB0LlxuICpcbiAqIEh5YnJpZCBDbGF1ZGUgZW5kcG9pbnRzIChlLmcuIFNvbm5ldCA0LjUrKSBtYXkgZW1pdCBgcmVhc29uaW5nYCBjb250ZW50XG4gKiBwYXJ0cyBvbiB0aGUgZmlyc3QgdHVybi4gTWFzdHJhIHBlcnNpc3RzIGFuZCByZXBsYXlzIHRoZW0gb24gdGhlIG5leHRcbiAqIGFnZW50IHN0ZXAsIGJ1dCBEYXRhYnJpY2tzLWhvc3RlZCBDbGF1ZGUgcmVqZWN0cyB0aG9zZSBibG9ja3Mgb25cbiAqIG11bHRpLXR1cm4gdG9vbCBjb250aW51YXRpb25zLiBUaGUgVUkgYWxyZWFkeSBjYXB0dXJlZCByZWFzb25pbmcgZm9yXG4gKiBkaXNwbGF5OyBzdHJpcHBpbmcgaGVyZSBrZWVwcyBwcm92aWRlciByZXBsYXkgY29tcGF0aWJsZSB3aXRob3V0XG4gKiBjaGFuZ2luZyB3aGF0IHVzZXJzIHNlZSBpbiB0aGUgY2hhdCBidWJibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdHJpcFJlYXNvbmluZ0Zyb21TZXJ2aW5nTWVzc2FnZXMobWVzc2FnZXM6IFNlcnZpbmdDaGF0TWVzc2FnZVtdKTogYm9vbGVhbiB7XG4gIGxldCBjaGFuZ2VkID0gZmFsc2U7XG4gIGZvciAobGV0IGkgPSBtZXNzYWdlcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIGNvbnN0IG1zZyA9IG1lc3NhZ2VzW2ldO1xuICAgIGlmICghbXNnKSBjb250aW51ZTtcbiAgICBpZiAobXNnLnJvbGUgPT09IFwicmVhc29uaW5nXCIpIHtcbiAgICAgIG1lc3NhZ2VzLnNwbGljZShpLCAxKTtcbiAgICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGlmIChtc2cucmVhc29uaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGRlbGV0ZSBtc2cucmVhc29uaW5nO1xuICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgfVxuICAgIGlmIChtc2cucmVhc29uaW5nX2NvbnRlbnQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZGVsZXRlIG1zZy5yZWFzb25pbmdfY29udGVudDtcbiAgICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgIH1cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkobXNnLmNvbnRlbnQpKSBjb250aW51ZTtcbiAgICBjb25zdCBmaWx0ZXJlZCA9IG1zZy5jb250ZW50LmZpbHRlcigocGFydCkgPT4ge1xuICAgICAgY29uc3QgdHlwZSA9IHBhcnQ/LnR5cGU7XG4gICAgICBpZiAodHlwZW9mIHR5cGUgPT09IFwic3RyaW5nXCIgJiYgUkVBU09OSU5HX1BBUlRfVFlQRVMuaGFzKHR5cGUpKSB7XG4gICAgICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbiAgICBpZiAoZmlsdGVyZWQubGVuZ3RoICE9PSBtc2cuY29udGVudC5sZW5ndGgpIHtcbiAgICAgIG1zZy5jb250ZW50ID0gZmlsdGVyZWQ7XG4gICAgfVxuICAgIGNvbnN0IGhhc1Rvb2xDYWxscyA9IEFycmF5LmlzQXJyYXkobXNnLnRvb2xfY2FsbHMpICYmIG1zZy50b29sX2NhbGxzLmxlbmd0aCA+IDA7XG4gICAgaWYgKG1zZy5yb2xlID09PSBcImFzc2lzdGFudFwiICYmICFoYXNUb29sQ2FsbHMgJiYgaXNFbXB0eVNlcnZpbmdDb250ZW50KG1zZy5jb250ZW50KSkge1xuICAgICAgbWVzc2FnZXMuc3BsaWNlKGksIDEpO1xuICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgfVxuICB9XG4gIHJldHVybiBjaGFuZ2VkO1xufVxuXG4vKipcbiAqIFJlcGFpciBhIE1hc3RyYS9BSSBTREsgbWVzc2FnZSByZXBsYXkgdGhhdCBEYXRhYnJpY2tzLWhvc3RlZCBDbGF1ZGVcbiAqIHJlamVjdHMgd2l0aCBgXCJUaGlzIG1vZGVsIGRvZXMgbm90IHN1cHBvcnQgYXNzaXN0YW50IG1lc3NhZ2VcbiAqIHByZWZpbGwuIFRoZSBjb252ZXJzYXRpb24gbXVzdCBlbmQgd2l0aCBhIHVzZXIgbWVzc2FnZS5cImAuXG4gKlxuICogVGhlIGJ1ZyBwYXR0ZXJuOiB3aGVuIGFuIGFzc2lzdGFudCB0dXJuIHN0cmVhbXMgdGV4dCAqYW5kKiBhXG4gKiBgdG9vbF9jYWxsYCwgdGhlIEFJIFNESyBwZXJzaXN0cyB0aGVtIGFzIHR3byBzZXBhcmF0ZSBhc3Npc3RhbnRcbiAqIGVudHJpZXMgKHRleHQtb25seSBhbmQgdG9vbC1jYWxsLW9ubHkpLiBPbiB0aGUgbmV4dCBhZ2VudCBzdGVwIHRoZVxuICogdG9vbC1jYWxsIGVudHJ5IGlzIHJlcGxheWVkICpiZWZvcmUqIHRoZSB0b29sIHJlc3VsdCBhbmQgdGhlXG4gKiB0ZXh0IGVudHJ5IGlzIHJlcGxheWVkICphZnRlciogaXQsIHNvIHRoZSBjb252ZXJzYXRpb24gZW5kcyB3aXRoIGFcbiAqIHRyYWlsaW5nIGFzc2lzdGFudCB0ZXh0IG1lc3NhZ2UuIEFudGhyb3BpYyBpbnRlcnByZXRzIHRoYXQgYXMgYVxuICogcHJlZmlsbCByZXF1ZXN0IGFuZCByZWplY3RzIGl0IG9uIERhdGFicmlja3MgKHRoZSB1cHN0cmVhbSBCZWRyb2NrXG4gKiByb3V0ZSBkaXNhbGxvd3MgcHJlZmlsbCkuXG4gKlxuICogRml4OiB3aGVuIHRoZSBsYXN0IG1lc3NhZ2UgaXMgYW4gYXNzaXN0YW50IHRleHQgd2l0aCBubyBgdG9vbF9jYWxsc2BcbiAqIGFuZCB0aGUgY2hhaW4gaW1tZWRpYXRlbHkgYmVmb3JlIGl0IGlzIGBhc3Npc3RhbnQodG9vbF9jYWxscz0uLi4pYFxuICogZm9sbG93ZWQgb25seSBieSBgdG9vbCguLi4pYCByZXN1bHRzLCBmb2xkIHRoZSB0cmFpbGluZyB0ZXh0IGJhY2tcbiAqIGludG8gdGhlIGBjb250ZW50YCBvZiB0aGF0IG9wZW5pbmcgYXNzaXN0YW50IGFuZCBkcm9wIHRoZSBkdXBsaWNhdGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXBhaXJBc3Npc3RhbnRQcmVmaWxsKG1lc3NhZ2VzOiBTZXJ2aW5nQ2hhdE1lc3NhZ2VbXSk6IGJvb2xlYW4ge1xuICBpZiAobWVzc2FnZXMubGVuZ3RoIDwgMikgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBsYXN0ID0gbWVzc2FnZXNbbWVzc2FnZXMubGVuZ3RoIC0gMV07XG4gIGlmICghbGFzdCB8fCBsYXN0LnJvbGUgIT09IFwiYXNzaXN0YW50XCIgfHwgKGxhc3QudG9vbF9jYWxscyAmJiBsYXN0LnRvb2xfY2FsbHMubGVuZ3RoID4gMCkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBsZXQgaSA9IG1lc3NhZ2VzLmxlbmd0aCAtIDI7XG4gIHdoaWxlIChpID49IDAgJiYgbWVzc2FnZXNbaV0/LnJvbGUgPT09IFwidG9vbFwiKSBpLS07XG4gIGlmIChpIDwgMCkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBvcGVuZXIgPSBtZXNzYWdlc1tpXTtcbiAgaWYgKFxuICAgICFvcGVuZXIgfHxcbiAgICBvcGVuZXIucm9sZSAhPT0gXCJhc3Npc3RhbnRcIiB8fFxuICAgICFvcGVuZXIudG9vbF9jYWxscyB8fFxuICAgIG9wZW5lci50b29sX2NhbGxzLmxlbmd0aCA9PT0gMFxuICApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBtZXJnZWQgPSBbXG4gICAgc3RyaW5nLnRyaW1Ub051bGwodGV4dEZyb21TZXJ2aW5nQ29udGVudChvcGVuZXIuY29udGVudCkpLFxuICAgIHN0cmluZy50cmltVG9OdWxsKHRleHRGcm9tU2VydmluZ0NvbnRlbnQobGFzdC5jb250ZW50KSksXG4gIF1cbiAgICAuZmlsdGVyKChzKTogcyBpcyBzdHJpbmcgPT4gcyAhPT0gbnVsbClcbiAgICAuam9pbihcIlxcblxcblwiKTtcbiAgb3BlbmVyLmNvbnRlbnQgPSBtZXJnZWQ7XG4gIG1lc3NhZ2VzLnBvcCgpO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBGbGF0dGVuIGNvbnRlbnQgdG8gdGhlIHByb3NlIGEgaHVtYW4gd291bGQgcmVhZDogdGV4dCBwYXJ0cyBvbmx5LCBzZXBhcmF0ZWRcbiAqIGJ5IGJsYW5rIGxpbmVzLCBzaW5jZSB0aGUgcmVzdWx0IGlzIHNwbGljZWQgaW50byBhbm90aGVyIHR1cm4ncyBtZXNzYWdlIGJvZHkuXG4gKi9cbmZ1bmN0aW9uIHRleHRGcm9tU2VydmluZ0NvbnRlbnQoY29udGVudDogU2VydmluZ0NoYXRNZXNzYWdlW1wiY29udGVudFwiXSk6IHN0cmluZyB7XG4gIHJldHVybiBvcGVuYWlDaGF0LmNoYXRDb250ZW50VG9UZXh0KGNvbnRlbnQsIHsgc2VwYXJhdG9yOiBcIlxcblxcblwiLCB0eXBlczogW1widGV4dFwiXSB9KTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGEgdHVybiBjYXJyaWVzIG5vdGhpbmcgd29ydGggcmVwbGF5aW5nLiBEZWxpYmVyYXRlbHkgc3RyaWN0ZXIgdGhhblxuICogXCJoYXMgbm8gdGV4dFwiOiBhIHBhcnQgb2YgYW55IG90aGVyIHR5cGUgKGFuIGltYWdlLCBhIGNhY2hlIG1hcmtlcikgY291bnRzIGFzXG4gKiBjb250ZW50LCBzbyBhIG1lc3NhZ2UgaG9sZGluZyBvbmUgaXMga2VwdCBldmVuIHRob3VnaCBpdCBoYXMgbm8gcHJvc2UuXG4gKi9cbmZ1bmN0aW9uIGlzRW1wdHlTZXJ2aW5nQ29udGVudChjb250ZW50OiBTZXJ2aW5nQ2hhdE1lc3NhZ2VbXCJjb250ZW50XCJdKTogYm9vbGVhbiB7XG4gIGlmIChjb250ZW50ID09PSB1bmRlZmluZWQpIHJldHVybiB0cnVlO1xuICBpZiAodHlwZW9mIGNvbnRlbnQgPT09IFwic3RyaW5nXCIpIHJldHVybiBjb250ZW50LnRyaW0oKS5sZW5ndGggPT09IDA7XG4gIGlmICghQXJyYXkuaXNBcnJheShjb250ZW50KSkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBjb250ZW50LmV2ZXJ5KChwYXJ0KSA9PiB7XG4gICAgaWYgKHBhcnQ/LnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICByZXR1cm4gdHlwZW9mIHBhcnQudGV4dCAhPT0gXCJzdHJpbmdcIiB8fCBwYXJ0LnRleHQudHJpbSgpLmxlbmd0aCA9PT0gMDtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9KTtcbn1cblxuLyoqXG4gKiBQYXJzZSwgc2FuaXRpemUsIGFuZCByZS1zZXJpYWxpemUgYSBgL3NlcnZpbmctZW5kcG9pbnRzLy4uLmAgbm9uLXN0cmVhbWluZ1xuICogSlNPTiBSRVNQT05TRSBib2R5LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBzdHJpbmcgdmVyYmF0aW0gd2hlbiB0aGUgYm9keSBpc1xuICogbm90IEpTT04gb3Igbm8gcmV3cml0ZSB3YXMgbmVlZGVkLCBtaXJyb3JpbmdcbiAqIHtAbGluayByZXdyaXRlU2VydmluZ0JvZHl9IG9uIHRoZSByZXF1ZXN0IHNpZGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXdyaXRlU2VydmluZ1Jlc3BvbnNlQm9keShib2R5OiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBwYXJzZWQgPSBqc29uLnBhcnNlUmVjb3JkKGJvZHkpO1xuICBpZiAoIXBhcnNlZCkgcmV0dXJuIGJvZHk7XG4gIHJldHVybiBmbGF0dGVuQ2hvaWNlTWVzc2FnZUNvbnRlbnQocGFyc2VkKSA/IEpTT04uc3RyaW5naWZ5KHBhcnNlZCkgOiBib2R5O1xufVxuXG4vKipcbiAqIENvbGxhcHNlIGEgc3RydWN0dXJlZCBgY2hvaWNlc1tdLm1lc3NhZ2UuY29udGVudGAgYXJyYXkgdG8gdGhlIHBsYWluIHN0cmluZ1xuICogdGhlIE9wZW5BSSBDaGF0IENvbXBsZXRpb25zIGNvbnRyYWN0IHNwZWNpZmllcy5cbiAqXG4gKiBEYXRhYnJpY2tzLWhvc3RlZCBHZW1pbmkgYW5zd2VycyBhIG5vbi1zdHJlYW1pbmcgYC9jaGF0L2NvbXBsZXRpb25zYCBjYWxsXG4gKiB3aXRoIHRoZSBHZW1pbmktbmF0aXZlIHBhcnRzIHNoYXBlOlxuICpcbiAqIGBgYGpzb25cbiAqIFwiY29udGVudFwiOiBbeyBcInR5cGVcIjogXCJ0ZXh0XCIsIFwidGV4dFwiOiBcIi4uLlwiLCBcInRob3VnaHRTaWduYXR1cmVcIjogXCIuLi5cIiB9XVxuICogYGBgXG4gKlxuICogYEBhaS1zZGsvb3BlbmFpLWNvbXBhdGlibGVgIHZhbGlkYXRlcyB0aGUgcmVzcG9uc2UgYWdhaW5zdCB0aGUgT3BlbkFJXG4gKiBzY2hlbWEsIHdoZXJlIGBjb250ZW50YCBpcyBhIG51bGxhYmxlIHN0cmluZywgc28gaXQgdGhyb3dzXG4gKiBgVHlwZSB2YWxpZGF0aW9uIGZhaWxlZDogLi4uIGV4cGVjdGVkIHN0cmluZywgcmVjZWl2ZWQgYXJyYXlgIGFuZCB0aGUgd2hvbGVcbiAqIGNhbGwgZmFpbHMgKGBBSV9BUElDYWxsRXJyb3I6IEludmFsaWQgSlNPTiByZXNwb25zZWAgb24gYW4gSFRUUCAyMDApLiBNYXN0cmFcbiAqIHVzZXMgYGRvR2VuZXJhdGVgIGZvciBpdHMgc2lkZSBjYWxscywgc28gdGhlIHZpc2libGUgc3ltcHRvbSBpc1xuICogYEVycm9yIGdlbmVyYXRpbmcgdGl0bGVgIC0gZXZlcnkgdGhyZWFkIGtlZXBzIGl0cyBwbGFjZWhvbGRlciBuYW1lLlxuICpcbiAqIEZsYXR0ZW5pbmcgb24gdGhlIHdpcmUga2VlcHMgdGhlIHJlcGFpciBpbiBvbmUgcGxhY2U6IHRoZSBzdHJlYW1pbmcgcGF0aCBpc1xuICogdW5hZmZlY3RlZCAoZGVsdGFzIGFscmVhZHkgY2Fycnkgc3RyaW5nIGNvbnRlbnQpLCBhbmQgbmVpdGhlciB0aGUgYWdlbnQnc1xuICogc3RvcmVkIHRyYW5zY3JpcHQgbm9yIHRoZSBVSSBoYXMgdG8ga25vdyB0aGUgcHJvdmlkZXIgZW1pdHRlZCBwYXJ0cy4gQW55XG4gKiBub24tdGV4dCBwYXJ0IChhIGB0aG91Z2h0U2lnbmF0dXJlYC1vbmx5IGVudHJ5LCBhbiBpbmxpbmUgaW1hZ2UpIGNvbnRyaWJ1dGVzXG4gKiBub3RoaW5nLCBtYXRjaGluZyB7QGxpbmsgb3BlbmFpQ2hhdC5jaGF0Q29udGVudFRvVGV4dH0sIGFuZCBhbiBhbGwtcGFydHMtZW1wdHlcbiAqIG1lc3NhZ2UgZmxhdHRlbnMgdG8gYFwiXCJgIHJhdGhlciB0aGFuIGJlaW5nIGRyb3BwZWQsIHNvIGBmaW5pc2hfcmVhc29uYCBhbmRcbiAqIGB1c2FnZWAgc3RpbGwgcm91bmQtdHJpcC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZsYXR0ZW5DaG9pY2VNZXNzYWdlQ29udGVudChwYXlsb2FkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IGJvb2xlYW4ge1xuICBpZiAoIUFycmF5LmlzQXJyYXkocGF5bG9hZC5jaG9pY2VzKSkgcmV0dXJuIGZhbHNlO1xuICBsZXQgY2hhbmdlZCA9IGZhbHNlO1xuICBmb3IgKGNvbnN0IGNob2ljZSBvZiBwYXlsb2FkLmNob2ljZXMpIHtcbiAgICBpZiAoIWNob2ljZSB8fCB0eXBlb2YgY2hvaWNlICE9PSBcIm9iamVjdFwiKSBjb250aW51ZTtcbiAgICBjb25zdCBtZXNzYWdlID0gKGNob2ljZSBhcyB7IG1lc3NhZ2U/OiB1bmtub3duIH0pLm1lc3NhZ2U7XG4gICAgaWYgKCFtZXNzYWdlIHx8IHR5cGVvZiBtZXNzYWdlICE9PSBcIm9iamVjdFwiKSBjb250aW51ZTtcbiAgICBjb25zdCB0YXJnZXQgPSBtZXNzYWdlIGFzIHsgY29udGVudD86IHVua25vd24gfTtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkodGFyZ2V0LmNvbnRlbnQpKSBjb250aW51ZTtcbiAgICB0YXJnZXQuY29udGVudCA9IG9wZW5haUNoYXQuY2hhdENvbnRlbnRUb1RleHQodGFyZ2V0LmNvbnRlbnQsIHsgdHlwZXM6IFtcInRleHRcIl0gfSk7XG4gICAgY2hhbmdlZCA9IHRydWU7XG4gIH1cbiAgcmV0dXJuIGNoYW5nZWQ7XG59XG4iXX0=
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Mastra-specific glue over the generic `@dbx-tools/model` toolkit.
3
+ *
4
+ * The live `/serving-endpoints` catalogue access, fuzzy name
5
+ * resolution, and class/fallback selection all live in
6
+ * `@dbx-tools/model`; this module only adds what is specific to the
7
+ * Mastra plugin: pulling a per-request model override off an HTTP
8
+ * request (header / query / body) and projecting the plugin config
9
+ * onto the knobs `buildModel` and the `/models` route share.
10
+ *
11
+ * @module
12
+ */
13
+ import type { MastraPluginConfig } from "./config.js";
14
+ /**
15
+ * `RequestContext` key under which {@link MastraServer} stores the
16
+ * per-request model override (header / query / body). `model.ts`
17
+ * reads it before falling back to the agent / plugin default.
18
+ */
19
+ export declare const MASTRA_MODEL_OVERRIDE_KEY = "mastra__model_override";
20
+ /**
21
+ * Minimal Express-ish request shape used by {@link extractModelOverride}.
22
+ * Keeps this module independent of `express` so the helper can be
23
+ * reused from non-Express adapters.
24
+ */
25
+ export interface ModelOverrideRequest {
26
+ headers?: Record<string, string | string[] | undefined>;
27
+ query?: Record<string, unknown> | undefined;
28
+ body?: unknown;
29
+ }
30
+ /**
31
+ * Pull a model override out of a single HTTP request, checking
32
+ * sources in priority order:
33
+ *
34
+ * 1. `X-Mastra-Model` header
35
+ * 2. `?model=` query string parameter
36
+ * 3. Body field (`model` or `modelId`, in that order)
37
+ *
38
+ * Returns `null` when nothing is set, so callers can wrap with
39
+ * `if (override) ...` without juggling empty strings. Body inspection
40
+ * is lenient - any plain object with one of the configured keys
41
+ * counts, mirroring how AI SDK chat clients pass arbitrary metadata
42
+ * alongside `messages`.
43
+ */
44
+ export declare function extractModelOverride(req: ModelOverrideRequest): string | null;
45
+ /**
46
+ * Read the fuzzy-resolution config knobs off the plugin config with
47
+ * `@dbx-tools/model` defaults applied. Kept here so `buildModel` and
48
+ * the `/models` route agree on what "enabled" means.
49
+ *
50
+ * `fallbacks` is the priority-ordered list `resolveModel` walks first
51
+ * when nothing explicit is set; defaults to an empty list so the
52
+ * generic resolver falls through to the live catalogue and its own
53
+ * `FALLBACK_MODEL_IDS` floor.
54
+ */
55
+ export declare function resolveServingConfig(config: MastraPluginConfig): {
56
+ ttlMs: number;
57
+ threshold: number;
58
+ fuzzy: boolean;
59
+ allowOverride: boolean;
60
+ fallbacks: readonly string[];
61
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Mastra-specific glue over the generic `@dbx-tools/model` toolkit.
3
+ *
4
+ * The live `/serving-endpoints` catalogue access, fuzzy name
5
+ * resolution, and class/fallback selection all live in
6
+ * `@dbx-tools/model`; this module only adds what is specific to the
7
+ * Mastra plugin: pulling a per-request model override off an HTTP
8
+ * request (header / query / body) and projecting the plugin config
9
+ * onto the knobs `buildModel` and the `/models` route share.
10
+ *
11
+ * @module
12
+ */
13
+ import { serving as nodeServing } from "@dbx-tools/model";
14
+ import { string } from "@dbx-tools/shared-core";
15
+ import { override } from "@dbx-tools/shared-mastra";
16
+ /**
17
+ * `RequestContext` key under which {@link MastraServer} stores the
18
+ * per-request model override (header / query / body). `model.ts`
19
+ * reads it before falling back to the agent / plugin default.
20
+ */
21
+ export const MASTRA_MODEL_OVERRIDE_KEY = "mastra__model_override";
22
+ /**
23
+ * Pull a model override out of a single HTTP request, checking
24
+ * sources in priority order:
25
+ *
26
+ * 1. `X-Mastra-Model` header
27
+ * 2. `?model=` query string parameter
28
+ * 3. Body field (`model` or `modelId`, in that order)
29
+ *
30
+ * Returns `null` when nothing is set, so callers can wrap with
31
+ * `if (override) ...` without juggling empty strings. Body inspection
32
+ * is lenient - any plain object with one of the configured keys
33
+ * counts, mirroring how AI SDK chat clients pass arbitrary metadata
34
+ * alongside `messages`.
35
+ */
36
+ export function extractModelOverride(req) {
37
+ const headers = req.headers;
38
+ if (headers) {
39
+ const headerVal = string.firstNonEmpty(headers[override.MODEL_OVERRIDE_HEADER] ??
40
+ headers[override.MODEL_OVERRIDE_HEADER.toLowerCase()]);
41
+ if (headerVal)
42
+ return headerVal;
43
+ }
44
+ if (req.query) {
45
+ const queryVal = string.firstNonEmpty(req.query[override.MODEL_OVERRIDE_QUERY]);
46
+ if (queryVal)
47
+ return queryVal;
48
+ }
49
+ if (req.body && typeof req.body === "object") {
50
+ const record = req.body;
51
+ for (const field of override.MODEL_OVERRIDE_BODY_FIELDS) {
52
+ const bodyVal = string.firstNonEmpty(record[field]);
53
+ if (bodyVal)
54
+ return bodyVal;
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ /**
60
+ * Read the fuzzy-resolution config knobs off the plugin config with
61
+ * `@dbx-tools/model` defaults applied. Kept here so `buildModel` and
62
+ * the `/models` route agree on what "enabled" means.
63
+ *
64
+ * `fallbacks` is the priority-ordered list `resolveModel` walks first
65
+ * when nothing explicit is set; defaults to an empty list so the
66
+ * generic resolver falls through to the live catalogue and its own
67
+ * `FALLBACK_MODEL_IDS` floor.
68
+ */
69
+ export function resolveServingConfig(config) {
70
+ return {
71
+ ttlMs: config.modelCacheTtlMs ?? nodeServing.DEFAULT_MODEL_CACHE_TTL_MS,
72
+ threshold: config.modelFuzzyThreshold ?? nodeServing.DEFAULT_FUZZY_THRESHOLD,
73
+ fuzzy: config.modelFuzzyMatch !== false,
74
+ allowOverride: config.modelOverride !== false,
75
+ fallbacks: config.defaultModelFallbacks ?? [],
76
+ };
77
+ }
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7OztHQVdHO0FBRUgsT0FBTyxFQUFFLE9BQU8sSUFBSSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBSXBEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyx3QkFBd0IsQ0FBQztBQWFsRTs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLEdBQXlCO0lBQzVELE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUM7SUFDNUIsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUNaLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQ3BDLE9BQU8sQ0FBQyxRQUFRLENBQUMscUJBQXFCLENBQUM7WUFDckMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUN4RCxDQUFDO1FBQ0YsSUFBSSxTQUFTO1lBQUUsT0FBTyxTQUFTLENBQUM7SUFDbEMsQ0FBQztJQUNELElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2QsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUM7UUFDaEYsSUFBSSxRQUFRO1lBQUUsT0FBTyxRQUFRLENBQUM7SUFDaEMsQ0FBQztJQUNELElBQUksR0FBRyxDQUFDLElBQUksSUFBSSxPQUFPLEdBQUcsQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDN0MsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQStCLENBQUM7UUFDbkQsS0FBSyxNQUFNLEtBQUssSUFBSSxRQUFRLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztZQUN4RCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ3BELElBQUksT0FBTztnQkFBRSxPQUFPLE9BQU8sQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxNQUEwQjtJQU83RCxPQUFPO1FBQ0wsS0FBSyxFQUFFLE1BQU0sQ0FBQyxlQUFlLElBQUksV0FBVyxDQUFDLDBCQUEwQjtRQUN2RSxTQUFTLEVBQUUsTUFBTSxDQUFDLG1CQUFtQixJQUFJLFdBQVcsQ0FBQyx1QkFBdUI7UUFDNUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxlQUFlLEtBQUssS0FBSztRQUN2QyxhQUFhLEVBQUUsTUFBTSxDQUFDLGFBQWEsS0FBSyxLQUFLO1FBQzdDLFNBQVMsRUFBRSxNQUFNLENBQUMscUJBQXFCLElBQUksRUFBRTtLQUM5QyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTWFzdHJhLXNwZWNpZmljIGdsdWUgb3ZlciB0aGUgZ2VuZXJpYyBgQGRieC10b29scy9tb2RlbGAgdG9vbGtpdC5cbiAqXG4gKiBUaGUgbGl2ZSBgL3NlcnZpbmctZW5kcG9pbnRzYCBjYXRhbG9ndWUgYWNjZXNzLCBmdXp6eSBuYW1lXG4gKiByZXNvbHV0aW9uLCBhbmQgY2xhc3MvZmFsbGJhY2sgc2VsZWN0aW9uIGFsbCBsaXZlIGluXG4gKiBgQGRieC10b29scy9tb2RlbGA7IHRoaXMgbW9kdWxlIG9ubHkgYWRkcyB3aGF0IGlzIHNwZWNpZmljIHRvIHRoZVxuICogTWFzdHJhIHBsdWdpbjogcHVsbGluZyBhIHBlci1yZXF1ZXN0IG1vZGVsIG92ZXJyaWRlIG9mZiBhbiBIVFRQXG4gKiByZXF1ZXN0IChoZWFkZXIgLyBxdWVyeSAvIGJvZHkpIGFuZCBwcm9qZWN0aW5nIHRoZSBwbHVnaW4gY29uZmlnXG4gKiBvbnRvIHRoZSBrbm9icyBgYnVpbGRNb2RlbGAgYW5kIHRoZSBgL21vZGVsc2Agcm91dGUgc2hhcmUuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IHNlcnZpbmcgYXMgbm9kZVNlcnZpbmcgfSBmcm9tIFwiQGRieC10b29scy9tb2RlbFwiO1xuaW1wb3J0IHsgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IG92ZXJyaWRlIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1hc3RyYVwiO1xuXG5pbXBvcnQgdHlwZSB7IE1hc3RyYVBsdWdpbkNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuXG4vKipcbiAqIGBSZXF1ZXN0Q29udGV4dGAga2V5IHVuZGVyIHdoaWNoIHtAbGluayBNYXN0cmFTZXJ2ZXJ9IHN0b3JlcyB0aGVcbiAqIHBlci1yZXF1ZXN0IG1vZGVsIG92ZXJyaWRlIChoZWFkZXIgLyBxdWVyeSAvIGJvZHkpLiBgbW9kZWwudHNgXG4gKiByZWFkcyBpdCBiZWZvcmUgZmFsbGluZyBiYWNrIHRvIHRoZSBhZ2VudCAvIHBsdWdpbiBkZWZhdWx0LlxuICovXG5leHBvcnQgY29uc3QgTUFTVFJBX01PREVMX09WRVJSSURFX0tFWSA9IFwibWFzdHJhX19tb2RlbF9vdmVycmlkZVwiO1xuXG4vKipcbiAqIE1pbmltYWwgRXhwcmVzcy1pc2ggcmVxdWVzdCBzaGFwZSB1c2VkIGJ5IHtAbGluayBleHRyYWN0TW9kZWxPdmVycmlkZX0uXG4gKiBLZWVwcyB0aGlzIG1vZHVsZSBpbmRlcGVuZGVudCBvZiBgZXhwcmVzc2Agc28gdGhlIGhlbHBlciBjYW4gYmVcbiAqIHJldXNlZCBmcm9tIG5vbi1FeHByZXNzIGFkYXB0ZXJzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1vZGVsT3ZlcnJpZGVSZXF1ZXN0IHtcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkPjtcbiAgcXVlcnk/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbiAgYm9keT86IHVua25vd247XG59XG5cbi8qKlxuICogUHVsbCBhIG1vZGVsIG92ZXJyaWRlIG91dCBvZiBhIHNpbmdsZSBIVFRQIHJlcXVlc3QsIGNoZWNraW5nXG4gKiBzb3VyY2VzIGluIHByaW9yaXR5IG9yZGVyOlxuICpcbiAqICAgMS4gYFgtTWFzdHJhLU1vZGVsYCBoZWFkZXJcbiAqICAgMi4gYD9tb2RlbD1gIHF1ZXJ5IHN0cmluZyBwYXJhbWV0ZXJcbiAqICAgMy4gQm9keSBmaWVsZCAoYG1vZGVsYCBvciBgbW9kZWxJZGAsIGluIHRoYXQgb3JkZXIpXG4gKlxuICogUmV0dXJucyBgbnVsbGAgd2hlbiBub3RoaW5nIGlzIHNldCwgc28gY2FsbGVycyBjYW4gd3JhcCB3aXRoXG4gKiBgaWYgKG92ZXJyaWRlKSAuLi5gIHdpdGhvdXQganVnZ2xpbmcgZW1wdHkgc3RyaW5ncy4gQm9keSBpbnNwZWN0aW9uXG4gKiBpcyBsZW5pZW50IC0gYW55IHBsYWluIG9iamVjdCB3aXRoIG9uZSBvZiB0aGUgY29uZmlndXJlZCBrZXlzXG4gKiBjb3VudHMsIG1pcnJvcmluZyBob3cgQUkgU0RLIGNoYXQgY2xpZW50cyBwYXNzIGFyYml0cmFyeSBtZXRhZGF0YVxuICogYWxvbmdzaWRlIGBtZXNzYWdlc2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0TW9kZWxPdmVycmlkZShyZXE6IE1vZGVsT3ZlcnJpZGVSZXF1ZXN0KTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IGhlYWRlcnMgPSByZXEuaGVhZGVycztcbiAgaWYgKGhlYWRlcnMpIHtcbiAgICBjb25zdCBoZWFkZXJWYWwgPSBzdHJpbmcuZmlyc3ROb25FbXB0eShcbiAgICAgIGhlYWRlcnNbb3ZlcnJpZGUuTU9ERUxfT1ZFUlJJREVfSEVBREVSXSA/P1xuICAgICAgICBoZWFkZXJzW292ZXJyaWRlLk1PREVMX09WRVJSSURFX0hFQURFUi50b0xvd2VyQ2FzZSgpXSxcbiAgICApO1xuICAgIGlmIChoZWFkZXJWYWwpIHJldHVybiBoZWFkZXJWYWw7XG4gIH1cbiAgaWYgKHJlcS5xdWVyeSkge1xuICAgIGNvbnN0IHF1ZXJ5VmFsID0gc3RyaW5nLmZpcnN0Tm9uRW1wdHkocmVxLnF1ZXJ5W292ZXJyaWRlLk1PREVMX09WRVJSSURFX1FVRVJZXSk7XG4gICAgaWYgKHF1ZXJ5VmFsKSByZXR1cm4gcXVlcnlWYWw7XG4gIH1cbiAgaWYgKHJlcS5ib2R5ICYmIHR5cGVvZiByZXEuYm9keSA9PT0gXCJvYmplY3RcIikge1xuICAgIGNvbnN0IHJlY29yZCA9IHJlcS5ib2R5IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGZvciAoY29uc3QgZmllbGQgb2Ygb3ZlcnJpZGUuTU9ERUxfT1ZFUlJJREVfQk9EWV9GSUVMRFMpIHtcbiAgICAgIGNvbnN0IGJvZHlWYWwgPSBzdHJpbmcuZmlyc3ROb25FbXB0eShyZWNvcmRbZmllbGRdKTtcbiAgICAgIGlmIChib2R5VmFsKSByZXR1cm4gYm9keVZhbDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogUmVhZCB0aGUgZnV6enktcmVzb2x1dGlvbiBjb25maWcga25vYnMgb2ZmIHRoZSBwbHVnaW4gY29uZmlnIHdpdGhcbiAqIGBAZGJ4LXRvb2xzL21vZGVsYCBkZWZhdWx0cyBhcHBsaWVkLiBLZXB0IGhlcmUgc28gYGJ1aWxkTW9kZWxgIGFuZFxuICogdGhlIGAvbW9kZWxzYCByb3V0ZSBhZ3JlZSBvbiB3aGF0IFwiZW5hYmxlZFwiIG1lYW5zLlxuICpcbiAqIGBmYWxsYmFja3NgIGlzIHRoZSBwcmlvcml0eS1vcmRlcmVkIGxpc3QgYHJlc29sdmVNb2RlbGAgd2Fsa3MgZmlyc3RcbiAqIHdoZW4gbm90aGluZyBleHBsaWNpdCBpcyBzZXQ7IGRlZmF1bHRzIHRvIGFuIGVtcHR5IGxpc3Qgc28gdGhlXG4gKiBnZW5lcmljIHJlc29sdmVyIGZhbGxzIHRocm91Z2ggdG8gdGhlIGxpdmUgY2F0YWxvZ3VlIGFuZCBpdHMgb3duXG4gKiBgRkFMTEJBQ0tfTU9ERUxfSURTYCBmbG9vci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVTZXJ2aW5nQ29uZmlnKGNvbmZpZzogTWFzdHJhUGx1Z2luQ29uZmlnKToge1xuICB0dGxNczogbnVtYmVyO1xuICB0aHJlc2hvbGQ6IG51bWJlcjtcbiAgZnV6enk6IGJvb2xlYW47XG4gIGFsbG93T3ZlcnJpZGU6IGJvb2xlYW47XG4gIGZhbGxiYWNrczogcmVhZG9ubHkgc3RyaW5nW107XG59IHtcbiAgcmV0dXJuIHtcbiAgICB0dGxNczogY29uZmlnLm1vZGVsQ2FjaGVUdGxNcyA/PyBub2RlU2VydmluZy5ERUZBVUxUX01PREVMX0NBQ0hFX1RUTF9NUyxcbiAgICB0aHJlc2hvbGQ6IGNvbmZpZy5tb2RlbEZ1enp5VGhyZXNob2xkID8/IG5vZGVTZXJ2aW5nLkRFRkFVTFRfRlVaWllfVEhSRVNIT0xELFxuICAgIGZ1enp5OiBjb25maWcubW9kZWxGdXp6eU1hdGNoICE9PSBmYWxzZSxcbiAgICBhbGxvd092ZXJyaWRlOiBjb25maWcubW9kZWxPdmVycmlkZSAhPT0gZmFsc2UsXG4gICAgZmFsbGJhY2tzOiBjb25maWcuZGVmYXVsdE1vZGVsRmFsbGJhY2tzID8/IFtdLFxuICB9O1xufVxuIl19
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Databricks Statement Execution helpers for the Mastra plugin.
3
+ *
4
+ * Wraps `client.statementExecution.getStatement` with the shape and
5
+ * size handling the plugin's tools and the `/embed/data/:id` route
6
+ * both need: a low-level fetch that returns a raw
7
+ * `{columns, rows, rowCount}` shape and coerces numeric strings to
8
+ * numbers so downstream charts and aggregations don't have to, plus a
9
+ * hard row cap callers clamp `limit` to so a runaway result set can't
10
+ * hose a response. Upstream 404s are detected via
11
+ * `error.errorContext(err).notFound` at the call sites.
12
+ *
13
+ * Not Genie-specific: a Databricks `statement_id` is workspace
14
+ * scoped and lives in the Statement Execution API regardless of
15
+ * which producer (Genie, a tool, a notebook, etc.) submitted the
16
+ * query. Co-located here so consumers can fetch / cap / handle
17
+ * 404s without reaching into the Genie tool module.
18
+ *
19
+ * @module
20
+ */
21
+ import { WorkspaceClient } from "@databricks/sdk-experimental";
22
+ import type { GenieDatasetData } from "@dbx-tools/shared-mastra";
23
+ /**
24
+ * Hard server-side cap on rows returned by the
25
+ * `/embed/data/:id` route. Sized to keep responses small
26
+ * enough for inline tables to render snappily; the route surfaces
27
+ * a `truncated` flag whenever the upstream `rowCount` exceeds
28
+ * this so end users know they're seeing a sample.
29
+ */
30
+ export declare const STATEMENT_ROW_CAP = 500;
31
+ /**
32
+ * Fetch a single statement's rows via the Statement Execution API
33
+ * and reshape into the shared {@link GenieDatasetData} shape
34
+ * (column array + row records).
35
+ *
36
+ * Optional `limit` slices the returned `rows` client-side so the
37
+ * agent can scan a small sample without paging the full result
38
+ * set into context. `rowCount` always reflects the upstream total
39
+ * so callers know when the slice truncated.
40
+ *
41
+ * Exported because every consumer in the plugin (the
42
+ * `get_statement` tool, the `prepare_chart` dataset resolver, and
43
+ * the `/embed/data/:id` route) needs the exact same
44
+ * fetch + coercion pipeline so LLM-side `get_statement` output
45
+ * and UI-side `[data:<id>]` rendering stay shape-identical for
46
+ * the same `statement_id`.
47
+ */
48
+ export declare function fetchStatementData(client: WorkspaceClient, statementId: string, options?: {
49
+ limit?: number;
50
+ signal?: AbortSignal;
51
+ }): Promise<GenieDatasetData>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Databricks Statement Execution helpers for the Mastra plugin.
3
+ *
4
+ * Wraps `client.statementExecution.getStatement` with the shape and
5
+ * size handling the plugin's tools and the `/embed/data/:id` route
6
+ * both need: a low-level fetch that returns a raw
7
+ * `{columns, rows, rowCount}` shape and coerces numeric strings to
8
+ * numbers so downstream charts and aggregations don't have to, plus a
9
+ * hard row cap callers clamp `limit` to so a runaway result set can't
10
+ * hose a response. Upstream 404s are detected via
11
+ * `error.errorContext(err).notFound` at the call sites.
12
+ *
13
+ * Not Genie-specific: a Databricks `statement_id` is workspace
14
+ * scoped and lives in the Statement Execution API regardless of
15
+ * which producer (Genie, a tool, a notebook, etc.) submitted the
16
+ * query. Co-located here so consumers can fetch / cap / handle
17
+ * 404s without reaching into the Genie tool module.
18
+ *
19
+ * @module
20
+ */
21
+ import { databricks } from "@dbx-tools/appkit";
22
+ /**
23
+ * Hard server-side cap on rows returned by the
24
+ * `/embed/data/:id` route. Sized to keep responses small
25
+ * enough for inline tables to render snappily; the route surfaces
26
+ * a `truncated` flag whenever the upstream `rowCount` exceeds
27
+ * this so end users know they're seeing a sample.
28
+ */
29
+ export const STATEMENT_ROW_CAP = 500;
30
+ /**
31
+ * Best-effort numeric coercion for the Statement Execution API's
32
+ * all-strings cells. Leaves non-numeric strings (and explicit
33
+ * `null`s) intact; everything else flows through `Number`.
34
+ */
35
+ function coerceCell(cell) {
36
+ if (cell === null)
37
+ return null;
38
+ if (/^-?\d+(\.\d+)?$/.test(cell)) {
39
+ const n = Number(cell);
40
+ if (Number.isFinite(n))
41
+ return n;
42
+ }
43
+ return cell;
44
+ }
45
+ /**
46
+ * Fetch a single statement's rows via the Statement Execution API
47
+ * and reshape into the shared {@link GenieDatasetData} shape
48
+ * (column array + row records).
49
+ *
50
+ * Optional `limit` slices the returned `rows` client-side so the
51
+ * agent can scan a small sample without paging the full result
52
+ * set into context. `rowCount` always reflects the upstream total
53
+ * so callers know when the slice truncated.
54
+ *
55
+ * Exported because every consumer in the plugin (the
56
+ * `get_statement` tool, the `prepare_chart` dataset resolver, and
57
+ * the `/embed/data/:id` route) needs the exact same
58
+ * fetch + coercion pipeline so LLM-side `get_statement` output
59
+ * and UI-side `[data:<id>]` rendering stay shape-identical for
60
+ * the same `statement_id`.
61
+ */
62
+ export async function fetchStatementData(client, statementId, options) {
63
+ const ctx = options?.signal ? databricks.toContext(options.signal) : undefined;
64
+ const r = await client.statementExecution.getStatement({ statement_id: statementId }, ctx);
65
+ const columns = (r.manifest?.schema?.columns ?? []).map((c) => c.name ?? "");
66
+ const dataArray = (r.result?.data_array ?? []);
67
+ const sliced = options?.limit !== undefined && options.limit >= 0
68
+ ? dataArray.slice(0, options.limit)
69
+ : dataArray;
70
+ const rows = sliced.map((row) => {
71
+ const obj = {};
72
+ columns.forEach((col, i) => {
73
+ obj[col] = coerceCell(row[i] ?? null);
74
+ });
75
+ return obj;
76
+ });
77
+ return {
78
+ columns,
79
+ rows,
80
+ rowCount: r.manifest?.total_row_count ?? dataArray.length,
81
+ };
82
+ }
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGVtZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0YXRlbWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUdILE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUcvQzs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUM7QUFFckM7Ozs7R0FJRztBQUNILFNBQVMsVUFBVSxDQUFDLElBQW1CO0lBQ3JDLElBQUksSUFBSSxLQUFLLElBQUk7UUFBRSxPQUFPLElBQUksQ0FBQztJQUMvQixJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2pDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QixJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxrQkFBa0IsQ0FDdEMsTUFBdUIsRUFDdkIsV0FBbUIsRUFDbkIsT0FBa0Q7SUFFbEQsTUFBTSxHQUFHLEdBQUcsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUMvRSxNQUFNLENBQUMsR0FBRyxNQUFNLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxZQUFZLENBQUMsRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDM0YsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzdFLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxVQUFVLElBQUksRUFBRSxDQUFnQyxDQUFDO0lBQzlFLE1BQU0sTUFBTSxHQUNWLE9BQU8sRUFBRSxLQUFLLEtBQUssU0FBUyxJQUFJLE9BQU8sQ0FBQyxLQUFLLElBQUksQ0FBQztRQUNoRCxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUNuQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2hCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUM5QixNQUFNLEdBQUcsR0FBNEIsRUFBRSxDQUFDO1FBQ3hDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDekIsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUM7UUFDeEMsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUMsQ0FBQyxDQUFDO0lBQ0gsT0FBTztRQUNMLE9BQU87UUFDUCxJQUFJO1FBQ0osUUFBUSxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsZUFBZSxJQUFJLFNBQVMsQ0FBQyxNQUFNO0tBQzFELENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEYXRhYnJpY2tzIFN0YXRlbWVudCBFeGVjdXRpb24gaGVscGVycyBmb3IgdGhlIE1hc3RyYSBwbHVnaW4uXG4gKlxuICogV3JhcHMgYGNsaWVudC5zdGF0ZW1lbnRFeGVjdXRpb24uZ2V0U3RhdGVtZW50YCB3aXRoIHRoZSBzaGFwZSBhbmRcbiAqIHNpemUgaGFuZGxpbmcgdGhlIHBsdWdpbidzIHRvb2xzIGFuZCB0aGUgYC9lbWJlZC9kYXRhLzppZGAgcm91dGVcbiAqIGJvdGggbmVlZDogYSBsb3ctbGV2ZWwgZmV0Y2ggdGhhdCByZXR1cm5zIGEgcmF3XG4gKiBge2NvbHVtbnMsIHJvd3MsIHJvd0NvdW50fWAgc2hhcGUgYW5kIGNvZXJjZXMgbnVtZXJpYyBzdHJpbmdzIHRvXG4gKiBudW1iZXJzIHNvIGRvd25zdHJlYW0gY2hhcnRzIGFuZCBhZ2dyZWdhdGlvbnMgZG9uJ3QgaGF2ZSB0bywgcGx1cyBhXG4gKiBoYXJkIHJvdyBjYXAgY2FsbGVycyBjbGFtcCBgbGltaXRgIHRvIHNvIGEgcnVuYXdheSByZXN1bHQgc2V0IGNhbid0XG4gKiBob3NlIGEgcmVzcG9uc2UuIFVwc3RyZWFtIDQwNHMgYXJlIGRldGVjdGVkIHZpYVxuICogYGVycm9yLmVycm9yQ29udGV4dChlcnIpLm5vdEZvdW5kYCBhdCB0aGUgY2FsbCBzaXRlcy5cbiAqXG4gKiBOb3QgR2VuaWUtc3BlY2lmaWM6IGEgRGF0YWJyaWNrcyBgc3RhdGVtZW50X2lkYCBpcyB3b3Jrc3BhY2VcbiAqIHNjb3BlZCBhbmQgbGl2ZXMgaW4gdGhlIFN0YXRlbWVudCBFeGVjdXRpb24gQVBJIHJlZ2FyZGxlc3Mgb2ZcbiAqIHdoaWNoIHByb2R1Y2VyIChHZW5pZSwgYSB0b29sLCBhIG5vdGVib29rLCBldGMuKSBzdWJtaXR0ZWQgdGhlXG4gKiBxdWVyeS4gQ28tbG9jYXRlZCBoZXJlIHNvIGNvbnN1bWVycyBjYW4gZmV0Y2ggLyBjYXAgLyBoYW5kbGVcbiAqIDQwNHMgd2l0aG91dCByZWFjaGluZyBpbnRvIHRoZSBHZW5pZSB0b29sIG1vZHVsZS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgV29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIkBkYXRhYnJpY2tzL3Nkay1leHBlcmltZW50YWxcIjtcbmltcG9ydCB7IGRhdGFicmlja3MgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXRcIjtcbmltcG9ydCB0eXBlIHsgR2VuaWVEYXRhc2V0RGF0YSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tYXN0cmFcIjtcblxuLyoqXG4gKiBIYXJkIHNlcnZlci1zaWRlIGNhcCBvbiByb3dzIHJldHVybmVkIGJ5IHRoZVxuICogYC9lbWJlZC9kYXRhLzppZGAgcm91dGUuIFNpemVkIHRvIGtlZXAgcmVzcG9uc2VzIHNtYWxsXG4gKiBlbm91Z2ggZm9yIGlubGluZSB0YWJsZXMgdG8gcmVuZGVyIHNuYXBwaWx5OyB0aGUgcm91dGUgc3VyZmFjZXNcbiAqIGEgYHRydW5jYXRlZGAgZmxhZyB3aGVuZXZlciB0aGUgdXBzdHJlYW0gYHJvd0NvdW50YCBleGNlZWRzXG4gKiB0aGlzIHNvIGVuZCB1c2VycyBrbm93IHRoZXkncmUgc2VlaW5nIGEgc2FtcGxlLlxuICovXG5leHBvcnQgY29uc3QgU1RBVEVNRU5UX1JPV19DQVAgPSA1MDA7XG5cbi8qKlxuICogQmVzdC1lZmZvcnQgbnVtZXJpYyBjb2VyY2lvbiBmb3IgdGhlIFN0YXRlbWVudCBFeGVjdXRpb24gQVBJJ3NcbiAqIGFsbC1zdHJpbmdzIGNlbGxzLiBMZWF2ZXMgbm9uLW51bWVyaWMgc3RyaW5ncyAoYW5kIGV4cGxpY2l0XG4gKiBgbnVsbGBzKSBpbnRhY3Q7IGV2ZXJ5dGhpbmcgZWxzZSBmbG93cyB0aHJvdWdoIGBOdW1iZXJgLlxuICovXG5mdW5jdGlvbiBjb2VyY2VDZWxsKGNlbGw6IHN0cmluZyB8IG51bGwpOiB1bmtub3duIHtcbiAgaWYgKGNlbGwgPT09IG51bGwpIHJldHVybiBudWxsO1xuICBpZiAoL14tP1xcZCsoXFwuXFxkKyk/JC8udGVzdChjZWxsKSkge1xuICAgIGNvbnN0IG4gPSBOdW1iZXIoY2VsbCk7XG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZShuKSkgcmV0dXJuIG47XG4gIH1cbiAgcmV0dXJuIGNlbGw7XG59XG5cbi8qKlxuICogRmV0Y2ggYSBzaW5nbGUgc3RhdGVtZW50J3Mgcm93cyB2aWEgdGhlIFN0YXRlbWVudCBFeGVjdXRpb24gQVBJXG4gKiBhbmQgcmVzaGFwZSBpbnRvIHRoZSBzaGFyZWQge0BsaW5rIEdlbmllRGF0YXNldERhdGF9IHNoYXBlXG4gKiAoY29sdW1uIGFycmF5ICsgcm93IHJlY29yZHMpLlxuICpcbiAqIE9wdGlvbmFsIGBsaW1pdGAgc2xpY2VzIHRoZSByZXR1cm5lZCBgcm93c2AgY2xpZW50LXNpZGUgc28gdGhlXG4gKiBhZ2VudCBjYW4gc2NhbiBhIHNtYWxsIHNhbXBsZSB3aXRob3V0IHBhZ2luZyB0aGUgZnVsbCByZXN1bHRcbiAqIHNldCBpbnRvIGNvbnRleHQuIGByb3dDb3VudGAgYWx3YXlzIHJlZmxlY3RzIHRoZSB1cHN0cmVhbSB0b3RhbFxuICogc28gY2FsbGVycyBrbm93IHdoZW4gdGhlIHNsaWNlIHRydW5jYXRlZC5cbiAqXG4gKiBFeHBvcnRlZCBiZWNhdXNlIGV2ZXJ5IGNvbnN1bWVyIGluIHRoZSBwbHVnaW4gKHRoZVxuICogYGdldF9zdGF0ZW1lbnRgIHRvb2wsIHRoZSBgcHJlcGFyZV9jaGFydGAgZGF0YXNldCByZXNvbHZlciwgYW5kXG4gKiB0aGUgYC9lbWJlZC9kYXRhLzppZGAgcm91dGUpIG5lZWRzIHRoZSBleGFjdCBzYW1lXG4gKiBmZXRjaCArIGNvZXJjaW9uIHBpcGVsaW5lIHNvIExMTS1zaWRlIGBnZXRfc3RhdGVtZW50YCBvdXRwdXRcbiAqIGFuZCBVSS1zaWRlIGBbZGF0YTo8aWQ+XWAgcmVuZGVyaW5nIHN0YXkgc2hhcGUtaWRlbnRpY2FsIGZvclxuICogdGhlIHNhbWUgYHN0YXRlbWVudF9pZGAuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaFN0YXRlbWVudERhdGEoXG4gIGNsaWVudDogV29ya3NwYWNlQ2xpZW50LFxuICBzdGF0ZW1lbnRJZDogc3RyaW5nLFxuICBvcHRpb25zPzogeyBsaW1pdD86IG51bWJlcjsgc2lnbmFsPzogQWJvcnRTaWduYWwgfSxcbik6IFByb21pc2U8R2VuaWVEYXRhc2V0RGF0YT4ge1xuICBjb25zdCBjdHggPSBvcHRpb25zPy5zaWduYWwgPyBkYXRhYnJpY2tzLnRvQ29udGV4dChvcHRpb25zLnNpZ25hbCkgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IHIgPSBhd2FpdCBjbGllbnQuc3RhdGVtZW50RXhlY3V0aW9uLmdldFN0YXRlbWVudCh7IHN0YXRlbWVudF9pZDogc3RhdGVtZW50SWQgfSwgY3R4KTtcbiAgY29uc3QgY29sdW1ucyA9IChyLm1hbmlmZXN0Py5zY2hlbWE/LmNvbHVtbnMgPz8gW10pLm1hcCgoYykgPT4gYy5uYW1lID8/IFwiXCIpO1xuICBjb25zdCBkYXRhQXJyYXkgPSAoci5yZXN1bHQ/LmRhdGFfYXJyYXkgPz8gW10pIGFzIEFycmF5PEFycmF5PHN0cmluZyB8IG51bGw+PjtcbiAgY29uc3Qgc2xpY2VkID1cbiAgICBvcHRpb25zPy5saW1pdCAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMubGltaXQgPj0gMFxuICAgICAgPyBkYXRhQXJyYXkuc2xpY2UoMCwgb3B0aW9ucy5saW1pdClcbiAgICAgIDogZGF0YUFycmF5O1xuICBjb25zdCByb3dzID0gc2xpY2VkLm1hcCgocm93KSA9PiB7XG4gICAgY29uc3Qgb2JqOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgIGNvbHVtbnMuZm9yRWFjaCgoY29sLCBpKSA9PiB7XG4gICAgICBvYmpbY29sXSA9IGNvZXJjZUNlbGwocm93W2ldID8/IG51bGwpO1xuICAgIH0pO1xuICAgIHJldHVybiBvYmo7XG4gIH0pO1xuICByZXR1cm4ge1xuICAgIGNvbHVtbnMsXG4gICAgcm93cyxcbiAgICByb3dDb3VudDogci5tYW5pZmVzdD8udG90YWxfcm93X2NvdW50ID8/IGRhdGFBcnJheS5sZW5ndGgsXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Derive a Postgres-safe schema name for per-agent Mastra storage.
3
+ *
4
+ * Agent ids are often kebab-case route segments (`data-mesh-book-assistant`)
5
+ * but {@link PostgresStore} validates `schemaName` with Mastra's
6
+ * `parseSqlIdentifier` (letter/underscore start, `[A-Za-z0-9_]` only, max 63).
7
+ *
8
+ * @module
9
+ */
10
+ /**
11
+ * Default Lakebase schema for one agent's thread/message store:
12
+ * `mastra_<sanitized-agent-id>`.
13
+ */
14
+ export declare function agentStorageSchemaName(agentId: string): string;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Derive a Postgres-safe schema name for per-agent Mastra storage.
3
+ *
4
+ * Agent ids are often kebab-case route segments (`data-mesh-book-assistant`)
5
+ * but {@link PostgresStore} validates `schemaName` with Mastra's
6
+ * `parseSqlIdentifier` (letter/underscore start, `[A-Za-z0-9_]` only, max 63).
7
+ *
8
+ * @module
9
+ */
10
+ import { string } from "@dbx-tools/shared-core";
11
+ const SCHEMA_PREFIX = "mastra_";
12
+ const MAX_PG_IDENTIFIER_LEN = 63;
13
+ /**
14
+ * Default Lakebase schema for one agent's thread/message store:
15
+ * `mastra_<sanitized-agent-id>`.
16
+ */
17
+ export function agentStorageSchemaName(agentId) {
18
+ const maxSlugLen = MAX_PG_IDENTIFIER_LEN - SCHEMA_PREFIX.length;
19
+ const slug = string.toIdentifierWithOptions({
20
+ delimiter: "_",
21
+ maxLength: maxSlugLen,
22
+ truncateStrategy: "hash",
23
+ truncateHashLength: 6,
24
+ }, agentId);
25
+ const body = slug ||
26
+ string.toIdentifierWithOptions({
27
+ delimiter: "_",
28
+ maxLength: maxSlugLen,
29
+ truncateStrategy: "hash",
30
+ truncateHashLength: 6,
31
+ }, "agent", agentId);
32
+ return `${SCHEMA_PREFIX}${body}`;
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS1zY2hlbWEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS1zY2hlbWEudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0dBUUc7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFaEQsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFDO0FBQ2hDLE1BQU0scUJBQXFCLEdBQUcsRUFBRSxDQUFDO0FBRWpDOzs7R0FHRztBQUNILE1BQU0sVUFBVSxzQkFBc0IsQ0FBQyxPQUFlO0lBQ3BELE1BQU0sVUFBVSxHQUFHLHFCQUFxQixHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUM7SUFDaEUsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLHVCQUF1QixDQUN6QztRQUNFLFNBQVMsRUFBRSxHQUFHO1FBQ2QsU0FBUyxFQUFFLFVBQVU7UUFDckIsZ0JBQWdCLEVBQUUsTUFBTTtRQUN4QixrQkFBa0IsRUFBRSxDQUFDO0tBQ3RCLEVBQ0QsT0FBTyxDQUNSLENBQUM7SUFDRixNQUFNLElBQUksR0FDUixJQUFJO1FBQ0osTUFBTSxDQUFDLHVCQUF1QixDQUM1QjtZQUNFLFNBQVMsRUFBRSxHQUFHO1lBQ2QsU0FBUyxFQUFFLFVBQVU7WUFDckIsZ0JBQWdCLEVBQUUsTUFBTTtZQUN4QixrQkFBa0IsRUFBRSxDQUFDO1NBQ3RCLEVBQ0QsT0FBTyxFQUNQLE9BQU8sQ0FDUixDQUFDO0lBQ0osT0FBTyxHQUFHLGFBQWEsR0FBRyxJQUFJLEVBQUUsQ0FBQztBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZXJpdmUgYSBQb3N0Z3Jlcy1zYWZlIHNjaGVtYSBuYW1lIGZvciBwZXItYWdlbnQgTWFzdHJhIHN0b3JhZ2UuXG4gKlxuICogQWdlbnQgaWRzIGFyZSBvZnRlbiBrZWJhYi1jYXNlIHJvdXRlIHNlZ21lbnRzIChgZGF0YS1tZXNoLWJvb2stYXNzaXN0YW50YClcbiAqIGJ1dCB7QGxpbmsgUG9zdGdyZXNTdG9yZX0gdmFsaWRhdGVzIGBzY2hlbWFOYW1lYCB3aXRoIE1hc3RyYSdzXG4gKiBgcGFyc2VTcWxJZGVudGlmaWVyYCAobGV0dGVyL3VuZGVyc2NvcmUgc3RhcnQsIGBbQS1aYS16MC05X11gIG9ubHksIG1heCA2MykuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IHN0cmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5cbmNvbnN0IFNDSEVNQV9QUkVGSVggPSBcIm1hc3RyYV9cIjtcbmNvbnN0IE1BWF9QR19JREVOVElGSUVSX0xFTiA9IDYzO1xuXG4vKipcbiAqIERlZmF1bHQgTGFrZWJhc2Ugc2NoZW1hIGZvciBvbmUgYWdlbnQncyB0aHJlYWQvbWVzc2FnZSBzdG9yZTpcbiAqIGBtYXN0cmFfPHNhbml0aXplZC1hZ2VudC1pZD5gLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWdlbnRTdG9yYWdlU2NoZW1hTmFtZShhZ2VudElkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBtYXhTbHVnTGVuID0gTUFYX1BHX0lERU5USUZJRVJfTEVOIC0gU0NIRU1BX1BSRUZJWC5sZW5ndGg7XG4gIGNvbnN0IHNsdWcgPSBzdHJpbmcudG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoXG4gICAge1xuICAgICAgZGVsaW1pdGVyOiBcIl9cIixcbiAgICAgIG1heExlbmd0aDogbWF4U2x1Z0xlbixcbiAgICAgIHRydW5jYXRlU3RyYXRlZ3k6IFwiaGFzaFwiLFxuICAgICAgdHJ1bmNhdGVIYXNoTGVuZ3RoOiA2LFxuICAgIH0sXG4gICAgYWdlbnRJZCxcbiAgKTtcbiAgY29uc3QgYm9keSA9XG4gICAgc2x1ZyB8fFxuICAgIHN0cmluZy50b0lkZW50aWZpZXJXaXRoT3B0aW9ucyhcbiAgICAgIHtcbiAgICAgICAgZGVsaW1pdGVyOiBcIl9cIixcbiAgICAgICAgbWF4TGVuZ3RoOiBtYXhTbHVnTGVuLFxuICAgICAgICB0cnVuY2F0ZVN0cmF0ZWd5OiBcImhhc2hcIixcbiAgICAgICAgdHJ1bmNhdGVIYXNoTGVuZ3RoOiA2LFxuICAgICAgfSxcbiAgICAgIFwiYWdlbnRcIixcbiAgICAgIGFnZW50SWQsXG4gICAgKTtcbiAgcmV0dXJuIGAke1NDSEVNQV9QUkVGSVh9JHtib2R5fWA7XG59XG4iXX0=