@mastra/core
Version:
255 lines (249 loc) • 9.49 kB
JavaScript
import { MASTRA_RESOURCE_ID_KEY } from '../chunk-W4DLMY73.js';
// src/tool-provider/types.ts
var SHARED_BUCKET_ID = "shared";
// src/tool-provider/base.ts
var BaseToolProvider = class {
allowedToolkits;
allowedTools;
constructor(options = {}) {
this.allowedToolkits = options.allowedToolkits ?? [];
this.allowedTools = options.allowedTools ?? {};
}
// ── VNext catalog (filtered) ──────────────────────────────────────────
async listToolkitsVNext() {
const all = await this.listAllToolkits();
const data = this.allowedToolkits.length === 0 ? all : all.filter((toolkit) => matchesAny(toolkit.slug, this.allowedToolkits));
return { data };
}
async listToolsVNext(opts = {}) {
if (opts.toolkit !== void 0 && this.allowedToolkits.length > 0 && !matchesAny(opts.toolkit, this.allowedToolkits)) {
return {
data: [],
pagination: { page: opts.page ?? 1, perPage: opts.perPage, hasMore: false }
};
}
const result = await this.listAllTools(opts);
if (Object.keys(this.allowedTools).length === 0) return result;
return {
...result,
data: result.data.filter((tool) => {
const toolkit = tool.toolkit;
if (!toolkit) return true;
const patterns = this.allowedTools[toolkit];
if (patterns === void 0) return true;
return matchesAny(tool.slug, patterns);
})
};
}
// ── legacy surface (default forwards to VNext) ───────────────────────
async listToolkits() {
const result = await this.listToolkitsVNext();
return { data: result.data };
}
async listTools(options = {}) {
const result = await this.listToolsVNext(options);
return { data: result.data, pagination: result.pagination };
}
/**
* Legacy `resolveTools` shim — subclasses that opt into the VNext surface
* normally implement `resolveToolsVNext` instead; the legacy signature
* delegates so existing callers keep working.
*/
async resolveTools(toolSlugs, toolConfigs, options) {
return this.resolveToolsVNext({
toolSlugs,
toolMeta: Object.fromEntries(
Object.entries(toolConfigs ?? {}).map(([slug, cfg]) => [slug, { description: cfg?.description }])
),
connectionId: "",
authorId: options?.userId,
requestContext: options?.requestContext
});
}
/**
* Default connection-fields implementation — returns `[]`. Subclasses
* whose underlying provider requires user-supplied custom fields at
* authorize time (e.g. Confluence subdomain) should override.
*/
async listConnectionFields(_opts) {
return [];
}
/**
* Default health implementation — returns `{ ok: true }`. Subclasses that
* need to probe SDK reachability or configuration should override.
*/
async getHealth() {
return { ok: true };
}
};
function matchesAny(slug, patterns) {
for (const pattern of patterns) {
if (pattern === slug) return true;
if (pattern.endsWith("*")) {
const prefix = pattern.slice(0, -1);
if (slug.startsWith(prefix)) return true;
}
}
return false;
}
// src/tool-provider/runtime.ts
function buildConnectionSuffix(label, usedSuffixes) {
const raw = (label ?? "").toUpperCase();
let base = "";
let prevWasUnderscore = true;
for (let i = 0; i < raw.length; i++) {
const c = raw.charCodeAt(i);
const isAllowed = c >= 65 && c <= 90 || // A-Z
c >= 48 && c <= 57;
if (isAllowed) {
base += raw[i];
prevWasUnderscore = false;
} else if (!prevWasUnderscore) {
base += "_";
prevWasUnderscore = true;
}
}
if (base.endsWith("_")) base = base.slice(0, -1);
if (!base) base = "CONN";
let candidate = base;
let n = 2;
while (usedSuffixes.has(candidate)) {
candidate = `${base}_${n}`;
n += 1;
}
usedSuffixes.add(candidate);
return candidate;
}
async function resolveStoredToolProviders(toolProviders, lookup, opts = {}) {
const { requestContext, authorId, logger } = opts;
const out = {};
logger?.debug(`[resolveStoredToolProviders] called`, {
providerIds: Object.keys(toolProviders ?? {}),
authorId
});
if (!toolProviders || Object.keys(toolProviders).length === 0) {
logger?.debug(`[resolveStoredToolProviders] no toolProviders on agent \u2014 returning {}`);
return out;
}
for (const [providerId, cfg] of Object.entries(toolProviders)) {
let provider;
try {
provider = lookup(providerId);
} catch (error) {
logger?.warn(`[resolveStoredToolProviders] Unknown provider "${providerId}"`, { error });
continue;
}
if (!provider.resolveToolsVNext) {
logger?.warn(`[resolveStoredToolProviders] Provider "${providerId}" does not implement resolveToolsVNext`);
continue;
}
const tools = cfg.tools ?? {};
const connectionsByToolkit = cfg.connections ?? {};
for (const [toolkit, connections] of Object.entries(connectionsByToolkit)) {
if (!connections || connections.length === 0) {
logger?.debug(
`[resolveStoredToolProviders] toolkit "${toolkit}" on provider "${providerId}" has no pinned connections \u2014 skipping`
);
continue;
}
if (connections.length > 1 && !provider.capabilities?.multipleConnectionsPerToolkit) {
logger?.warn(
`[resolveStoredToolProviders] provider "${providerId}" does not support multiple connections per toolkit but received ${connections.length} for "${toolkit}" \u2014 skipping`
);
continue;
}
const slugsForToolkit = Object.entries(tools).filter(([slug, meta]) => meta?.toolkit ? meta.toolkit === toolkit : slug.startsWith(`${toolkit}.`)).map(([slug]) => slug);
if (slugsForToolkit.length === 0) {
logger?.debug(
`[resolveStoredToolProviders] toolkit "${toolkit}" on provider "${providerId}" has connections but no matching tool slugs \u2014 skipping`,
{ availableSlugs: Object.keys(tools) }
);
continue;
}
logger?.debug(`[resolveStoredToolProviders] resolving tools for ${providerId}/${toolkit}`, {
slugs: slugsForToolkit,
connectionCount: connections.length
});
const skipSuffix = connections.length === 1;
const usedSuffixes = /* @__PURE__ */ new Set();
for (const connection of connections) {
const suffix = skipSuffix ? "" : `__${buildConnectionSuffix(connection.label, usedSuffixes)}`;
const resolvedAuthorId = resolveConnectionAuthorId(connection, authorId, requestContext, logger);
let resolved;
try {
resolved = await provider.resolveToolsVNext({
toolSlugs: slugsForToolkit,
toolMeta: cfg.tools ?? {},
connectionId: connection.connectionId,
authorId: resolvedAuthorId,
requestContext
});
} catch (error) {
logger?.warn(
`[resolveStoredToolProviders] Failed to resolve tools for ${providerId}/${toolkit} connection ${connection.connectionId}`,
{ error }
);
continue;
}
for (const [slug, tool] of Object.entries(resolved)) {
const renamedSlug = `${slug}${suffix}`;
const baseDescription = tool.description ?? "";
const description = skipSuffix ? baseDescription : appendRoutingHint(baseDescription, connection);
out[renamedSlug] = {
...tool,
id: renamedSlug,
description
};
}
}
}
}
return out;
}
var defaultBucketWarned = false;
function warnDefaultBucketFallback(logger) {
if (defaultBucketWarned) return;
defaultBucketWarned = true;
logger?.warn(
'[resolveStoredToolProviders] caller-supplied scope falling back to shared "default" bucket \u2014 wire authConfig.mapUserToResourceId to avoid cross-tenant OAuth sharing'
);
}
function resolveConnectionAuthorId(connection, callerAuthorId, requestContext, logger) {
if (connection.kind !== "author") return void 0;
if (connection.scope === "shared") return SHARED_BUCKET_ID;
if (connection.scope === "caller-supplied") {
const resourceId = requestContext?.[MASTRA_RESOURCE_ID_KEY];
if (typeof resourceId === "string" && resourceId.length > 0) return resourceId;
warnDefaultBucketFallback(logger);
return "default";
}
return callerAuthorId;
}
function appendRoutingHint(description, connection) {
const hint = `Routes through connection: ${connection.label ?? connection.connectionId}`;
if (!description) return hint;
return `${description}
${hint}`;
}
// src/tool-provider/errors.ts
var DuplicateToolProviderError = class extends Error {
ids;
constructor(ids) {
super(`Duplicate tool provider ids: ${ids.join(", ")}`);
this.name = "DuplicateToolProviderError";
this.ids = ids;
}
};
var UnknownToolProviderError = class extends Error {
id;
knownIds;
constructor(id, knownIds) {
super(`Unknown tool provider "${id}". Known ids: ${knownIds.length ? knownIds.join(", ") : "(none)"}`);
this.name = "UnknownToolProviderError";
this.id = id;
this.knownIds = knownIds;
}
};
export { BaseToolProvider, DuplicateToolProviderError, SHARED_BUCKET_ID, UnknownToolProviderError, buildConnectionSuffix, resolveStoredToolProviders };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map