Skip to content

0.5.0

Latest

Choose a tag to compare

@github-actions github-actions released this 21 Sep 17:22
· 42 commits to main since this release

LangChain and LangGraph

  • What each model call was sent, and what came back, lands beside the conversation as a provider
    body, cut against what the session already holds by pkg/providerbody — the same mechanism as
    Claude Code's bodies. It is what the continuity check between calls runs on, and it shows a
    nested agent its own prompt. Measured on the captured corpus, a twenty-turn conversation lands
    at 13% of what it was on the wire, bodies included, and a conversation of a few short calls at
    about a third. provider_bodies: false on the langsmith-ingest adapter turns it off. A
    request on this wire names its call, the run's own id, and the assembler now joins a request by
    the call it names, when exactly one names it; a request that names none, as Claude Code's do,
    joins as before. A nested stream's records name the tool they ran inside as their prompt, not
    the trace.

  • asz assembles conversations from an agent built on LangChain or LangGraph without changing the
    application. The langsmith-ingest adapter is a receiver the tracing client is pointed at, and
    since that client is a dependency of langchain-core, every LangChain application already
    carries it: four environment variables are the whole integration. See
    LangChain and LangGraph.

  • What the receiver leaves out of its capability answer is what keeps it simple. The client
    compresses only when told the receiver can read zstd, so not advertising it keeps every body
    plain and keeps a compression library out of this project. A client that compresses anyway is
    refused with the flag named.

  • A run arrives more than once: posted when it starts, patched when it ends. Each arrival is its
    own record sharing one call, and only the arrival carrying the run's end carries its content —
    otherwise one call would emit the assistant message twice, in a round that called itself
    verified. Work in progress lands as data, so a slow turn is visible before it finishes and a
    process that died mid-turn still leaves what it had reported.

  • A graph's own runs land trimmed. They were 30 of 39 runs and 74% of the bytes in one capture,
    because each repeats the whole message list its model call already carries. The envelope and the
    graph's metadata land, the repeated content does not, and the record says how many bytes went
    with it.

  • Ownership is a namespace, not a thread key: two applications can both use the project
    production and the thread 123. A supplied key is never used as a path either, since
    ../outside, team/customer, _hidden and 会话-1 all arrive as real thread keys.

  • A demo application under tests/apps/langchain, and the fixtures captured from it. It is a real
    LangGraph application, one case per shape a conversation can take, driven by a stand-in model
    over HTTP so it needs no API key, no network and no provider account. make langchain-capture
    runs every case and writes MEASUREMENTS.md from what it captured, so the numbers there never
    drift from the fixtures. Fifteen cases cover a plain turn, three turns on one thread, a tool that
    fails, parallel tool calls, a graph that loops, two threads at once, a slow tool whose runs are
    posted before they finish, a process that dies mid-turn, large content, a sub-agent, a missing
    thread key, two applications sharing one, keys that are not safe as paths, and the tracing
    client's own decorator with no LangChain in it.

  • A LangChain plugin, apache-skywalking-asz-langchain, records what each of an agent's tool calls
    changed on disk. It is thirty lines of glue: asz-changes does the scanning and diffing, and the
    shim says when a tool call begins and ends, which LangChain has no way to say on its own. The
    application imports nothing — a .pth runs a loader at interpreter start, and that loader reads
    one environment variable and imports nothing else, so the plugin costs 0.01 s of interpreter
    start when it is off. See LangChain Plugin.

  • asz-changes is no longer Claude Code's alone. A tool with no shell command is no longer
    classified read-only and skipped; tools.scope takes an exact name, a regular expression
    beginning re:, or * for every tool, with an exclude list in the same three forms; the data
    directory can be named with ASZ_CHANGES_DATA; and the events have neutral names — tool.begin,
    tool.end, tool.failed — meaning exactly what Claude Code's do.

  • asz glossary takes a dialect, and asz conversation -terms native reads the one a session's
    own records were landed in. A root can hold conversations from more than one runtime, and the
    runtime's words have to be the ones belonging to what is being read.

  • The changes adapter may be named once per recorder directory, so a machine that runs Claude
    Code's plugin and a LangChain shim collects both. Two entries that read one directory are
    refused, and the adapter's old name counts as the same adapter; before, a second entry silently
    replaced the first.

  • claude_code.token.usage is derived from Claude Code's transcripts alone. A LangChain
    conversation in the same root carries calls and usage too, and was counted into it.

  • A session sent before its transcript landed - the recorder's files often come first - is
    attributed by the name asz gave it, so a LangChain session's change records no longer leave
    under Claude Code's name.

  • The LangChain plugin is published to PyPI after the vote, as the Homebrew tap and the apt
    repository are written after it. How to Release has the
    step, the pypi skill does it, and prepare writes the version into the plugin.

