public static CompositeKernel UseProgressiveLearning( this CompositeKernel kernel, HttpClient httpClient = null) { kernel.Bootstrapping(); var fromUrlOption = new Option <Uri>( "--from-url", "Specify lesson source URL"); var fromFileOption = new Option <FileInfo>( "--from-file", description: "Specify lesson source file", parseArgument: result => { var filePath = result.Tokens.Single().Value; var fromUrlResult = result.FindResultFor(fromUrlOption); if (fromUrlResult is not null) { result.ErrorMessage = $"The {fromUrlResult.Token.Value} and {(result.Parent as OptionResult).Token.Value} options cannot be used together"; return(null); } if (!File.Exists(filePath)) { result.ErrorMessage = Resources.Instance.FileDoesNotExist(filePath); return(null); } return(new FileInfo(filePath)); }); var startCommand = new Command("#!start-lesson") { fromFileOption, fromUrlOption }; startCommand.Handler = CommandHandler.Create <Uri, FileInfo, KernelInvocationContext>(StartCommandHandler); kernel.AddDirective(startCommand); return(kernel); async Task StartCommandHandler(Uri fromUrl, FileInfo fromFile, KernelInvocationContext context) { InteractiveDocument document = fromFile switch { { } => await NotebookLessonParser.ReadFileAsInteractiveDocument(fromFile, kernel), _ => await NotebookLessonParser.LoadNotebookFromUrl(fromUrl, httpClient) }; NotebookLessonParser.Parse(document, out var lessonDefinition, out var challengeDefinitions); var challenges = challengeDefinitions.Select(b => b.ToChallenge()).ToList(); challenges.SetDefaultProgressionHandlers(); Lesson.From(lessonDefinition); Lesson.SetChallengeLookup(queryName => { return(challenges.FirstOrDefault(c => c.Name == queryName)); }); await kernel.StartLesson(); await Lesson.StartChallengeAsync(challenges.First()); await kernel.InitializeChallenge(Lesson.CurrentChallenge); }