@@ -28,10 +28,12 @@ import type {
2828import {
2929 coreSchema ,
3030 isToolPolicyAction ,
31+ TOOL_INVOCATION_COLUMNS ,
3132 type ConnectionRow ,
3233 type CoreSchema ,
3334 type IntegrationRow ,
3435 type OAuthClientRow ,
36+ type ToolInvocationRow ,
3537 type ToolRow ,
3638 type ToolPolicyRow ,
3739} from "./core-schema" ;
@@ -513,7 +515,13 @@ const connectionItemIds = (row: ConnectionRow): Record<string, string> => {
513515 return decoded as Record < string , string > ;
514516} ;
515517
516- const rowToTool = ( row : ToolRow , annotations ?: ToolAnnotations ) : Tool => {
518+ // Accepts a projected row (the invoke/list paths select away the heavy
519+ // schema columns); `Tool.inputSchema`/`outputSchema` are optional and stay
520+ // absent for those callers — `tools.schema` is the schema-bearing surface.
521+ const rowToTool = (
522+ row : ToolInvocationRow & Partial < Pick < ToolRow , "input_schema" | "output_schema" > > ,
523+ annotations ?: ToolAnnotations ,
524+ ) : Tool => {
517525 const owner = row . owner as Owner ;
518526 const integration = IntegrationSlug . make ( row . integration ) ;
519527 const connection = ConnectionName . make ( row . connection ) ;
@@ -539,16 +547,29 @@ const rowToTool = (row: ToolRow, annotations?: ToolAnnotations): Tool => {
539547type AnyCb = ConditionBuilder < Record < string , AnyColumn > > ;
540548type CoreTableName = keyof CoreSchema & string ;
541549type CoreRow < TName extends CoreTableName > = FumaRow < CoreSchema [ TName ] > ;
550+ type CoreColumn < TName extends CoreTableName > = keyof CoreRow < TName > & string ;
542551type CoreWhere = ( b : AnyCb ) => Condition | boolean ;
543- type CoreFindManyOptions = {
552+ type CoreFindManyOptions < TName extends CoreTableName = CoreTableName > = {
544553 readonly where ?: CoreWhere ;
545554 readonly limit ?: number ;
546555 readonly offset ?: number ;
547556 readonly orderBy ?:
548557 | readonly [ string , "asc" | "desc" ]
549558 | readonly ( readonly [ string , "asc" | "desc" ] ) [ ] ;
559+ /** Column projection (fumadb `select`). Omit for all columns. Use on hot
560+ * paths whose rows carry heavy JSON columns the caller discards — e.g. a
561+ * tool row is ~KBs of schemas but invoke routing needs only the names. */
562+ readonly select ?: readonly CoreColumn < TName > [ ] ;
550563} ;
551- type CoreFindFirstOptions = Omit < CoreFindManyOptions , "limit" | "offset" > ;
564+ type CoreFindFirstOptions < TName extends CoreTableName = CoreTableName > = Omit <
565+ CoreFindManyOptions < TName > ,
566+ "limit" | "offset"
567+ > ;
568+ /** The narrowed row a projected query returns: the selected columns keep
569+ * their types, everything else is absent. */
570+ type CoreProjectedRow < TName extends CoreTableName , TSelect > = TSelect extends readonly ( infer K ) [ ]
571+ ? Pick < CoreRow < TName > , Extract < K , keyof CoreRow < TName > > >
572+ : CoreRow < TName > ;
552573
553574type LooseStorageDb = {
554575 readonly count : ( tableName : string , options ?: unknown ) => Promise < number > ;
@@ -603,20 +624,20 @@ const makeCoreDb = (fuma: ReturnType<typeof makeFumaClient>) => ({
603624 fuma . use ( `${ tableName } .deleteMany` , ( db ) =>
604625 asLooseStorageDb ( db ) . deleteMany ( tableName , options ) ,
605626 ) ,
606- findFirst : < TName extends CoreTableName > (
627+ findFirst : < TName extends CoreTableName , const TOptions extends CoreFindFirstOptions < TName > > (
607628 tableName : TName ,
608- options : CoreFindFirstOptions ,
609- ) : Effect . Effect < CoreRow < TName > | null , StorageFailure > =>
629+ options : TOptions ,
630+ ) : Effect . Effect < CoreProjectedRow < TName , TOptions [ "select" ] > | null , StorageFailure > =>
610631 fuma . use ( `${ tableName } .findFirst` , ( db ) =>
611632 asLooseStorageDb ( db ) . findFirst ( tableName , options ) ,
612- ) as Effect . Effect < CoreRow < TName > | null , StorageFailure > ,
613- findMany : < TName extends CoreTableName > (
633+ ) as Effect . Effect < CoreProjectedRow < TName , TOptions [ "select" ] > | null , StorageFailure > ,
634+ findMany : < TName extends CoreTableName , const TOptions extends CoreFindManyOptions < TName > > (
614635 tableName : TName ,
615- options : CoreFindManyOptions = { } ,
616- ) : Effect . Effect < readonly CoreRow < TName > [ ] , StorageFailure > =>
636+ options : TOptions = { } as TOptions ,
637+ ) : Effect . Effect < readonly CoreProjectedRow < TName , TOptions [ "select" ] > [ ] , StorageFailure > =>
617638 fuma . use ( `${ tableName } .findMany` , ( db ) =>
618639 asLooseStorageDb ( db ) . findMany ( tableName , options ) ,
619- ) as Effect . Effect < readonly CoreRow < TName > [ ] , StorageFailure > ,
640+ ) as Effect . Effect < readonly CoreProjectedRow < TName , TOptions [ "select" ] > [ ] , StorageFailure > ,
620641 updateMany : < TName extends CoreTableName > (
621642 tableName : TName ,
622643 options : {
@@ -2300,6 +2321,9 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
23002321
23012322 const toolsList = ( filter ?: ToolListFilter ) : Effect . Effect < readonly Tool [ ] , StorageFailure > =>
23022323 Effect . gen ( function * ( ) {
2324+ // Projected: the list surface is metadata (address, description,
2325+ // annotations) — loading every tool's input/output schema JSON made
2326+ // an unbounded list scale with schema bytes, not tool count.
23032327 const rows = yield * core . findMany ( "tool" , {
23042328 where : ( b : AnyCb ) =>
23052329 b . and (
@@ -2311,6 +2335,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
23112335 ? true
23122336 : b ( "connection" , "=" , String ( filter . connection ) ) ,
23132337 ) ,
2338+ select : TOOL_INVOCATION_COLUMNS ,
23142339 } ) ;
23152340 const includeBlocked = filter ?. includeBlocked ?? false ;
23162341 const policyRows = yield * core . findMany ( "tool_policy" , { } ) ;
@@ -2650,7 +2675,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
26502675
26512676 const TOOL_SUGGESTION_LIMIT = 5 ;
26522677
2653- const toolSuggestions = ( rows : readonly ToolRow [ ] ) : readonly ToolAddress [ ] =>
2678+ const toolSuggestions = ( rows : readonly ToolInvocationRow [ ] ) : readonly ToolAddress [ ] =>
26542679 rows . map ( ( row ) => rowToTool ( row ) . address ) ;
26552680
26562681 const toolRowsForConnectionWhere = ( parsed : ParsedToolAddress ) => ( b : AnyCb ) =>
@@ -2662,7 +2687,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
26622687
26632688 const searchToolRowsForConnection = (
26642689 parsed : ParsedToolAddress ,
2665- ) : Effect . Effect < readonly ToolRow [ ] , StorageFailure > =>
2690+ ) : Effect . Effect < readonly ToolInvocationRow [ ] , StorageFailure > =>
26662691 core . findMany ( "tool" , {
26672692 where : ( b : AnyCb ) =>
26682693 b . and (
@@ -2674,15 +2699,17 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
26742699 ) ,
26752700 orderBy : [ "name" , "asc" ] ,
26762701 limit : TOOL_SUGGESTION_LIMIT ,
2702+ select : TOOL_INVOCATION_COLUMNS ,
26772703 } ) ;
26782704
26792705 const findToolRowsForConnection = (
26802706 parsed : ParsedToolAddress ,
2681- ) : Effect . Effect < readonly ToolRow [ ] , StorageFailure > =>
2707+ ) : Effect . Effect < readonly ToolInvocationRow [ ] , StorageFailure > =>
26822708 core . findMany ( "tool" , {
26832709 where : toolRowsForConnectionWhere ( parsed ) ,
26842710 orderBy : [ "name" , "asc" ] ,
26852711 limit : TOOL_SUGGESTION_LIMIT ,
2712+ select : TOOL_INVOCATION_COLUMNS ,
26862713 } ) ;
26872714
26882715 const execute = (
@@ -2743,7 +2770,9 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
27432770 return yield * new ToolNotFoundError ( { address } ) ;
27442771 }
27452772
2746- // Find the tool row.
2773+ // Find the tool row — projected: invoke needs routing/policy fields
2774+ // only, never the multi-KB input/output schema JSON (`tools.schema`
2775+ // is the schema-bearing surface).
27472776 const row = yield * core . findFirst ( "tool" , {
27482777 where : ( b : AnyCb ) =>
27492778 b . and (
@@ -2752,6 +2781,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
27522781 b ( "connection" , "=" , String ( parsed . connection ) ) ,
27532782 b ( "name" , "=" , String ( parsed . tool ) ) ,
27542783 ) ,
2784+ select : TOOL_INVOCATION_COLUMNS ,
27552785 } ) ;
27562786 if ( ! row ) {
27572787 const searchMatches = yield * searchToolRowsForConnection ( parsed ) ;
0 commit comments