Skip to content

0.4.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 12:34
· 49 commits to main since this release

Provider bodies

  • A new adapter, claude-code-provider, lands the request and response bodies Claude Code writes
    for its model provider when OTEL_LOG_RAW_API_BODIES=file:<dir> is in its environment: the
    system prompt, the tool schemas and every message as it was sent, which no transcript holds. A
    request names its session; a response is claimed by a later request that names its request id,
    or by the one session whose transcript holds its message id, and waits otherwise. On by default,
    it does nothing until the variable is set. See
    Claude Code Provider Bodies.
  • The kind provider_body, reserved until now, lands under <session>/provider_body/, in files of
    at most max_delta_bytes each; only a body larger than that lands in a larger file of its own. A record keeps only what its session does not hold yet: each tool definition
    and every string of 1 KiB or more is a piece named by its SHA-256, and the front a body shares
    with the previous body of its chain is one copy. Its last part, a provider_body/1 manifest,
    rebuilds the body byte for byte, which the adapter checks through the writer and reader before a
    record lands. On two captures of Claude Code 2.1.260 the landed files were 25.5% and 21.6% of the
    bytes written, and all 42 bodies rebuilt exactly. pkg/providerbody cuts and rebuilds bodies for
    any reader.
  • Assembly leaves provider bodies out of the fold, and the index keeps them out of every lookup, so
    a session folds to the same nodes with and without them. In the asz.view document, an llm.call
    lists its request and response under provider_bodies, each by role and the landed record it
    rebuilds from, joined by the bodies' own ids; a reader loads the bodies when it wants them.
    summary.provider_bodies counts the bodies and summary.captured_prompts the calls whose request is
    captured. The version stays 1.0.
  • The round carries that join. An llm.call in a .sf round carries provider_bodies in its
    attributes, and the session node how many bodies the session holds. The join was made when a
    conversation was rendered, which meant every reader repeated it, and to repeat it a reader had to
    open every landed body — the largest files a session holds — to read one line of each. A server
    that mirrors the format paid that on every read of a conversation: measured on the end-to-end
    session, 27,884 bytes of provider bodies against 8,158 bytes of transcript, none of it in the
    document. It is now resolved once, when the round is parsed, from the index alone; the index keeps
    each body's role, its request id and the request before it, and each record's line in its stream,
    which is what tells a gapped stream from a whole one. The rules are unchanged, the document is
    unchanged, and a round reader refuses a body reference past the round's own range as it refuses
    any other. A conversation whose rounds were parsed before this carries no bodies on its calls;
    parsing its chain again brings them in. The index schema is bumped, so it rebuilds itself.
  • asz verify rebuilds every landed provider body and compares its digest. storage.LandedFiles
    lists the session's provider_body/ directory, so parse, push, repack and the view see the files.
    The root keeps a derived table of the body files, _provider/seen.state.
  • A scenario with provider_bodies: true writes every call's bodies in both formats. The new
    property provider_bodies_rebuild reads each body a call lists from only the provider files up to
    its own, as an on-demand reader does, on the root and on its repacked copy.
    provider_bodies_leave_the_fold compares the fold without them, and parts_keep_source_bytes
    rebuilds every body and compares it with its file. An expectation's collect.max_delta_bytes is
    written into the build's configuration, and the check collects by it. A scenario removal waits until
    every body the build wrote is landed, deletes the body files with the session's other files, and
    drops the session's lines from _provider/seen.state. tests/scenarios/provider-bodies.yaml is the
    example, with bodies cut into five files.
  • asz view draws the prompt too. The embedded renderer moves to Horizon 53c1f63b. Horizon
    0ce1f8d6 added the inspector's Prompt tab, and the page gains the files route that tab reads: GET /api/c/{conversation}/files?session=&seq= returns the landed files by sequence, at most 32 a
    request, as base64 in a JSON array. The renderer offers the tab only to a host that can read files,
    so without the route the page beside the storage root would have shown less than the SkyWalking UI.
  • The Prompt tab reads a message in either spelling. Claude Code sends a message of one text
    block as a list of blocks while it is the newest, and as a plain string once it is not. The
    renderer before Horizon 53c1f63b took the two for different messages, so it reported an
    ordinary growth step as a rewritten history: 60 of 62 steps on one real conversation of 94 calls.
    It now reads both as one message. When the history does change, it says the context was replaced
    by a summary, with how many messages became how many, or warns when the history changed without
    getting shorter. Claude Code Provider Bodies describes
    both spellings.
  • A scenario writes the prompt its agent sends. system_prompt and tools say what a stream's
    requests carry, on the scenario for the main stream and on an agent, skill or workflow child
    for its own. Before this every scenario sent the same stand-in, which advertised Read and Bash
    whatever the agent did, so a calendar assistant was drawn as a coding agent. The stand-in stays for
    a scenario that writes neither, because it is sized to make a body worth cutting. A response now
    carries the call's own usage, the numbers its transcript already records.
  • A scenario build records the signature it drops from every thinking block, as the adapter does.
    The .sd writer recorded the drop only for reasoning whose text was already gone, so a session
    whose reasoning kept its text folded to another conversation through the transcript writer.
    tests/scenarios/reasoning-text.yaml writes both shapes in one session.

Collection

  • The collector's default interval is 10 minutes, in asz.yaml and when no configuration is
    given; it was 5 seconds. Every pass that finds new records lands new files, so a period of
    seconds wrote many small files, and each one is a log record when sent. asz collect and
    asz server still make a pass when they start. A configuration that sets interval keeps its
    value. Configuration explains the choice.
  • A scenario build writes interval: 5s into the configuration it creates, so a collector beside a
    feed still picks up each session as it arrives. A directory an earlier build wrote without an
    interval is brought up to date instead of refused.

Install

  • The Claude Code plugin installs from a marketplace. 0.3.0 told users to run
    claude --plugin-dir on the packaged plugin, which Claude Code keeps for one session only, so the
    next plain claude recorded nothing and said nothing. The repository now carries
    .claude-plugin/marketplace.json, and claude plugin marketplace add at a version's tag, then
    claude plugin install asz-changes@skywalking-ai-sessionizer, keeps the plugin installed across
    sessions. The manifest and the hooks moved to plugins/claude-code/plugin/, which holds only what
    Claude Code reads and its own LICENSE and NOTICE, so no Go source reaches a user's plugin
    cache. The manifest names no version, so the version is the tag's commit and no release can leave
    a stale one behind. Claude Code Plugin gives the commands, and
    how to upgrade without losing records asz has not collected yet: removing the marketplace deletes
    the plugin's data directory unless the plugin is first uninstalled with --keep-data.
  • The hooks run asz-claude-plugin by name from PATH, as Anthropic's language server plugins
    run their servers. A binary inside the plugin would have to be committed for every platform, and
    a source release carries no compiled file. With no binary on PATH, Claude Code 2.1.274 reported
    Executable not found in $PATH for the hook, and the tool still ran.
  • Each binary package holds asz and asz-claude-plugin side by side, with LICENSE, NOTICE
    and licenses/, and no claude-code-plugin/ directory. make build writes both to bin/. The
    package smoke test finds the plugin's binary by name on PATH. The candidate check in
    tools/release/release.sh, and the Scoop and winget manifests follow the new layout, and put both
    binaries on the path. The Homebrew formula becomes two, one for each install: asz and
    asz-claude-code. The tap is this repository: after each release the formulae go to Formula/
    on main, which .gitattributes keeps out of the source package, and users run
    brew tap apache/skywalking-ai-sessionizer https://github.com/apache/skywalking-ai-sessionizer,
    then brew install apache/skywalking-ai-sessionizer/asz and .../asz-claude-code.
  • Every release stays installable with Homebrew. Each release adds asz@VERSION and
    asz-claude-code@VERSION, keg-only, beside the current formulae, and moves asz and
    asz-claude-code only forward.
  • The steps after the vote that write for a package manager are skills and documented steps, not
    scripts.
    tools/install-manifests.sh, which publish ran, is gone, and publish now
    writes only the announcement and the website entries. The homebrew skill in .claude/skills/
    holds the formula templates, writes the formulae of a released version, runs each through
    brew style, brew audit --strict, brew install and brew test, and opens a pull request to
    main. The apt skill adds a released version to the apt repository and opens a pull request to
    apache/skywalking-website. The Scoop and winget manifests are in
    How to Release, with the commands that fill and test them,
    and its Release targets list where a released
    version goes.
  • Debian packages, and an apt repository on the website. Each release ships
    apache-skywalking-ai-sessionizer-VERSION-bin-asz-ARCH.deb and ...-bin-asz-claude-code-ARCH.deb
    for amd64 and arm64, voted and signed with the other packages. tools/release/deb-package writes them in
    make binaries from the same staged files, with the same time, owner and modes, so a rebuild
    gives the same bytes on any machine. https://skywalking.apache.org/apt serves an index of every
    released version, signed with a key in KEYS, and .htaccess redirects that send apt to the newest
    version on the mirrors and to every older one on archive.apache.org. The apt skill writes them.
    CI's packages job installs the Debian packages with apt on Linux, on amd64 and arm64.
    Install gives the commands. candidate checks each .deb's contents and
    control file, and make binaries removes .DS_Store, ._ and __MACOSX files from what it
    packages.
  • Two install scripts, one for each install. asz, the collector, and the Claude Code plugin are
    installed apart. install/asz.sh and install/asz.ps1 install asz, and
    Install runs them from the version's tag in one command. The
    plugin's own scripts, install/claude-code-plugin.sh and install/claude-code-plugin.ps1,
    install asz-claude-plugin and add the plugin to Claude Code at the same tag, and
    Claude Code Plugin runs them. The reader sets the
    version. Each script downloads the package and its .sha512: through the mirrors for the newest
    release, which is all downloads.apache.org holds, and from archive.apache.org for any older one.
    It stops unless they match, checks that its binary starts, and installs it
    where the Claude Code installer puts claude: ~/.local/bin, or %USERPROFILE%\.local\bin.
    Run again with a newer version, the plugin's script uninstalls the plugin with --keep-data
    before it moves the marketplace, and copies a 0.3.0 settings.yaml over once.
  • CI runs the install pages with Claude Code. A new claude-code job runs
    tools/test/claude-code-check with Claude Code 2.1.274 on each binary package's platform, Linux, macOS
    and Windows on x86-64 and ARM 64. It runs both install commands as the pages write them, the
    plugin's upgrade by hand and by its script, and its install by hand, with only the download
    addresses pointed at the runner. A headless session must be recorded by the plugin and collected
    by asz, a session without the binary must still run its tool, and each upgrade must keep the
    plugin's data. Before, no platform ran the plugin's hooks inside Claude Code in CI, and Windows
    never had. It passes on all six. On Windows the hooks' asz-claude-plugin starts
    asz-claude-plugin.exe, and both scripts run in Windows PowerShell and PowerShell 7.

