{ description = "slopbot - Zulip bot with stock price lookups and LLM replies"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; agentd = { url = "github:bsima/agentd"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, agentd }: let system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; pythonEnv = pkgs.python3.withPackages (ps: [ ps.zulip ps.yfinance ps.openai ps.requests ]); agent = pkgs.rustPlatform.buildRustPackage { pname = "agent"; version = "0.1.0"; src = agentd; cargoLock.lockFile = "${agentd}/Cargo.lock"; cargoBuildFlags = [ "-p" "agent" ]; doCheck = false; }; researchPython = pkgs.python3.withPackages (ps: [ ps.trafilatura ]); slopSearch = pkgs.writeShellApplication { name = "slop-search"; runtimeInputs = [ pkgs.coreutils pkgs.curl pkgs.python3 ]; text = '' if [ "$#" -eq 0 ]; then echo "usage: slop-search QUERY" >&2 exit 2 fi if [ -z "''${KAGI_API_KEY:-}" ]; then echo "error: KAGI_API_KEY is not set" >&2 exit 1 fi query="$*" encoded="$(${pkgs.python3}/bin/python -c 'import sys, urllib.parse; print(urllib.parse.urlencode({"q": " ".join(sys.argv[1:])}))' "$@")" tmp="$(mktemp)" trap 'rm -f "$tmp"' EXIT curl -fsS \ -H "Authorization: Bot ''${KAGI_API_KEY}" \ -H "Accept: application/json" \ "https://kagi.com/api/v0/search?''${encoded}" \ -o "$tmp" ${pkgs.python3}/bin/python - "$query" "$tmp" <<'PY' import json import sys query, path = sys.argv[1], sys.argv[2] payload = json.load(open(path)) items = payload.get("data") or [] results = [] for item in items: if not item.get("url"): continue item_type = item.get("t") or item.get("type") or "" if item_type and item_type != "search_result": continue results.append(item) if len(results) >= 8: break print(f"QUERY: {query}\n") for i, item in enumerate(results, 1): title = item.get("title") or "untitled" url = item.get("url") or "" snippet = item.get("snippet") or item.get("description") or "" print(f"[{i}] {title}\nURL: {url}\nSNIPPET: {snippet}\n") PY ''; }; slopFetch = pkgs.writeShellApplication { name = "slop-fetch"; runtimeInputs = [ pkgs.coreutils pkgs.curl researchPython ]; text = '' if [ "$#" -ne 1 ]; then echo "usage: slop-fetch URL" >&2 exit 2 fi url="$1" tmp="$(mktemp)" trap 'rm -f "$tmp"' EXIT curl -fsSL --max-time 20 -A 'slopbot/1.0' "$url" -o "$tmp" ${researchPython}/bin/python - "$url" "$tmp" <<'PY' import sys import trafilatura url, path = sys.argv[1], sys.argv[2] html = open(path, "rb").read() text = trafilatura.extract(html, url=url, include_comments=False, include_tables=False) if not text: print(f"error: could not extract readable text from {url}", file=sys.stderr) sys.exit(1) print(text[:12000]) PY ''; }; slopTools = pkgs.symlinkJoin { name = "slopbot-agent-tools"; paths = [ slopSearch slopFetch ]; }; in { devShells.${system}.default = pkgs.mkShell { buildInputs = [ pythonEnv agent slopTools ]; shellHook = '' echo "slopbot dev shell ready" echo "Run: python main.py" ''; }; checks.${system}.default = pkgs.runCommand "slopbot-tests" { buildInputs = [ pythonEnv ]; } '' cp -r ${self} source cd source chmod -R u+w . python -m unittest discover -s tests touch $out ''; packages.${system} = rec { default = slopbot; slopbot = pkgs.writeShellScriptBin "slopbot" '' cd "''${SLOPBOT_DIR:-/home/ben/src/bsima/slopbot}" export PATH=${slopTools}/bin export SLOPBOT_AGENT=${agent}/bin/agent export SLOPBOT_AGENT_PATH=${slopTools}/bin exec ${pythonEnv}/bin/python ${./main.py} ''; inherit agent slopTools slopSearch slopFetch; }; }; }