@dbx-tools/appkit-mastra 0.1.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 +593 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +18 -0
- package/dist/src/agents.d.ts +306 -0
- package/dist/src/agents.js +379 -0
- package/dist/src/config.d.ts +170 -0
- package/dist/src/config.js +12 -0
- package/dist/src/genie.d.ts +109 -0
- package/dist/src/genie.js +271 -0
- package/dist/src/memory.d.ts +79 -0
- package/dist/src/memory.js +197 -0
- package/dist/src/model.d.ts +159 -0
- package/dist/src/model.js +423 -0
- package/dist/src/plugin.d.ts +120 -0
- package/dist/src/plugin.js +235 -0
- package/dist/src/server.d.ts +42 -0
- package/dist/src/server.js +109 -0
- package/dist/src/serving.d.ts +156 -0
- package/dist/src/serving.js +214 -0
- package/index.ts +36 -0
- package/package.json +55 -0
- package/src/agents.ts +675 -0
- package/src/config.ts +179 -0
- package/src/genie.ts +354 -0
- package/src/memory.ts +245 -0
- package/src/model.ts +491 -0
- package/src/plugin.ts +269 -0
- package/src/server.ts +130 -0
- package/src/serving.ts +294 -0
package/src/memory.ts
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lakebase-backed Mastra memory wiring.
|
|
3
|
+
*
|
|
4
|
+
* Provides a {@link MemoryBuilder} that mints one `Memory` per agent
|
|
5
|
+
* with two independent knobs:
|
|
6
|
+
*
|
|
7
|
+
* - **Storage** (threads / messages via `PostgresStore`): defaults to
|
|
8
|
+
* **per-agent** namespacing via `schemaName: "mastra_<agentId>"` so
|
|
9
|
+
* conversation history stays isolated between agents in the same
|
|
10
|
+
* database. `PostgresStore` auto-creates the schema with
|
|
11
|
+
* `CREATE SCHEMA IF NOT EXISTS` on init.
|
|
12
|
+
* - **Memory** (semantic recall via `PgVector`): defaults to a single
|
|
13
|
+
* **shared** instance across every agent. Cross-agent recall on one
|
|
14
|
+
* index is almost always what users want; opt into per-agent recall
|
|
15
|
+
* by passing a {@link MastraMemoryConfigOverride} on the agent.
|
|
16
|
+
*
|
|
17
|
+
* Plugin-level `config.storage` / `config.memory` act as the baseline
|
|
18
|
+
* (auto-defaulted to `true` in `plugin.ts` when the `lakebase` plugin
|
|
19
|
+
* is registered); per-agent settings cascade on top of that.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { lakebase } from "@databricks/appkit";
|
|
23
|
+
import { pluginUtils } from "@dbx-tools/appkit-shared";
|
|
24
|
+
import { fastembed } from "@mastra/fastembed";
|
|
25
|
+
import { Memory } from "@mastra/memory";
|
|
26
|
+
import { PgVector, PostgresStore } from "@mastra/pg";
|
|
27
|
+
import { randomUUID } from "node:crypto";
|
|
28
|
+
import type { Pool } from "pg";
|
|
29
|
+
|
|
30
|
+
import type {
|
|
31
|
+
MastraAgentDefinition,
|
|
32
|
+
MastraMemoryConfigOverride,
|
|
33
|
+
} from "./agents.js";
|
|
34
|
+
import type { MastraPluginConfig } from "./config.js";
|
|
35
|
+
|
|
36
|
+
/** Pool handle returned by the AppKit `lakebase` plugin `exports().pool`. */
|
|
37
|
+
export type LakebasePool = ReturnType<
|
|
38
|
+
InstanceType<ReturnType<typeof lakebase>["plugin"]>["exports"]
|
|
39
|
+
>["pool"];
|
|
40
|
+
|
|
41
|
+
/** Effective per-knob setting after the plugin/agent cascade. */
|
|
42
|
+
type StorageSetting = MastraAgentDefinition["storage"];
|
|
43
|
+
type MemorySetting = MastraAgentDefinition["memory"];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* True when any plugin-level or per-agent setting could need the
|
|
47
|
+
* Lakebase pool. Used by `plugin.ts` to gate pool acquisition; the
|
|
48
|
+
* builder also acquires lazily so missed cases still fail with a
|
|
49
|
+
* clear lakebase-not-registered error.
|
|
50
|
+
*/
|
|
51
|
+
export function needsLakebase(config: MastraPluginConfig): boolean {
|
|
52
|
+
if (settingNeedsSharedPool(config.storage)) return true;
|
|
53
|
+
if (settingNeedsSharedPool(config.memory)) return true;
|
|
54
|
+
const defs = collectAgentDefinitions(config);
|
|
55
|
+
return defs.some(
|
|
56
|
+
(d) =>
|
|
57
|
+
settingNeedsSharedPool(d.storage) || settingNeedsSharedPool(d.memory),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Look up the `lakebase` plugin and return its managed `pg.Pool`.
|
|
63
|
+
* Throws when the sibling plugin is not registered; enabling
|
|
64
|
+
* `storage` / `memory` without lakebase is a wiring bug, not a runtime
|
|
65
|
+
* condition we can recover from.
|
|
66
|
+
*/
|
|
67
|
+
export function resolveLakebasePool(
|
|
68
|
+
context: pluginUtils.PluginContextLike | undefined,
|
|
69
|
+
caller: MastraPluginConfig,
|
|
70
|
+
): LakebasePool {
|
|
71
|
+
return pluginUtils.require(context, lakebase, caller).exports().pool;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Construct a per-agent {@link Memory} factory. Caches the shared
|
|
76
|
+
* `PgVector` singleton (built on first need) and the lazily-resolved
|
|
77
|
+
* Lakebase pool so each agent build is O(1) after the first.
|
|
78
|
+
*/
|
|
79
|
+
export function createMemoryBuilder(
|
|
80
|
+
config: MastraPluginConfig,
|
|
81
|
+
context: pluginUtils.PluginContextLike | undefined,
|
|
82
|
+
): MemoryBuilder {
|
|
83
|
+
return new MemoryBuilder(config, context);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Builds one `Memory` per agent. Per-instance state keeps the shared
|
|
88
|
+
* `PgVector` and the resolved Lakebase pool alive across calls so
|
|
89
|
+
* registering N agents stays cheap.
|
|
90
|
+
*/
|
|
91
|
+
export class MemoryBuilder {
|
|
92
|
+
private sharedVector: PgVector | undefined;
|
|
93
|
+
private pool: LakebasePool | undefined;
|
|
94
|
+
|
|
95
|
+
constructor(
|
|
96
|
+
private readonly config: MastraPluginConfig,
|
|
97
|
+
private readonly context: pluginUtils.PluginContextLike | undefined,
|
|
98
|
+
) {}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Build a `Memory` for `agentId` after the plugin/agent cascade.
|
|
102
|
+
* Returns `undefined` when the agent has neither storage nor a
|
|
103
|
+
* vector store enabled - Mastra accepts a missing `memory` field
|
|
104
|
+
* and treats the agent as stateless.
|
|
105
|
+
*/
|
|
106
|
+
forAgent(agentId: string, def: MastraAgentDefinition): Memory | undefined {
|
|
107
|
+
const storageSetting = def.storage ?? this.config.storage;
|
|
108
|
+
const memorySetting = def.memory ?? this.config.memory;
|
|
109
|
+
|
|
110
|
+
const storage = this.buildStorage(agentId, storageSetting);
|
|
111
|
+
const vector = this.buildVector(memorySetting);
|
|
112
|
+
if (!storage && !vector) return undefined;
|
|
113
|
+
|
|
114
|
+
return new Memory({
|
|
115
|
+
...(storage ? { storage } : {}),
|
|
116
|
+
...(vector ? { vector, embedder: fastembed } : {}),
|
|
117
|
+
options: {
|
|
118
|
+
lastMessages: 10,
|
|
119
|
+
...(vector
|
|
120
|
+
? { semanticRecall: { topK: 3, messageRange: 2 } }
|
|
121
|
+
: {}),
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private buildStorage(
|
|
127
|
+
agentId: string,
|
|
128
|
+
setting: StorageSetting,
|
|
129
|
+
): PostgresStore | undefined {
|
|
130
|
+
if (!setting) return undefined;
|
|
131
|
+
if (typeof setting === "boolean") {
|
|
132
|
+
return new PostgresStore({
|
|
133
|
+
id: `mastra-store__${agentId}`,
|
|
134
|
+
schemaName: `mastra_${agentId}`,
|
|
135
|
+
pool: this.requirePool() as Pool,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// Cast: `withId` guarantees `id` is set, but the distributive
|
|
139
|
+
// Omit + `id?: string` shape doesn't structurally narrow to the
|
|
140
|
+
// discriminated union members. Runtime shape is identical.
|
|
141
|
+
return new PostgresStore(
|
|
142
|
+
withId(setting, `mastra-store__${agentId}`) as ConstructorParameters<
|
|
143
|
+
typeof PostgresStore
|
|
144
|
+
>[0],
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Resolve the agent's vector store. Cascade:
|
|
150
|
+
*
|
|
151
|
+
* - falsy: no vector.
|
|
152
|
+
* - `boolean` / `undefined-inheriting-true`: return the shared
|
|
153
|
+
* singleton (built lazily on first call). All agents that
|
|
154
|
+
* default-enable memory write into and recall from one index.
|
|
155
|
+
* - object: build a dedicated `PgVector` for this agent.
|
|
156
|
+
*/
|
|
157
|
+
private buildVector(setting: MemorySetting): PgVector | undefined {
|
|
158
|
+
if (!setting) return undefined;
|
|
159
|
+
if (typeof setting === "boolean") return this.getSharedVector();
|
|
160
|
+
return buildPgVector(setting);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private getSharedVector(): PgVector {
|
|
164
|
+
if (!this.sharedVector) {
|
|
165
|
+
this.sharedVector = buildSharedPgVector(this.requirePool());
|
|
166
|
+
}
|
|
167
|
+
return this.sharedVector;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private requirePool(): LakebasePool {
|
|
171
|
+
if (!this.pool) {
|
|
172
|
+
this.pool = resolveLakebasePool(this.context, this.config);
|
|
173
|
+
}
|
|
174
|
+
return this.pool;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Build the shared `PgVector` that backs the default
|
|
180
|
+
* `def.memory === true` case across every agent.
|
|
181
|
+
*
|
|
182
|
+
* `PgVector`'s constructor accepts only connection-style configs
|
|
183
|
+
* (`HostConfig` / `ConnectionStringConfig` / `ClientConfig`); there is
|
|
184
|
+
* no `{ pool }` shorthand the way `PostgresStore` has one. Worse, the
|
|
185
|
+
* constructor synchronously kicks off a `cacheWarmupPromise` IIFE that
|
|
186
|
+
* calls `this.pool.connect()` before returning, so we can't cleanly
|
|
187
|
+
* hand it an inert config and patch the pool afterwards.
|
|
188
|
+
*
|
|
189
|
+
* The trick: pass illegal-but-validation-passing placeholders so the
|
|
190
|
+
* warmup's `net.connect()` rejects synchronously with `RangeError`
|
|
191
|
+
* (Node validates `0 <= port < 65536`). The IIFE's `catch {}` swallows
|
|
192
|
+
* it, no DNS lookup or TCP attempt happens, and we then swap
|
|
193
|
+
* `pgVector.pool` to the lakebase pool. Every subsequent `PgVector`
|
|
194
|
+
* method reads `this.pool` at call time, so all real I/O goes through
|
|
195
|
+
* the lakebase pool from then on. The placeholder pool is `.end()`'d
|
|
196
|
+
* so its socket book-keeping is released.
|
|
197
|
+
*/
|
|
198
|
+
function buildSharedPgVector(pool: LakebasePool): PgVector {
|
|
199
|
+
const vector = new PgVector({
|
|
200
|
+
id: `pg${randomUUID()}`,
|
|
201
|
+
host: "-1",
|
|
202
|
+
port: -1,
|
|
203
|
+
database: "_",
|
|
204
|
+
user: "_",
|
|
205
|
+
password: "_",
|
|
206
|
+
});
|
|
207
|
+
const placeholder = vector.pool;
|
|
208
|
+
vector.pool = pool as Pool;
|
|
209
|
+
void placeholder.end().catch(() => undefined);
|
|
210
|
+
return vector;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Per-agent dedicated `PgVector` (rare; opt-in via object override). */
|
|
214
|
+
function buildPgVector(setting: MastraMemoryConfigOverride): PgVector {
|
|
215
|
+
return new PgVector(
|
|
216
|
+
withId(setting, `pg-vector__${randomUUID()}`) as ConstructorParameters<
|
|
217
|
+
typeof PgVector
|
|
218
|
+
>[0],
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** True when this setting requires the shared Lakebase pool. */
|
|
223
|
+
function settingNeedsSharedPool(
|
|
224
|
+
setting: StorageSetting | MemorySetting | undefined,
|
|
225
|
+
): boolean {
|
|
226
|
+
return setting === true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Walk the three shapes of `config.agents` into a flat list. */
|
|
230
|
+
function collectAgentDefinitions(
|
|
231
|
+
config: MastraPluginConfig,
|
|
232
|
+
): MastraAgentDefinition[] {
|
|
233
|
+
const agents = config.agents;
|
|
234
|
+
if (!agents) return [];
|
|
235
|
+
if (Array.isArray(agents)) return agents;
|
|
236
|
+
if (typeof (agents as MastraAgentDefinition).instructions === "string") {
|
|
237
|
+
return [agents as MastraAgentDefinition];
|
|
238
|
+
}
|
|
239
|
+
return Object.values(agents as Record<string, MastraAgentDefinition>);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Fill in a default `id` when the caller didn't supply one. */
|
|
243
|
+
function withId<T extends { id?: string }>(value: T, fallback: string): T {
|
|
244
|
+
return value.id ? value : { ...value, id: fallback };
|
|
245
|
+
}
|