Renamed

The change recorder is not Claude Code's: it records what any runtime's tool call changed, and a
LangChain application now produces the same records. The names say so, and every one of them is
carried across rather than dropped.

These are breaking, and deliberately so: the project is before 1.0, and carrying two names for
every artifact would cost more than the upgrade does.

  • The binary asz-claude-plugin is asz-changes. Reinstall the Claude Code plugin once so its
    hooks call the new name; install/claude-code-plugin.sh does it and carries the plugin's data
    across.

  • The Debian package asz-claude-code is asz-changes. Run
    sudo apt install asz-changes && sudo apt remove asz-claude-code.

  • One Homebrew formula. asz installs both binaries, where two formulae used to fetch the
    identical archive and the identical checksum and install one binary each — which only invited a
    machine to end up with asz of one version and the recorder of another. Run
    brew uninstall asz-claude-code.

  • The Claude Code plugin asz-changes is file-changes, so the plugin and the program it runs
    no longer share a name. A plugin's data directory is named after the plugin, so the installer
    copies the old one across before the first session: the settings, and any change record asz had
    not collected yet. Nothing is lost by upgrading.

  • The adapter claude-code-changes is changes. A configuration that still names it is read
    as the same adapter, and so is every header landed under it, which keeps its name forever.

  • The recorder's data directory can be named with ASZ_CHANGES_DATA. CLAUDE_PLUGIN_DATA still
    works, because Claude Code sets it for every hook.

Install

  • Install tells a Homebrew user to run
    brew trust https://github.com/apache/skywalking-ai-sessionizer before tapping. Homebrew 7 loads
    a tap that is not its own only after brew trust, and it matches a user/repository entry only
    against a tap at its default remote, which this one is not: the repository is not named
    homebrew-skywalking-ai-sessionizer. Without the trust, brew tap stops with
    Refusing to load formula ... from untrusted tap.

Release

  • The install scripts put asz-changes beside asz, as Homebrew and apt do. asz-changes says
    its own name in its help and its version, where it still said asz-claude-plugin.

  • A failing test of the LangChain plugin fails make check; it was reported as Python not
    installed.

  • asz.yaml writes headers out, and the test that holds it to spelling out every value reads
    the file's keys rather than the loaded values, which the defaults had filled in.

  • A scenario's coverage check judges each change file against the cursor it was landed behind,
    as collection does, and a cursor names the recorder root its file is under: two roots can hold
    one session under one relative path, and one cursor for both stopped both. A cursor from
    before 0.5.0 belongs to the root whose file it was read from, by the file's device and inode
    and the bytes before its offset together, and is written with that root on the next pass; one whose
    file was copied or restored since is read again from the start, and the index keeps the first
    record of an id. A session with two plugin directories was never reported as
    covered, so a scenario's removal waited for ever.

  • Configuration says which of several agents,
    instances and machines one asz serves, and what needs one process each.

  • Upgrading from 0.4.0 is one ordered list. The plugin
    installer finds the plugin under its old name and uninstalls it with its data kept, copies the
    data beside the new directory and renames it into place - so a copy that stops half way is
    done again rather than skipped - and finds Claude Code's directory the way asz does.

  • The downloads page lists the source package and the binary archives only. publish listed the
    Debian packages there too, beside the archives of the same binaries. They stay in the release
    directory with their signatures and checksums, and apt installs them from the repository on the
    website.

Where to get it