Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ jobs:
${{ runner.os }}-mix-
- name: Install Mix dependencies
run: nix develop -c mix deps.get
- name: Compile project
run: nix develop -c mix compile --warnings-as-errors
# Type-check gate: replaces Dialyzer. Elixir 1.20's built-in
# set-theoretic type checker runs during `mix compile`; its findings
# surface as compile warnings, and --warnings-as-errors fails CI on them.
- name: Compile project (type-check gate)
run: nix develop -c mix compile --warnings-as-errors --force
- name: Run tests
run: nix develop -c mix test
- name: Check code formatting
run: nix develop -c mix format --check-formatted
- name: Run Credo
run: nix develop -c mix credo
- name: Run Dialyzer
run: nix develop -c mix dialyzer
30 changes: 12 additions & 18 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,15 @@ Configuration is in `.credo.exs`. Current settings:
- Strict consistency checks enabled
- TODOs allowed (warning only)

### Dialyzer
### Type checking

Static type analysis using Dialyzer:
Static type analysis is handled by Elixir's built-in set-theoretic
(gradual) type checker, which runs automatically during `mix compile`.
Treat its warnings as errors to gate on them:

```bash
# Run Dialyzer (first run will be slow while building PLT)
mix dialyzer

# Clean PLT cache
rm -rf priv/plts/
# Type-check the project (forces a full recompile so all warnings surface)
mix compile --warnings-as-errors --force
```

PLT files are cached in `priv/plts/` and excluded from git.
Expand Down Expand Up @@ -140,10 +139,9 @@ Tests run on multiple Elixir and OTP versions:
- Runs Credo in strict mode
- Uses dependency and build caching

2. **Dialyzer Job**
- Runs on latest Elixir/OTP only
- Caches PLT files for faster runs
- Performs static type analysis
2. **Type-check gate**
- Part of the compile step (`mix compile --warnings-as-errors --force`)
- Surfaces the built-in set-theoretic type checker's findings as errors

## Code Style Guidelines

Expand Down Expand Up @@ -240,14 +238,11 @@ mix deps.get
mix test
```

### Dialyzer Issues
### Type-check Issues

```bash
# Clean PLT cache
rm -rf priv/plts/

# Rebuild PLT
mix dialyzer
# Force a full recompile so all type-checker warnings surface
mix compile --warnings-as-errors --force
```

### Formatting Conflicts
Expand All @@ -274,5 +269,4 @@ mix format --check-formatted

- **Mix tasks**: `mix help`
- **Credo**: `mix credo --help`
- **Dialyzer**: `mix dialyzer --help`
- **Tests**: `mix help test`
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,9 @@ mix credo --strict
# Generate documentation
mix docs

# Run Dialyzer (type checking)
mix dialyzer
# Type checking (Elixir's built-in set-theoretic type checker runs at compile time;
# treat its warnings as errors to gate on them)
mix compile --warnings-as-errors --force
```

### Pre-commit Hook
Expand Down
3 changes: 1 addition & 2 deletions lib/agent_obs/req_llm.ex
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,6 @@ defmodule AgentObs.ReqLLM do
- `[:agent_obs, :tool, :exception]` - If tool execution fails
"""
@spec trace_tool_execution(struct(), map(), keyword()) :: {:ok, term()} | {:error, term()}
@dialyzer {:nowarn_function, trace_tool_execution: 3}
def trace_tool_execution(tool, tool_call, opts \\ []) do
_ = opts

Expand All @@ -726,7 +725,7 @@ defmodule AgentObs.ReqLLM do
{:error, error}

# ReqLLM.Tool.execute can return raw values when the callback doesn't wrap in {:ok, _}
# Dialyzer thinks this is unreachable, but it happens in practice (see integration tests)
# (the typespec marks this as unreachable, but it happens in practice see integration tests)
result ->
{:ok, result, %{result: result}}
end
Expand Down
4 changes: 0 additions & 4 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ defmodule AgentObs.MixProject do
description: description(),
package: package(),
docs: docs(),
dialyzer: [
plt_file: {:no_warn, "priv/plts/dialyzer.plt"}
],
aliases: aliases()
]
end
Expand All @@ -43,7 +40,6 @@ defmodule AgentObs.MixProject do

# Development and testing dependencies
{:ex_doc, "~> 0.40", only: :dev, runtime: false},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
]
end
Expand Down
2 changes: 0 additions & 2 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@
"crontab": {:hex, :crontab, "1.2.0", "503611820257939d5d0fd272eb2b454f48a470435a809479ddc2c40bb515495c", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "ebd7ef4d831e1b20fa4700f0de0284a04cac4347e813337978e25b4cc5cc2207"},
"ctx": {:hex, :ctx, "0.6.0", "8ff88b70e6400c4df90142e7f130625b82086077a45364a78d208ed3ed53c7fe", [:rebar3], [], "hexpm", "a14ed2d1b67723dbebbe423b28d7615eb0bdcba6ff28f2d1f1b0a7e1d4aa5fc2"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"},
"dotenvy": {:hex, :dotenvy, "1.1.1", "00e318f3c51de9fafc4b48598447e386f19204dc18ca69886905bb8f8b08b667", [:mix], [], "hexpm", "c8269471b5701e9e56dc86509c1199ded2b33dce088c3471afcfef7839766d8e"},
"earmark_parser": {:hex, :earmark_parser, "1.4.45", "cba8369ab2a1342e419bc2760eec731b17be828941dcf494045d44766227e1d5", [:mix], [], "hexpm", "d3ec045bf122965db20c0bdb420e19ee1415843135327124918473feb4b328e8"},
"erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
"ex_aws_auth": {:hex, :ex_aws_auth, "1.4.1", "2f4faf59dd62933c52faf5c026f22b6b9b7d143cf30ee462204a646e3304761f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: true]}], "hexpm", "42ea14c586689652f51906c797378a07822b65b32febd22067b4e93ff9dc7d4f"},
"ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"},
"expo": {:hex, :expo, "1.1.1", "4202e1d2ca6e2b3b63e02f69cfe0a404f77702b041d02b58597c00992b601db5", [:mix], [], "hexpm", "5fb308b9cb359ae200b7e23d37c76978673aa1b06e2b3075d814ce12c5811640"},
Expand Down
Loading