History

tools: collapse annotation N+1 + push sourceId filter to DB

openapi/graphql resolveAnnotations ran one listOperationsBySource per distinct scope in the toolRows. Store the owning scopeId on each StoredOperation instead and issue a single query, partitioning by op.scopeId so shadowed tools still resolve against the right binding. Also push executor.tools.list's sourceId filter down to storage so `/sources/:id/tools` stops pulling every row in the scope stack.

Rhys Sullivan committed 6 months ago

Commit 400a8061 parent aa220d75 files · +44 −40Browse files

Showing the changes to packages/plugins/openapi/src (2 of 5 files). Show all

Unified · Split

2 files
  1. packages/plugins/openapi/src/sdk/plugin.ts +13 −12
  2. packages/plugins/openapi/src/sdk/store.ts +4 −6
packages/plugins/openapi/src/sdk/plugin.ts+13−12
@@ -408,6 +408,7 @@ export const openApiPlugin = definePlugin( · 407 unmodified lines
408408 const storedOps: StoredOperation[] = definitions.map((def) => ({
409409 toolId: `${namespace}.${def.toolPath}`,
410410 sourceId: namespace,
411+ scopeId: input.scope,
411412 binding: toBinding(def),
412413 }));
413414
@@ -949,19 +950,19 @@ export const openApiPlugin = definePlugin( · 535 unmodified lines
949950 // toolRows for a single (plugin_id, source_id) group can still
950951 // straddle multiple scopes when the source is shadowed (e.g. an
951952 // org-level openapi source plus a per-user override that
952− // re-registers the same tool ids). Run one listOperationsBySource
953− // per distinct scope so each lookup pins {source_id, scope_id}
954− // and we don't fall through to the wrong scope's bindings.
955− const scopes = new Set<string>();
956− for (const row of toolRows as readonly ToolRow[]) {
957− scopes.add(row.scope_id as string);
958− }
953+ // re-registers the same tool ids). One query returns every op
954+ // row in the caller's stack (the scoped adapter pins
955+ // `scope_id IN (stack)`); partition by `op.scopeId` so each
956+ // tool row resolves against its own scope's binding.
957+ const ops = yield* ctx.storage.listOperationsBySource(sourceId);
959958 const byScope = new Map<string, Map<string, OperationBinding>>();
960− for (const scope of scopes) {
961− const ops = yield* ctx.storage.listOperationsBySource(sourceId, scope);
962− const byId = new Map<string, OperationBinding>();
963− for (const op of ops) byId.set(op.toolId, op.binding);
964− byScope.set(scope, byId);
959+ for (const op of ops) {
960+ let byId = byScope.get(op.scopeId);
961+ if (!byId) {
962+ byId = new Map<string, OperationBinding>();
963+ byScope.set(op.scopeId, byId);
964+ }
965+ byId.set(op.toolId, op.binding);
965966 }
966967
967968 const out: Record<string, ToolAnnotations> = {};
packages/plugins/openapi/src/sdk/store.ts+4−6
@@ -119,6 +119,7 @@ export type StoredSourceSchemaType = typeof StoredSourceSchema.Type; · 118 unmodified lines
119119 export interface StoredOperation {
120120 readonly toolId: string;
121121 readonly sourceId: string;
122+ readonly scopeId: string;
122123 readonly binding: OperationBinding;
123124 }
124125
@@ -202,7 +203,6 @@ export interface OpenapiStore { · 77 unmodified lines
202203
203204 readonly listOperationsBySource: (
204205 sourceId: string,
205− scope: string,
206206 ) => Effect.Effect<readonly StoredOperation[], StorageFailure>;
207207
208208 readonly removeSource: (
@@ -255,6 +255,7 @@ export const makeDefaultOpenapiStore = ({ · 46 unmodified lines
255255 const rowToOperation = (row: Record<string, unknown>): StoredOperation => ({
256256 toolId: row.id as string,
257257 sourceId: row.source_id as string,
258+ scopeId: row.scope_id as string,
258259 binding: decodeBinding(
259260 typeof row.binding === "string" ? JSON.parse(row.binding) : row.binding,
260261 ),
@@ -388,14 +389,11 @@ export const makeDefaultOpenapiStore = ({ · 127 unmodified lines
388389 })
389390 .pipe(Effect.map((row) => (row ? rowToOperation(row) : null))),
390391
391− listOperationsBySource: (sourceId, scope) =>
392+ listOperationsBySource: (sourceId) =>
392393 adapter
393394 .findMany({
394395 model: "openapi_operation",
395− where: [
396− { field: "source_id", value: sourceId },
397− { field: "scope_id", value: scope },
398− ],
396+ where: [{ field: "source_id", value: sourceId }],
399397 })
400398 .pipe(Effect.map((rows) => rows.map(rowToOperation))),
401399