fix: toml-relative agent spec resolves against toml dir + clean TypeError for wrong-type graph on default path (gh #116, #117) - #118
Merged
Conversation
…rror for wrong-type graph on default path (gh #116, #117) #116: A relative `agent.spec` in a walked-up `langstage.toml` (what `init` scaffolds) was resolved against the process cwd, so running from a subdir crashed `Agent file not found` even though `--show-config` reported the spec resolved. A toml-sourced relative file spec now rebases onto the toml's own directory (the discovered project root) — like a path in pyproject.toml / tsconfig — while `-a`/env specs keep their cwd-relative base (#30). The `path:attr` split is factored into `_split_py_file_spec` (Windows drive-letter safe) and reused; `config.toml_dir_for` finds the file that defines the key. #117: On the default persist-on path, a wrong-type agent (`graph = None`, a dict, an int) leaked `AttributeError: 'X' object has no attribute 'checkpointer'` because the durable saver was assigned before `build_agent` validated the graph. The assignment is now guarded like `_ensure_checkpointer`, so the object falls through to `build_agent`'s clean `TypeError: build_agent expected a compiled LangGraph graph ...` — matching `--verify` / `--no-persist`. Regression tests: init-scaffold runs from a subdir (spec resolved against toml dir) + `-a` stays cwd-relative; `graph = None` on the default config shows the clean TypeError, not the checkpointer leak. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011HWCfJii6gXd3XL3Gq3W8B
This was referenced Aug 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ships 0.6.30, fixing two cli-local bugs.
#116 — relative
agent.specinlangstage.tomlresolved against cwd, not the toml's dirConfig discovery walks UP ancestor dirs to find
langstage.toml, but a relativeagent.specin it (whatinitscaffolds:spec = "my_agent.py:graph") was resolved against the process cwd. So running from a subdirectory crashedAgent file not foundeven though--show-configreported the spec resolved.Fix: a relative file spec whose source is a discovered
langstage.tomlnow rebases onto that toml's own directory (the project root) before loading — the same way a path inpyproject.toml/tsconfig.jsonresolves relative to the config file. A spec from-a/LANGSTAGE_AGENT_SPECkeeps its cwd-relative base (#30 — "the file is where the user typed it"); only toml-sourced relative specs change base. Thepath:attrsplit is factored into_split_py_file_spec(Windows drive-letter safe —C:\x.py:graph) and reused by both_absolutize_file_spec(cwd) and the new_rebase_toml_file_spec(toml dir);config.toml_dir_forfinds the merged file that actually defines the key.#117 — wrong-type agent leaked
AttributeError: '...' object has no attribute 'checkpointer'on the DEFAULT pathOn the default persist-on path, a wrong-type agent object (
graph = None, a dict, an int) crashed with a crypticAttributeErrorbecause the durableAsyncSqliteSaverwas assigned tograph.checkpointerbeforebuild_agentvalidated the graph.--verifyand--no-persistalready showed the clean message.Fix: the durable saver assignment is guarded exactly like the non-durable
_ensure_checkpointer(try/except), so a wrong-type object falls through tobuild_agent's actionableTypeError: build_agent expected a compiled LangGraph graph (CompiledStateGraph) ... but got NoneType.— matching--verify/--no-persist. Valid graphs are unaffected.Tests
test_spec_resolution.py: init-scaffold runs from a subdir (spec resolved against the toml dir);-astays cwd-relative alongside alangstage.toml(control).test_wrong_type_graph.py:graph = Noneon the default config shows the cleanTypeError, not the checkpointer leak, and exits non-zero.ruff check+ruff format --checkclean.Closes #116, closes #117.
🤖 Generated with Claude Code
https://claude.ai/code/session_011HWCfJii6gXd3XL3Gq3W8B