Documentation

Release

  • publish asks whether the version becomes the latest GitHub release before anything moves, and
    promotes with that answer. Before, promotion left the Latest label on the older release, because
    CI creates the prerelease with --latest=false. The answer offered is yes for a version newer
    than every full release, and no for a patch of an older line. --latest and --not-latest answer
    without asking. The latest image tag follows GitHub's latest release, so one decision moves
    both. Before, the image took the highest version on its own.
  • website.txt is a release for data/projects.yml, the one file where the SkyWalking website now
    keeps its downloads and its documentation. Before, it held entries for data/releases.yml and
    data/docs.yml, which the website no longer has, so the 0.3.0 entries were rewritten by hand.
    The release is marked the latest, with the Latest documentation, only when GitHub's Latest label
    names it. A run after promotion reads the label, so its entries agree with the label too. The
    release guide describes the new shape, and the steps publish prints name the new file.
  • The text of the GitHub release links the changelog's other pages at the tag. The changelog links
    them by a path relative to itself, which on the 0.3.0 release page resolved under /releases/
    and found nothing.
  • tools/ is in two folders. tools/release/ holds what makes a release: release.sh,
    ci-binaries.sh, ci-upload-binaries.sh, package-check.sh, dep-notices.sh and
    deb-package. tools/test/ holds the checks CI runs and the tests of the release scripts. Folder
    names separate their words with a hyphen. tools/otlpdump is gone: TestCaptures in
    internal/metrics writes a new capture with its identifying values replaced, and checks every
    committed capture on each run.
  • prepare refuses to run on a detached HEAD, where it would push the tag and then have no branch
    to raise the pull request against.

Where to get it