commit 1e81f417eff1d6f3969b2e2e5a12f925ed391fe9 Author: alejandro-angulo Date: Sat May 31 16:26:11 2025 -0700 Initial commit diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..77eccda --- /dev/null +++ b/.envrc @@ -0,0 +1,15 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" +fi + +watch_file flake.nix +watch_file flake.lock +if ! use flake . --no-pure-eval +then + echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2 +fi + +# NOTE: Add a line like this to .env +# export ANTHROPIC_API_KEY=XXX +dotenv + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f5ec81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.devenv +.env +agent diff --git a/README.md b/README.md new file mode 100644 index 0000000..6f1cb26 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# go-ai-agent + +This repo contains the code for Thorsten Ball's "How to Build an Agent" post +(see [here](https://ampcode.com/how-to-build-an-agent)). + +## Setup + +This repo contains everything you need to get a development environment ready +to go through the tutorial. You'll first need to make sure `nix` and `direnv` +are installed. An anthropic API key is also required (one can be generated +[here](https://console.anthropic.com/)). + +### Install Nix + +Nix is package manager that allows us to "make reproducible, declarative and +reliable systems" (according to [their site](https://nixos.org/)). + +Nix can be installed using [the Determinate Systems +installer](https://github.com/DeterminateSystems/nix-installer). Run the +following command: + +```bash +curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate +``` + +### Install Direnv + +[Direnv](https://direnv.net/) is a tool that enables us to quickly load and +unload an environemnt when we enter and leave a directory. + +Direnv is available in homebrew. Run the following command: + +```bash +brew install direnv +``` + +Once it's installed you'll have to configure your shell. If you're using ZSH +run the following: + +```bash +echo 'eval "$(direnv hook bash)"' >> ~/.zshrc +``` + +NOTE: You'll have to start a new terminal session for the changes in `~/.zshrc` +to take effect! + +For all other shells, refer [here](https://direnv.net/docs/hook.html). + +### Configure Anthropic API Key + +First, generate an Anthropic API key from [the +console](https://console.anthropic.com/). This repo has a `.envrc` (direnv +configuration file) that will read from a `.env` file (not committed to this +repo since we'll use it to house secrets). Once you have your API key, run the +following (make sure to replace the placeholder text with your actual API key): + +```bash +echo 'export ANTHROPIC_API_KEY=' > .env +``` + +### Build the Development Environment + +We're now ready to build the development environment. Direnv configuration +files (`.envrc` files) have to be explicitly trusted before they take effect. +Run the following to build and automatically enter the development environment: + +```bash +direnv allow +``` + +Once that runs, nix will do its thing and set up the environment. This might +take a bit. Once it's done you can check to see if it worked by running the following: + +```bash +which go +``` + +This should spit out a value like +`/nix/store/fd2s1z3why92qn8w7j6r0xlarikpv27v-go-1.24.2/bin/go`. + +## Follow the Tutorial + +You can now follow [the tutorial](https://ampcode.com/how-to-build-an-agent). +This repo also has some branches containing the tutorial code as well if you'd +prefer to not copy/paste (or preferably type it out) yourself. Branches +`step1`, `step2`, `step3`, `step4` correspond to the different parts of the +tutorial. `step1` is the initial setup of the conversation loop and the other +steps correspond to the three tools you'll implement as part of the tutorial. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3560984 --- /dev/null +++ b/flake.lock @@ -0,0 +1,262 @@ +{ + "nodes": { + "cachix": { + "inputs": { + "devenv": [ + "devenv" + ], + "flake-compat": [ + "devenv" + ], + "git-hooks": [ + "devenv" + ], + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1744206633, + "narHash": "sha256-pb5aYkE8FOoa4n123slgHiOf1UbNSnKe5pEZC+xXD5g=", + "owner": "cachix", + "repo": "cachix", + "rev": "8a60090640b96f9df95d1ab99e5763a586be1404", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "latest", + "repo": "cachix", + "type": "github" + } + }, + "devenv": { + "inputs": { + "cachix": "cachix", + "flake-compat": "flake-compat", + "git-hooks": "git-hooks", + "nix": "nix", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748688634, + "narHash": "sha256-S9J86Dn05c1Skk1dpOEUM2AgO+tkiAyaGXT2PZLMcRM=", + "owner": "cachix", + "repo": "devenv", + "rev": "df38744269cc4ea8cee9e36fe882e9ef786df11b", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "devenv", + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "devenv" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1746537231, + "narHash": "sha256-Wb2xeSyOsCoTCTj7LOoD6cdKLEROyFAArnYoS+noCWo=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "fa466640195d38ec97cf0493d6d6882bc4d14969", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "devenv", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "libgit2": { + "flake": false, + "locked": { + "lastModified": 1697646580, + "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=", + "owner": "libgit2", + "repo": "libgit2", + "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5", + "type": "github" + }, + "original": { + "owner": "libgit2", + "repo": "libgit2", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": [ + "devenv" + ], + "flake-parts": "flake-parts", + "libgit2": "libgit2", + "nixpkgs": "nixpkgs_2", + "nixpkgs-23-11": [ + "devenv" + ], + "nixpkgs-regression": [ + "devenv" + ], + "pre-commit-hooks": [ + "devenv" + ] + }, + "locked": { + "lastModified": 1745930071, + "narHash": "sha256-bYyjarS3qSNqxfgc89IoVz8cAFDkF9yPE63EJr+h50s=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b455edf3505f1bf0172b39a735caef94687d0d9c", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.24", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1733212471, + "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1717432640, + "narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "88269ab3044128b7c2f4c7d68448b2fb50456870", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1746807397, + "narHash": "sha256-zU2z0jlkJGWLhdNr/8AJSxqK8XD0IlQgHp3VZcP56Aw=", + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "c5208b594838ea8e6cca5997fbf784b7cca1ca90", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs_3", + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d0978fe --- /dev/null +++ b/flake.nix @@ -0,0 +1,50 @@ +{ + inputs = { + nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling"; + systems.url = "github:nix-systems/default"; + devenv.url = "github:cachix/devenv"; + devenv.inputs.nixpkgs.follows = "nixpkgs"; + }; + + nixConfig = { + extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw="; + extra-substituters = "https://devenv.cachix.org"; + }; + + outputs = + { + self, + nixpkgs, + devenv, + systems, + ... + }@inputs: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + in + { + packages = forEachSystem (system: { + devenv-up = self.devShells.${system}.default.config.procfileScript; + devenv-test = self.devShells.${system}.default.config.test; + }); + + devShells = forEachSystem ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = devenv.lib.mkShell { + inherit inputs pkgs; + modules = [ + { + # https://devenv.sh/reference/options/ + languages.go.enable = true; + languages.javascript.enable = true; + } + ]; + }; + } + ); + }; +}