1.27.0
Release Notes
Added
- Concurrent I/O — blocking leaves now overlap on the scheduler. Previously
async/spawncould interleave channels and sleeps, but any task that hit network or a
subprocess froze the single VM thread for the whole round-trip, so spawned I/O ran
serially. Nowhttp/*,shell,llm/embed, andllm/complete/llm/classify/
llm/extractyield to the scheduler while their work runs on a background runtime
(via a new cooperativeAwaitIoyield), so spawning them as tasks makes wall-clock
approachmax(latency)instead ofsum(latency). Verified live: 4× concurrent
llm/complete~3.4× faster than serial; 4×llm/embed~13.6×; 5×shell514 ms vs
2571 ms. Top-level (non-async) calls are unchanged — byte-identical synchronous behavior. async/pool-map— bounded-concurrency fan-out:(async/pool-map f items n)mapsf
overitemswith at mostncalls in flight, results in input order. Fan a large batch
(embeddings, fetches, completions) across a rate-limited resource without launching
everything at once.async/mapandasync/spawn-all— ergonomic unbounded fan-out.(async/map f items)
is a concurrentmap(a task per item, results in input order);(async/spawn-all thunks)
spawns a list of zero-arg thunks and awaits them all. Both are the obvious sugar over
(async/all (map #(async/spawn …) …)); reach forasync/pool-mapwhen you need a cap.- Nested-trace propagation across
async/spawn. Spans opened inside a spawned task now
nest under the spawning task's active span and share its trace, so
(with-span … (async/map …))(or any nested async) renders as ONE connected trace tree in
Jaeger/Phoenix/Langfuse instead of fragmenting into N disconnected single-span traces. A
top-level spawn (no active span) still starts its own trace, so independent top-level tasks
stay isolated. - True cancellation.
async/cancelandasync/timeoutnow abort in-flight I/O for
real where the runtime allows: a cancelled/timed-outhttp/*request tears down its
connection, and ashellsubprocess is killed (SIGKILL) instead of running to
completion in the background.llm/*cancellation stays best-effort (the blocking worker
can't be interrupted mid-call; the result is discarded).async/timeoutexpiry now
cancels its target task automatically (you no longer need a pairedasync/cancelto free
its resources). - Per-task OpenTelemetry isolation. Concurrent LLM tasks each carry their own span
stack + conversation/session/user scope (swapped on every scheduler task-switch), so
overlappingllm/embed/llm/completespans never cross-contaminate.
Fixed
- Scheduler no longer reaps still-pending tasks at an outermost exit. A task spawned in
one top-level form and awaited in a later one (e.g. a streaming-pipeline collector spawned
before an(async/all …)of the other stages) was being cleared between scheduler runs
→ "async/await: still pending after scheduler run". The reap is now terminal-only.
Docs: Concurrency → Concurrent I/O.
Install sema-lang 1.27.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/HelgeSverre/sema/releases/download/v1.27.0/sema-lang-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/HelgeSverre/sema/releases/download/v1.27.0/sema-lang-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install helgesverre/tap/sema-langDownload sema-lang 1.27.0
| File | Platform | Checksum |
|---|---|---|
| sema-lang-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| sema-lang-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| sema-lang-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| sema-lang-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| sema-lang-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |