(ctx context.Context, dag *dagql.Server)
| 1123 | } |
| 1124 | |
| 1125 | func (obj *ModuleObject) installEntrypointMethods(ctx context.Context, dag *dagql.Server) error { |
| 1126 | moduleID, err := NewUserMod(obj.Module).ResultCallModule(ctx) |
| 1127 | if err != nil { |
| 1128 | return fmt.Errorf("failed to resolve module identity for entrypoint object %q: %w", obj.TypeDef.Name, err) |
| 1129 | } |
| 1130 | constructorName := gqlFieldName(obj.Module.Self().Name()) |
| 1131 | |
| 1132 | // Build constructor arg specs from the module's type definition |
| 1133 | // rather than looking them up from the server — the constructor |
| 1134 | // is not installed on the outer server when Entrypoint is set. |
| 1135 | var constructorArgs []dagql.InputSpec |
| 1136 | if obj.TypeDef.Constructor.Valid { |
| 1137 | fn, err := NewModFunction(ctx, obj.Module, obj.TypeDef, obj.TypeDef.Constructor.Value.Self()) |
| 1138 | if err != nil { |
| 1139 | return fmt.Errorf("failed to create constructor function: %w", err) |
| 1140 | } |
| 1141 | if err := fn.mergeUserDefaultsTypeDefs(ctx); err != nil { |
| 1142 | return fmt.Errorf("failed to merge constructor user defaults: %w", err) |
| 1143 | } |
| 1144 | spec, err := fn.metadata.FieldSpec(ctx, NewUserMod(obj.Module)) |
| 1145 | if err != nil { |
| 1146 | return fmt.Errorf("failed to get constructor field spec: %w", err) |
| 1147 | } |
| 1148 | constructorArgs = spec.Args.Inputs(dag.View) |
| 1149 | } |
| 1150 | |
| 1151 | // Install `with` field on Query that stores constructor args for |
| 1152 | // entrypoint proxy resolvers to forward to the constructor. |
| 1153 | // Only installed when the constructor has arguments. |
| 1154 | if len(constructorArgs) > 0 { |
| 1155 | // Use the original constructor's description if available, |
| 1156 | // since `with` IS the user-facing constructor. |
| 1157 | withDesc := obj.TypeDef.Constructor.Value.Self().Description |
| 1158 | if withDesc == "" { |
| 1159 | withDesc = fmt.Sprintf("Configure the %s constructor arguments.", obj.Module.Self().Name()) |
| 1160 | } |
| 1161 | withSpec := dagql.FieldSpec{ |
| 1162 | Name: "with", |
| 1163 | Description: withDesc, |
| 1164 | Type: &Query{}, |
| 1165 | Module: moduleID, |
| 1166 | Args: dagql.NewInputSpecs(constructorArgs...), |
| 1167 | DoNotCache: "Pure routing; the inner module constructor has its own caching policy.", |
| 1168 | NoTelemetry: true, |
| 1169 | } |
| 1170 | dag.Root().ObjectType().Extend( |
| 1171 | withSpec, |
| 1172 | func(ctx context.Context, self dagql.AnyResult, args map[string]dagql.Input) (dagql.AnyResult, error) { |
| 1173 | query, ok := dagql.UnwrapAs[*Query](self) |
| 1174 | if !ok { |
| 1175 | return nil, fmt.Errorf("expected *Query, got %T", self) |
| 1176 | } |
| 1177 | // store only the args the caller actually provided — found in |
| 1178 | // the call frame, built from the query AST — so the |
| 1179 | // constructor still applies its own defaults, including .env |
| 1180 | // user defaults, to the rest. |
| 1181 | var explicit map[string]bool |
| 1182 | if frame := dagql.CurrentCall(ctx); frame != nil { |
no test coverage detected