Packages
nous
0.17.1
0.17.1
0.17.0
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.17
0.12.16
0.12.15
0.12.14
0.12.13
0.12.12
0.12.11
0.12.9
0.12.7
0.12.6
0.12.5
0.12.3
0.12.2
0.12.0
0.11.3
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.5.0
AI agent framework for Elixir with multi-provider LLM support
Current section
Files
Jump to
Current section
Files
mix.exs
defmodule Nous.MixProject do
use Mix.Project
@version "0.17.1"
@source_url "https://github.com/nyo16/nous"
def project do
[
app: :nous,
version: @version,
elixir: "~> 1.18",
start_permanent: Mix.env() == :prod,
deps: deps(),
docs: docs(),
aliases: aliases(),
description: "AI agent framework for Elixir with multi-provider LLM support",
source_url: @source_url,
package: package(),
elixirc_paths: elixirc_paths(Mix.env()),
# hackney is an optional backend (see deps); without this, apps that
# depend on nous without hackney get ":hackney is not available"
# warnings when compiling the dep.
elixirc_options: [no_warn_undefined: [:hackney, :hackney_pool]],
# Coverage ratchet. `mix test --cover` defaults to a 90% threshold this
# project has never met, and no CI job ran it, so the gate was purely
# decorative. 59 is the current measured floor (60.05%, :llm/:llama
# excluded as in CI) with ~1pp of headroom, enforced by the `coverage`
# job in .github/workflows/ci.yml. Raise it as coverage improves; never
# lower it. History: 56.80% at the audit, 57 after the perf wave, 59 once
# the provider/web_fetch/prompt_template suites landed.
#
# :threshold MUST be nested under :summary — a bare
# `test_coverage: [threshold: n]` is silently ignored and you keep the
# 90% default (Mix.Tasks.Test.Coverage `get_threshold(true)`).
test_coverage: [summary: [threshold: 59]],
dialyzer: [
plt_file: {:no_warn, "priv/plts/dialyzer.plt"},
plt_add_apps: [:mix, :ex_unit]
]
]
end
def application do
[
extra_applications: [:logger],
mod: {Nous.Application, []},
# hackney's :default pool starts automatically when the :hackney
# application starts; ensuring it's listed here is just defensive.
included_applications: []
]
end
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
defp deps do
[
# YAML (for evaluation framework)
{:yaml_elixir, "~> 2.9"},
# Validation
{:ecto, "~> 3.11"},
# HTTP clients for all LLM providers.
# Finch/Req is the default backend for both one-shot and streaming.
# Hackney is an opt-in alternative for SSE/long-streaming bodies — its
# `:async, :once` mode is truly pull-based, so the consumer paces the
# producer and a slow consumer can't OOM us via mailbox accumulation.
# (Finch.stream/5's callback is push-based; a fast LLM + slow consumer =
# unbounded mailbox growth — see review M-12.) To use the hackney
# backend, declare `{:hackney, "~> 4.0"}` in your app's deps and select
# it via `NOUS_HTTP_BACKEND=hackney` (or the streaming variant).
{:finch, "~> 0.19"},
# req 0.7+: `finch:` takes options (`[name: ...]`) — the bare-atom shape
# our backends used through 0.6 is deprecated with a per-request IO.warn
# and slated for removal, so the call sites use the new shape and the
# constraint floor moves with them.
{:req, "~> 0.7"},
{:hackney, "~> 4.0", optional: true},
# Google Cloud auth for Vertex AI (optional — add to your app's deps to unlock)
{:goth, "~> 1.4", optional: true},
# HTML parsing (for web content extraction in research tools)
{:floki, "~> 0.36", optional: true},
# Code Mode's JS runtime: an embedded Deno isolate via Rustler NIFs
# (optional — add to your app's deps to unlock `Nous.CodeRuntime.JS`).
# 0.4 is the floor, not a preference: it is the first version with an
# execution interrupt that terminates a `while(true){}` guest, an opt-in
# `:apply` allowlist rather than an always-on arbitrary-module gateway,
# and a `:max_heap_mb` cap. Code Mode needs all three, so an earlier
# tyrex is not "mostly fine" — it is unusable for model-authored code.
{:tyrex, "~> 0.4", optional: true},
# Memory system store backends (all optional — add to your app's deps to unlock)
# {:exqlite, "~> 0.27", optional: true},
# {:duckdbex, "~> 0.3", optional: true},
# Local LLM inference via llama.cpp NIFs (optional — add to your app's deps
# to unlock the LlamaCpp provider). optional: true keeps it out of
# downstream apps' builds unless they opt in, while still being available
# for Nous's own dev/test (e.g. the tagged llamacpp smoke test).
{:llama_cpp_ex, "~> 0.8", optional: true},
# Memory system embedding providers (all optional — add to your app's deps to unlock)
# {:bumblebee, "~> 0.6", optional: true},
# {:exla, "~> 0.9", optional: true},
# Process execution for command hooks and the Bash tool. A NIF-based
# runner is used (over System.cmd/Port) for fine-grained process-tree
# control and reliable kill-on-timeout of child processes. `~> 1.0` (not
# the tighter `~> 1.0.4`) so downstream apps can pick up 1.x fixes without
# waiting on a nous release.
{:net_runner, "~> 1.0"},
# Telemetry
{:telemetry, "~> 1.2"},
# Note: For Prometheus metrics, users can add {:prom_ex, "~> 1.11"} and {:plug, "~> 1.18"}
# to their deps. The Nous.PromEx.Plugin will automatically be available.
# Dev/Test
# >= 0.34 for `mix docs --warnings-as-errors`, which the `docs` CI job runs.
{:ex_doc, "~> 0.34", only: :dev, runtime: false},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
# optional (not only: :test) so the `~> 2.1` constraint reaches downstream
# resolvers — Nous.PubSub integrates with phoenix_pubsub at runtime (guarded
# by Code.ensure_loaded?), and apps that bring their own copy should see a
# compatible-version requirement rather than a hidden test-only pin.
{:phoenix_pubsub, "~> 2.1", optional: true},
# Bypass = in-test HTTP server for exercising the streaming pipeline
# without hitting real LLM endpoints. `only: :test`: nothing in :dev uses
# Bypass, and it drags in plug_cowboy/cowboy/ranch — currently carrying
# HIGH advisories (see `mix hex.audit`) — which would otherwise be
# compiled and loadable while `Nous.Application` runs in :dev.
{:bypass, "~> 2.1", only: :test},
# Benchee = the bench/ scripts. Also in :test because
# `bench/http_backend.exs` starts an in-process plug_cowboy server, and
# plug_cowboy now only reaches the build through Bypass in :test:
#
# MIX_ENV=test mix run bench/http_backend.exs
{:benchee, "~> 1.3", only: [:dev, :test]}
]
end
defp docs do
[
main: "readme",
extras: [
"README.md",
"CHANGELOG.md",
{"AGENTS.md", title: "AI Agent Guide (AGENTS.md)"},
{"CONTRIBUTING.md", title: "Contributing"},
# Getting Started
{"docs/README.md", filename: "docs_index", title: "Documentation Hub"},
{"docs/getting-started.md", filename: "getting_started", title: "Getting Started Guide"},
# Examples Overview
{"examples/README.md", filename: "examples_overview", title: "Examples Overview"},
{"docs/guides/README.md", filename: "guides_index", title: "All Guides"},
# Livebook notebooks (ex_doc renders .livemd natively)
{"notebooks/01_intro_to_nous.livemd",
filename: "notebook_intro", title: "Livebook: Intro to Nous"},
{"notebooks/02_tools_and_agents.livemd",
filename: "notebook_tools", title: "Livebook: Tools & Agents"},
{"notebooks/03_rag_knowledge_base.livemd",
filename: "notebook_rag", title: "Livebook: RAG & Knowledge Base"},
# Production Guides
{"docs/guides/skills.md", filename: "skills", title: "Skills Guide"},
{"docs/guides/hooks.md", filename: "hooks", title: "Hooks Guide"},
{"docs/guides/code_mode.md", filename: "code_mode", title: "Code Mode Guide"},
{"docs/guides/liveview-integration.md",
filename: "liveview_integration", title: "Phoenix LiveView Integration"},
{"docs/guides/best_practices.md",
filename: "best_practices", title: "Production Best Practices"},
{"docs/guides/tool_development.md",
filename: "tool_development", title: "Tool Development Guide"},
{"docs/guides/troubleshooting.md",
filename: "troubleshooting", title: "Troubleshooting Guide"},
{"docs/guides/migration_guide.md", filename: "migration_guide", title: "Migration Guide"},
{"docs/guides/evaluation.md",
filename: "evaluation", title: "Evaluation Framework Guide"},
{"docs/guides/structured_output.md",
filename: "structured_output", title: "Structured Output Guide"},
{"docs/guides/workflows.md", filename: "workflows", title: "Workflow Engine Guide"},
{"docs/guides/memory.md", filename: "memory", title: "Memory System Guide"},
{"docs/guides/context.md", filename: "context", title: "Context & Dependencies Guide"},
{"docs/guides/transcript.md", filename: "transcript", title: "Transcripts & Compaction"},
{"docs/guides/knowledge_base.md",
filename: "knowledge_base", title: "Knowledge Base Guide"},
{"docs/guides/permissions.md",
filename: "permissions", title: "Permissions & Guardrails Guide"},
{"docs/guides/observability.md",
filename: "observability", title: "Observability & Telemetry Guide"},
# Orchestration & Multi-Agent
{"docs/guides/teams.md", filename: "teams", title: "Multi-Agent Teams Guide"},
{"docs/guides/decisions.md", filename: "decisions", title: "Decision Graph Guide"},
{"docs/guides/research.md", filename: "research", title: "Deep Research Guide"},
# Providers & Backends
{"docs/guides/providers.md", filename: "providers", title: "Providers Overview"},
{"docs/guides/custom_providers.md",
filename: "custom_providers", title: "Custom Providers Guide"},
{"docs/guides/http_backends.md", filename: "http_backends", title: "HTTP Backends Guide"},
{"docs/guides/vertex_ai_setup.md",
filename: "vertex_ai_setup", title: "Vertex AI Setup Guide"},
{"docs/guides/fallback.md", filename: "fallback", title: "Fallback Chains Guide"},
# Design Documents
{"docs/design/llm_council_design.md",
filename: "council_design", title: "LLM Council Design (Proposal)"},
{"docs/benchmarks/http_backend.md",
filename: "http_backend_benchmark", title: "HTTP Backend Benchmark"}
],
source_ref: "v#{@version}",
source_url: @source_url,
# Internal modules (`@moduledoc false`). AGENTS.md's "What NOT to use"
# section and older CHANGELOG entries name them in code style; without
# this, ExDoc tries to autolink each one and warns "references module
# ... but it is hidden". This list is the single place the hidden set is
# spelled out — if you hide a module and mention it in prose, add it
# here; if you un-hide one, remove it and the warning tells you where
# the stale reference is.
skip_code_autolink_to: [
"Nous.AgentRunner.IterationLoop",
"Nous.AgentRunner.PromptAssembly",
"Nous.AgentRunner.RequestDispatch",
"Nous.AgentRunner.Streaming",
"Nous.AgentRunner.ToolExecution",
"Nous.Application",
"Nous.JSON",
"Nous.Memory.Embedding.Bumblebee.ServingHolder",
"Nous.Memory.Embedding.Bumblebee.ServingSupervisor",
"Nous.OutputSchema.UseMacro",
"Nous.Persistence.ETS.TableOwner",
"Nous.Util",
"Nous.Workflow.Checkpoint.ETS.TableOwner",
"Nous.Workflow.Engine.Executor",
"Nous.Workflow.Engine.ParallelExecutor",
"Nous.Workflow.Engine.StateMerger"
],
groups_for_extras: [
"Getting Started": [
"readme.html",
"docs_index.html",
"getting_started.html",
"examples_overview.html",
"guides_index.html",
"notebook_intro.html",
"notebook_tools.html",
"notebook_rag.html"
],
"Production Guides": [
"skills.html",
"hooks.html",
"liveview_integration.html",
"best_practices.html",
"tool_development.html",
"troubleshooting.html",
"migration_guide.html",
"evaluation.html",
"structured_output.html",
"memory.html",
"context.html",
"transcript.html",
"knowledge_base.html",
"permissions.html",
"observability.html"
],
"Orchestration & Multi-Agent": [
"teams.html",
"decisions.html",
"research.html",
"workflows.html"
],
"Providers & Backends": [
"providers.html",
"custom_providers.html",
"http_backends.html",
"vertex_ai_setup.html",
"fallback.html"
],
Design: [
"council_design.html",
"http_backend_benchmark.html"
],
Reference: [
"changelog.html",
"agents.html",
"contributing.html"
]
],
groups_for_modules: [
"Core API": [
Nous,
Nous.Agent,
Nous.Agent.Context,
Nous.Agent.Behaviour,
Nous.Agent.Callbacks,
Nous.ReActAgent,
Nous.Transcript,
Nous.LLM,
Nous.RunContext
],
"Agent Implementations": [
Nous.Agents.BasicAgent,
Nous.Agents.ReActAgent
],
"Agent Execution": [
Nous.AgentRunner,
Nous.AgentServer
],
"Model Configuration": [
Nous.Model,
Nous.ModelDispatcher,
Nous.Fallback
],
Providers: [
Nous.Provider,
Nous.Providers.HTTP,
Nous.Providers.HTTP.JSONArrayParser,
Nous.Providers.OpenAI,
Nous.Providers.OpenAICompatible,
Nous.Providers.Anthropic,
Nous.Providers.Custom,
Nous.Providers.Gemini,
Nous.Providers.Mistral,
Nous.Providers.LMStudio,
Nous.Providers.VertexAI,
Nous.Providers.LlamaCpp,
Nous.Providers.VLLM,
Nous.Providers.SGLang
],
"Messages & Streaming": [
Nous.Message,
Nous.Message.ContentPart,
Nous.Messages,
Nous.Messages.OpenAI,
Nous.Messages.Anthropic,
Nous.Messages.Gemini,
Nous.StreamNormalizer,
Nous.StreamNormalizer.OpenAI,
Nous.StreamNormalizer.Anthropic,
Nous.StreamNormalizer.Gemini,
Nous.StreamNormalizer.LlamaCpp,
Nous.StreamNormalizer.ToolCallAccumulator
],
"HTTP Backends": [
Nous.HTTP.Backend,
Nous.HTTP.Backend.Req,
Nous.HTTP.Backend.Hackney,
Nous.HTTP.StreamBackend,
Nous.HTTP.StreamBackend.Req,
Nous.HTTP.StreamBackend.Hackney,
Nous.HTTP.Buffer
],
"Tool System": [
Nous.Tool,
Nous.Tool.Behaviour,
Nous.Tool.ContextUpdate,
Nous.Tool.Validator,
Nous.Tool.Registry,
Nous.Tool.Schema,
Nous.ToolSchema,
Nous.ToolExecutor,
Nous.ToolCall
],
"Structured Output": [
Nous.OutputSchema,
Nous.OutputSchema.Validator
],
"Research Tools": [
Nous.Tools.WebFetch,
Nous.Tools.Summarize,
Nous.Tools.SearchScrape,
Nous.Tools.TavilySearch,
Nous.Tools.BraveSearch,
Nous.Tools.ResearchNotes,
Nous.Tools.Search.Common
],
"Coding Tools": [
Nous.Tools.Bash,
Nous.Tools.FileRead,
Nous.Tools.FileWrite,
Nous.Tools.FileEdit,
Nous.Tools.FileGlob,
Nous.Tools.FileGrep,
Nous.Tools.TodoTools,
Nous.Tools.PathGuard,
Nous.Tools.UrlGuard,
Nous.Tools.Env
],
"Utility Tools": [
Nous.Tools.DateTimeTools,
Nous.Tools.StringTools,
Nous.Tools.ReActTools
],
Testing: [
Nous.Tool.Testing
],
Templates: [
Nous.PromptTemplate
],
"Data Types": [
Nous.Types,
Nous.Usage
],
Infrastructure: [
Nous.Telemetry,
Nous.PromEx.Plugin,
Nous.Errors,
Nous.Errors.Base,
Nous.Errors.RetryInfo,
Nous.Errors.ConfigurationError,
Nous.Errors.ModelError,
Nous.Errors.ProviderError,
Nous.Errors.ToolError,
Nous.Errors.ToolTimeout,
Nous.Errors.ValidationError,
Nous.Errors.UsageLimitExceeded,
Nous.Errors.MaxIterationsExceeded,
Nous.Errors.ExecutionCancelled
],
Evaluation: [
Nous.Eval,
Nous.Eval.Suite,
Nous.Eval.TestCase,
Nous.Eval.Runner,
Nous.Eval.Evaluator,
Nous.Eval.Evaluators.Contains,
Nous.Eval.Evaluators.ExactMatch,
Nous.Eval.Evaluators.FuzzyMatch,
Nous.Eval.Evaluators.LLMJudge,
Nous.Eval.Evaluators.Schema,
Nous.Eval.Evaluators.ToolUsage,
Nous.Eval.Metrics,
Nous.Eval.Metrics.Summary,
Nous.Eval.Result,
Nous.Eval.SuiteResult,
Nous.Eval.YamlLoader,
Nous.Eval.Config,
Nous.Eval.Reporter,
Nous.Eval.Reporter.Console,
Nous.Eval.Reporter.Json,
Nous.Eval.Optimizer,
Nous.Eval.Optimizer.Parameter,
Nous.Eval.Optimizer.SearchSpace,
Nous.Eval.Optimizer.Strategy,
Nous.Eval.Optimizer.Strategies.Bayesian,
Nous.Eval.Optimizer.Strategies.GridSearch,
Nous.Eval.Optimizer.Strategies.Random
],
"Hooks System": [
Nous.Hook,
Nous.Hook.Registry,
Nous.Hook.Runner
],
"Skills System": [
Nous.Skill,
Nous.Skill.Loader,
Nous.Skill.Registry,
Nous.Plugins.Skills,
Nous.Skills.CodeReview,
Nous.Skills.TestGen,
Nous.Skills.Debug,
Nous.Skills.Refactor,
Nous.Skills.ExplainCode,
Nous.Skills.CommitMessage,
Nous.Skills.DocGen,
Nous.Skills.SecurityScan,
Nous.Skills.Architect,
Nous.Skills.TaskBreakdown,
Nous.Skills.PhoenixLiveView,
Nous.Skills.EctoPatterns,
Nous.Skills.OtpPatterns,
Nous.Skills.ElixirTesting,
Nous.Skills.ElixirIdioms,
Nous.Skills.PythonFastAPI,
Nous.Skills.PythonTesting,
Nous.Skills.PythonTyping,
Nous.Skills.PythonDataScience,
Nous.Skills.PythonSecurity,
Nous.Skills.PythonUv
],
"Plugin System": [
Nous.Plugin,
Nous.Plugins.HumanInTheLoop,
Nous.Plugins.InputGuard,
Nous.Plugins.InputGuard.Strategy,
Nous.Plugins.InputGuard.Result,
Nous.Plugins.InputGuard.Policy,
Nous.Plugins.InputGuard.Strategies.Pattern,
Nous.Plugins.InputGuard.Strategies.LLMJudge,
Nous.Plugins.InputGuard.Strategies.Semantic,
Nous.Plugins.Memory,
Nous.Plugins.SubAgent,
Nous.Plugins.Summarization,
Nous.Plugins.Decisions,
Nous.Plugins.TeamTools
],
"Multi-Agent (Teams)": [
Nous.Teams,
Nous.Teams.Supervisor,
Nous.Teams.Coordinator,
Nous.Teams.Role,
Nous.Teams.Comms,
Nous.Teams.SharedState,
Nous.Teams.RateLimiter
],
"Decision Graph": [
Nous.Decisions,
Nous.Decisions.Node,
Nous.Decisions.Edge,
Nous.Decisions.ContextBuilder,
Nous.Decisions.Store,
Nous.Decisions.Store.ETS,
Nous.Decisions.Store.DuckDB
],
Memory: [
Nous.Memory,
Nous.Memory.Entry,
Nous.Memory.Scope,
Nous.Memory.Store,
Nous.Memory.Store.ETS,
Nous.Memory.Store.SQLite,
Nous.Memory.Store.DuckDB,
Nous.Memory.Store.Results,
Nous.Memory.Store.Conformance,
Nous.Memory.Scoring,
Nous.Memory.Search,
Nous.Memory.Tools,
Nous.Memory.Embedding,
Nous.Memory.Embedding.Bumblebee,
Nous.Memory.Embedding.OpenAI,
Nous.Memory.Embedding.Local
],
PubSub: [
Nous.PubSub,
Nous.PubSub.Approval
],
Persistence: [
Nous.Persistence,
Nous.Persistence.ETS
],
Supervision: [
Nous.AgentRegistry,
Nous.AgentDynamicSupervisor
],
Research: [
Nous.Research,
Nous.Research.Coordinator,
Nous.Research.Planner,
Nous.Research.Searcher,
Nous.Research.Synthesizer,
Nous.Research.Reporter,
Nous.Research.Finding,
Nous.Research.Report
],
Session: [
Nous.Session.Config,
Nous.Session.Guardrails
],
Permissions: [
Nous.Permissions,
Nous.Permissions.Policy
],
"Knowledge Base": [
Nous.KnowledgeBase,
Nous.KnowledgeBase.Entry,
Nous.KnowledgeBase.Document,
Nous.KnowledgeBase.Link,
Nous.KnowledgeBase.Store,
Nous.KnowledgeBase.Store.ETS,
Nous.KnowledgeBase.Tools,
Nous.KnowledgeBase.Workflows,
Nous.KnowledgeBase.HealthReport,
Nous.KnowledgeBase.Prompts,
Nous.Plugins.KnowledgeBase,
Nous.Agents.KnowledgeBaseAgent
],
"Workflow Engine": [
Nous.Workflow,
Nous.Workflow.Graph,
Nous.Workflow.Node,
Nous.Workflow.Edge,
Nous.Workflow.State,
Nous.Workflow.Compiler,
Nous.Workflow.Engine,
Nous.Workflow.Mermaid,
Nous.Workflow.Trace,
Nous.Workflow.Checkpoint,
Nous.Workflow.Checkpoint.Store,
Nous.Workflow.Checkpoint.ETS,
Nous.Workflow.Scratch,
Nous.Workflow.Telemetry
],
"Mix Tasks": [
Mix.Tasks.Nous.Eval,
Mix.Tasks.Nous.Optimize
]
]
]
end
defp package do
[
# Explicit files list — exclude `priv/plts/` (dialyzer artifacts) which
# the default Hex package set would otherwise bundle, bloating the
# tarball by 100MB+.
files: ~w(lib .formatter.exs mix.exs README.md LICENSE CHANGELOG.md AGENTS.md),
licenses: ["Apache-2.0"],
links: %{
"GitHub" => @source_url,
"Changelog" => "#{@source_url}/blob/master/CHANGELOG.md"
}
]
end
defp aliases do
[docs: ["docs", ©_images/1]]
end
defp copy_images(_) do
File.mkdir_p!("doc/images")
File.cp!("images/header.jpeg", "doc/images/header.jpeg")
File.cp!("images/logo.jpeg", "doc/images/logo.jpeg")
end
end