diff --git a/docs/r0b0t.ipynb b/docs/r0b0t.ipynb deleted file mode 100644 index ffc9165..0000000 --- a/docs/r0b0t.ipynb +++ /dev/null @@ -1,128 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Designing a structure from the bottom up: r0b0t" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**r0b0t** is a small program for interacting with Large Language Models you can find [here](https://github.com/lamg/r0b0t). This article shows how it was restructured by finding complex operations that could be contained and exposed through simpler interfaces." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The [Stream](https://github.com/lamg/r0b0t/tree/master/Lib/Stream) module" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A module is a group of elements whose interactions can be contained, abstracted and hidden under a small interface compared to the one that would be the result from exposing their full domain.\n", - "The modules defined below follow that principle\n", - "\n", - "Stream exposes the following interface\n", - "\n", - "```fsharp\n", - "type GetProvider = unit -> AsyncSeq\n", - "type StopInsert = {insertWord: string -> unit; stop: unit -> unit}\n", - "\n", - "val main: GetProvider -> StopInsert -> unit\n", - "```\n", - "\n", - "The purpose of this module is to consume a `None` terminated sequence of strings, `AsyncSeq`, generated by an LLM and send it to a GUI, hidden in the implementation of [StopInsert](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/Stream/Types.fs#L7). The choice of this module as a starting point comes from the observation that this is one of the places where the most complex operations take place, namely the coordination between the consumption of asynchronous data and its display on a GUI.\n", - "\n", - "By focusing on such operations first, I try to create abstractions that will effectively contain some complexity, but at the same time expose what is needed for a correct implementation. In this way, experimentation and development can take place within the modules without external interference. This doesn't mean that the components are or should be reusable, as their interfaces are quite specific to this project." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The [GetProviderImpl](https://github.com/lamg/r0b0t/blob/master/Lib/GetProviderImpl.fs) module" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The above module relies on [GetProvider](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/Stream/Types.fs#L5) and [StopInsert](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/Stream/Types.fs#L7). We can focus now on implementing them. Let's start with a module for [GetProvider](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/Stream/Types.fs#L5):\n", - "\n", - "```fsharp\n", - "type Conf =\n", - " { active: Active\n", - " providers: Map }\n", - "\n", - "val initConf: ProviderModule list -> Provider -> Conf\n", - "val newGetProvider: (unit -> Conf) -> (unit -> Prompt) -> Stream.Types.GetProvider \n", - "```\n", - "\n", - "You may notice that instead of `Conf` and `Prompt`, [newGetProvider](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/GetProviderImpl.fs#L43) gets `unit -> Conf` and `unit -> Prompt`. The reason for this is that the configuration and the prompt are values stored in mutable variables, in the user interface implementation." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The [ProviderModule](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/GetProviderImpl.fs#L16) implementation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the module above, `initConf` relies on `ProviderModule`, which is the interface that hides the interaction with GitHub Copilot, OpenAI's API, or any others that might be added in the future. Implementations for these can be found in the [ProviderModuleImpl](https://github.com/lamg/r0b0t/tree/master/Lib/ProviderModuleImpl) directory.\n", - "\n", - "Their exposed interface is [this](https://github.com/lamg/r0b0t/blob/348309a979379b765779b575839eb292e21250bf/Lib/GetProviderImpl.fs#L16)\n", - "\n", - "```fsharp\n", - "val providerModule: GetProviderImpl.ProviderModule\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## [GUI](https://github.com/lamg/r0b0t/blob/master/Lib/GUI.fs) module: initialization and mutable state" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the above modules implemented, all that remains is to create the context in which the configuration is used and mutated by the GUI. This allows us to call `initConf`, `newGetProvider` and finally `Stream.main` to get answers from the LLMs. `Stream.main` also relies on `StopInsert`, but its implementation turned out to be so tied to the `GUI` module that it didn't deserve a separate one." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".NET (C#)", - "language": "C#", - "name": ".net-csharp" - }, - "language_info": { - "name": "python" - }, - "polyglot_notebook": { - "kernelInfo": { - "defaultKernelName": "csharp", - "items": [ - { - "aliases": [], - "name": "csharp" - } - ] - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}