Changelog¶
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]¶
[0.3.4] - 2026-11-14¶
Changed¶
- The Issues link on PyPI and in the docs points to
/-/work_items, which loads when you are logged out. The old/-/issuesURL returned 404. - The key record
.keys/<key>.jsonno longer holds the value of a skipped component, such as aConfigfield. AConfigcan hold a client or a secret, and the record goes to disk or to a shared store. The record keeps the field name. dag()now draws cached steps green, as the docs always said. Before, a cached step and a pending step had the same fill, and only blocked steps had their own color. The classesis-cached,is-pendingandis-blockedare unchanged, so your own stylesheet still wins.
[0.3.0] - 2026-11-12¶
0.2.6 to 0.2.43 were published per commit; this entry collects all of them. Read
Migrating to 0.3.0 before you upgrade: every
step result recomputes once, and so do BatchStep items whose keys adag derives.
Added¶
- Custom graph drawing has a public API:
node_metadata(nodes)returns whatdagwould draw; replace anyNodeMetadataand pass the list torender_graph_svg.Node,Edge,NodeMetadata,compute_state,node_metadataandrender_graph_svgimport fromadag. The old private names keep working until 1.0. Pipeline(metadata=...): caller data, any JSON value, saved inpipeline.jsonand read back byfrom_directory.adag.JsonValue: the type ofPipeline(metadata=...)andpipeline.metadata, instead ofAny. A strict type checker now asks you to narrow the loaded value before you use it.aresolve_all(targets, context, max_concurrency=): resolve several nodes level by level inside your own event loop, with one memo, equal keys run once, and a bound on running step bodies.Pipeline.aexecutenow uses it.- After each save, adag writes a key record
.keys/<key>.json(theexplain_keyoutput, under 1 KB for a small step) next to the result. Code that lists every file in a cache directory now also sees.keys/. StepResult.explain_key(params)andPipeline.explain_keys(params)list every component of a cache key, so you can see why a node recomputed. See the docs page "Why a step recomputed".adag.hashing.KEY_FORMAT(now 2): the version of the cache key bytes. A release that changes every key bumps it.SerializableStep.from_directoryhas a default that rebuilds a step from itsspec. A step it cannot rebuild now raisesTypeErrorat save time instead of failing at load time.AdagDeprecationWarning: every deprecated name and call form warns with it. It is aFutureWarning, so scripts and notebooks see it without changing warning filters, and each message names the replacement. Deprecated forms keep working until adag 1.0.- Python 3.12 support (
requires-python >=3.12), tested in CI. Step.save_resultandStep.load_result: cache a result that is not one JSON document (JSONL, a directory, a file plus a sidecar), under a path keyed on the step and its inputs.BatchStepuses them too.InputParam(..., value_type=T)tellsadag runhow to parse--param, so a requiredstrparam keeps007as"007".RemoteDispatcher(backend)runs fan-out branches as jobs on any scheduler. A backend (JobBackend) has three methods:submit,status,cancel.LocalJobBackendruns local processes.BranchPolicygainsqueue_timeout_seconds,retry_delay_secondsandresult_grace_seconds.timeout_secondsnow counts from when the job starts running.Pipeline(..., store=CacheStore)keeps step results andBatchStepitem caches in SQLite, SQL, Redis or memory instead of files undercache_dir.store_from_url(url)opens a store from a URL, andadag resolve-branch --store-urllets a worker write to that store. Passstore_url=toRemoteDispatcherwhen the pipeline has a store.adag resolve-branchtakes a module name (pkg.pipeline) as well as a file path, and--expect-hash. A worker whose branch hash differs exits 2 and is not retried.
Fixed¶
- The per-run memo keeps each node with its result. A
ResolveContextreused after its graph was freed could hand one node's result to a new node that got the sameid(). - Two
aresolvecalls gathered on one context ran a shared upstream step twice. The first task now claims the node and the others wait for it, as the threaded path already did. dag(..., cache_dir=)draws pipeline-cached steps as cached. It read the step hash, which the pipeline does not use as a key, so every step showed as pending.- A
FanOutStepruns underPipeline.aexecute(). It raisedNotImplementedErrorbefore. - A
FileSource,LinesSourceorJSONLSourceon a directory (an empty path included) raises an error that names the source and the path. It raised a bareIsADirectoryErrorfrom inside hashing. StepResult.is_cachedfor a step withsave_result/load_resultcallsload_result, so an entry it rejects is not cached, the same answer the resolver gives. It checked only that the files existed.- A step whose
load_resultgives back less thanrunproduced (for example a field markedexclude=True) now logsstep.load_result_differson the first save. Downstream gets the reloaded value, so the data was dropped silently. The Caching page now says so. - A
StepResultheld in a step field raisesTypeErrorwhen the step is called, and says to pass it as a call input. It failed later, in hashing, with advice to useConfig(...), which would have removed the edge from the graph. Hashing errors no longer suggestConfig(...)for a graph node.
Changed¶
- Tests pin the cache key format. A future release changes keys only on purpose, and says so here.
- Calling a step warns (
AdagDeprecationWarning) when an upstream step is both a field and an input. Wire it once, as an input. It becomes aTypeErrorin adag 1.0. SubprocessDispatcherruns at most one process per CPU at a time (max_concurrent=), not one per branch. It waitsretry_delay_seconds, notpoll_interval_seconds, between attempts.- A custom dispatcher implements
dispatch_all(branches, context)(all branches of one fan-out). A dispatcher with only the olddispatch(branch, sub, context)still works, with a warning. - Dispatching a fan-out whose keys have the same text (
1and"1") raisesValueError. NullObservernow silences a whole run. Progress logs (cache writes, batch progress, dispatch) go through the newon_eventobserver hook; warnings and errors still log.
Restored¶
The 0.2 releases removed names that existing code still uses. They are back, and every name
the first release exported imports again, except BatchDispatcher (use RemoteDispatcher with a
JobBackend) and StepOutput (nothing returned one). Deprecated ones warn and work until 1.0.
- The top-level exports removed in 0.2.5: executors, dispatchers,
Deferred,ResolveContext,Progress,BranchRef,current_observer,observing,walk,render_pipeline_svg. Step.produces,Step.acceptsandStep.accepts_from.CachedStepas a working class, with its directoutput_path,save,load,validate,is_cachedandis_partialmethods (deprecated; seesave_result/load_result).hash_scalarandhash_list, with the same bytes as the first release.ResolveContextandBranchPolicykeep their first-release positional field order.
Deprecated¶
Each warns with AdagDeprecationWarning and works until adag 1.0.
CachedStep: subclassStep, and overridesave_result/load_resultfor a result that is not one JSON document.Parameter,StepMode,BranchExecutionError.NullObserver.on_embeddingandon_model_refused: declare a typed hook of your own.- A dispatcher with only
dispatch(): implementdispatch_all. run_branchwith aKEY=VALUElist, andresolve-branch --param: use--params-json.- An upstream step that is both a field and an input.
Removed¶
BatchDispatcher: useRemoteDispatcherwith aJobBackend.StepOutput: nothing returned one.
[0.2.5] - 2026-11-11¶
0.2.0 to 0.2.5 are one change set; patch versions were bumped per commit.
Changed¶
- All caches recompute once: the cache key format changed to fix the bugs below.
CachedStepis deprecated: subclassStepinstead. Its directsave,load,is_partialandoutput_pathmethods are removed; the pipeline caches everyStep.- A step field the cache key cannot hash now raises
UnhashableValueError. Wrap execution-only values inConfig(...), or setstrict_content_hash = False.
Fixed¶
- Lists with the same digits in a different split, like
(1, 23)and(12, 3), no longer share a cache key. - Changing a
Path,Enum,dict,setorUUIDfield now changes the cache key. InputParamvalues hash by value, not byrepr(), so they get cache hits.- An empty or corrupt cache file is recomputed instead of crashing.
- Threaded fan-out results keep the order of
over. - Worker processes receive params as JSON, so a str
"5"stays a str. - Steps with a
kindhash their source code too, so a code edit recomputes.
Removed¶
- From the top-level
adagnamespace: executors, dispatchers,Deferred,ResolveContext,Progress,BranchRef,current_observer,observing,walk,render_pipeline_svg. Import them from their submodules (for exampleadag.dispatch). Parameter,StepMode,StepOutput,BatchDispatcher, and theon_embeddingandon_model_refusedobserver hooks.
[0.1.1] - 2026-11-11¶
Added¶
- Initial release.