Skip to content

VAF v0.1.0a21

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 Aug 17:29
· 36 commits to main since this release

Added

  • The README says plainly what VAF sends and where it goes. A new
    "What VAF sends, and where" section: VAF collects no usage data and reports
    nothing to Veyllo, there is no analytics SDK and no crash reporter, and the
    only outbound request VAF makes on its own is the startup version check
    against GitHub's public releases API - which carries no data about you and
    which update_check_on_start: false turns off. The section is equally plain
    about the other direction: if you point VAF at a cloud provider, your prompts
    go to that provider. "No telemetry" means Veyllo receives nothing; it does not
    mean a cloud-backed agent works without talking to the cloud. The README badge
    row now also shows the release, last commit, tool and test counts, the number
    of supported LLM providers, and the supported platforms.

  • The license now states, in one place, what a fork owes its users. VAF
    carries a short legal notice under Section 7(b) of the AGPL, in English and
    German, naming its origin and the obligations that come with it: pass it on
    under the same license, make the corresponding source available, and if you run
    a modified version as a network service, offer that service's users your
    complete source. It also names the commercial license as the way out of those
    obligations. A fork must keep the notice in its source. It does not have to
    be displayed anywhere, and it restricts nothing else - renaming, rebranding and
    commercial operation stay permitted, exactly as the AGPL allows. The notice is
    static text: nothing about it is transmitted, and it involves no telemetry of
    any kind.

  • Tools can write their own log lines: self.log(...). Every tool - including
    one written by a third party against the public BaseTool - can now report what
    it is doing without reaching into VAF's internals. Lines land in tools_*.log
    with the tool name and session filled in, follow the same VAF_LOG_DIR and
    Debug Logs settings as everything else, and are cleaned up by the same garbage
    collector. It never raises, so a logging mistake cannot fail a tool call.

  • Sessions can be created, renamed and deleted inside the terminal app.
    The sessions panel (Ctrl+S) gained n for a fresh session, r to rename
    the highlighted one and d to delete it after a confirmation - deleting
    the session you are in is refused until you switch away. /session new
    and /session rename <name> do the same from the prompt. The panel now
    shows the same list the web sidebar shows: messenger chats and internal
    thinking runs stay in their dashboards instead of flooding the list.

  • A session keeps ONE name everywhere, including across a web rename.
    Renaming is now a single engine operation that changes the session file
    and nothing else - before, renaming from a list could silently drag the
    renamed session's saved state into the running one. The terminal app
    adopts the on-disk name before saving on exit, so renaming a chat in the
    web while the terminal had it open no longer loses the new name when the
    terminal closes; the background worker had silently ignored web renames
    altogether and now honors them.

  • Switching sessions in the terminal app now shows the conversation.
    Loading another session swapped the agent's memory but left the previous
    conversation on screen, and a resumed session started with an empty
    transcript as if nothing had ever been said. The transcript now follows: a
    switch repaints the loaded conversation (the newest forty messages, with an
    honest note when older ones were trimmed - /export writes the full
    record), and starting VAF with an existing session shows its conversation
    under the start banner. Replayed messages carry the time they were actually
    sent.

  • Automations and the tool catalog live in the terminal app's settings.
    The Automations submenu shows what the classic menu showed - name, schedule,
    next run, enabled state - and selecting an automation switches it on or off;
    the storage folder opens from its own row. "Show All Tools" now opens the
    tool catalog instead of pointing at a restart.

  • The local model can be switched inside the terminal app, without losing
    the conversation.
    "Select Active Model" now lists the models on disk with
    the active one marked, and picking one swaps the running agent live: the
    llama server is restarted with the chosen weights (it verifies which model
    it serves instead of blindly reusing whatever runs), the model-specific
    behavior follows the new weights, and the chat you were in stays. The swap
    waits until the new model has loaded and says so; while a reply is being
    generated it refuses instead of pulling the model out from under it. With a
    cloud provider selected, picking a file stores the choice for the next time
    the local provider serves - as the classic menu did. Only the model download
    still points at vaf settings.

  • The context limit, custom numbers, the microphone and About live in the
    terminal app now.
    Four more settings rows stop pointing at vaf settings:
    the context limit offers the classic presets plus a free value and says
    honestly that it applies at the next start; the sub-agent timeout and the
    auto-open tab cap take any number in their classic ranges; the microphone
    submenu lists your real input devices and switches the live microphone at
    once; and About shows version, licence and links without leaving the app.

  • /export <file> writes the conversation from inside the terminal app -
    markdown, or JSON when the filename ends in .json. The sessions panel now
    shows each session's id and a line of its summary, and session current
    prints the full id - the one thing vaf run --session <id> needs and the
    panel can only truncate. session list opens the panel instead of failing as
    an unknown id.

Changed

  • Files VAF writes and reads back now say which format they are in. Three
    stores kept no format identity of their own, so a reader had to guess from the
    keys it happened to find. The filesystem index cache carries a schema tag and a
    cache without the current tag is rebuilt instead of being read as if it were
    current - previously any JSON file at that path with a matching os key was
    accepted, including one written by an older build or another tool. Handoff
    bundles are written with a format tag, and bundles stored before the tag keep
    loading, so an open handover is not lost across an update. The audit timeline's
    hash chain starts from a versioned seed; timeline files written earlier start
    from the old seed and still verify as intact. One visible effect: after the
    update the filesystem index is rebuilt once on first use.
  • The tool-use log now covers every lane, not only chat. tool_use_*.log
    records which session and which user scope were behind a tool call - the first
    place to look when isolation looks wrong. It was written from the chat loop
    only, so workflow steps, librarian sub-tools, training samples and tools added
    by an embedded application never appeared in it. The shared dispatcher writes
    it now, so all of them do. Two details worth knowing: a call that a permission
    check refused is logged too (a blocked attempt is exactly what this file is
    opened for), and the argument preview is sanitized the same way the live event
    stream already was, so a large field such as a file's contents is summarised by
    length and digest instead of pasted in whole. The coder's own tool loop does not
    use the shared dispatcher and is still absent.
  • A pip-installed VAF no longer writes logs into its own install directory.
    The log directory search included the folder above the package, which in a
    checkout is the repository and in a pip install is site-packages. Installed
    copies now fall through to the normal application data directory; a checkout is
    unaffected. Set VAF_LOG_DIR to choose explicitly.
  • Tool-loading diagnostics no longer print underneath the terminal app. The
    per-turn tool hot-reload, the custom-tool reload and a failed provider switch
    wrote their warnings straight to the raw terminal - under the full-screen app
    that corrupted the display mid-conversation. These messages now travel the
    same event lane as the rest of VAF's status output: the terminal app shows
    them as notes, the classic terminal shows the usual styled event line instead
    of a bare [WARN] ..., and the web log receives them too.
  • vaf run --web no longer starts the background service behind your back.
    The README has always described this command as the dashboard WITHOUT the tray,
    and the lane hosts the dashboard itself - but if the background service was not
    running, the command quietly launched it as a detached process that outlived
    your session. Now the dashboard lives and dies with your session, as promised.
    If you relied on vaf run --web to bootstrap the persistent service, start it
    the intended way: vaf tray. A service that is already running keeps serving
    unchanged.

Fixed

  • The sub-agent windows are dark in dark mode. The librarian's file browser
    came up with bright, near-white panels: its window body, the file area behind
    the listing and the toolbar above it were painted with fixed colour values,
    and fixed values do not follow the theme. All sub-agent windows shared those
    values, so the coder, research, document and browser views were bright in the
    same places. They are now defined once and follow the theme. Light mode is
    unchanged.

  • Asking about files in one folder no longer answers about another one. The
    librarian answers simple folder questions from a cached index in about a
    second. That index decided which folder to report from the file type in your
    question, not from the folder you named - so "how many PDFs are in Downloads"
    came back with the count from Documents, fluently and fast enough to look
    authoritative. Measured on one machine: 33 PDFs in Downloads, answer said 9,
    which is the Documents figure. The folder you name now decides the answer; a
    question with no folder gets the counts for every folder instead of a guess;
    and where the index has no figures at all it stays quiet and lets a real
    search run rather than reporting a zero nobody counted.

  • Clearing the chat while an answer is still arriving now discards that
    answer.
    The reply kept streaming into the freshly emptied conversation,
    so a paragraph appeared with no question above it - belonging to a history
    that was deleted a moment later anyway. The terminal app drops it and says
    so.

  • The model list no longer offers the vision helper file as a model. When
    local image understanding is set up, VAF downloads a second file next to the
    model - the "projector" that lets the model see pictures. It ends in .gguf
    like a model, so every model picker (terminal app, classic settings, web UI)
    listed it as a choice; picking it left the local server unable to start with
    a cryptic unsupported model architecture: 'clip'. Those files are filtered
    out everywhere now, and a configuration that already points at one falls
    back to a fitting model with a clear message instead of failing to start.

  • Switching the local model keeps your context size and GPU setting. The
    server was restarted with the defaults instead of your configured values, so
    a large context window silently shrank whenever the model changed - while
    the setting still showed the old number.

  • Setting a plan in the terminal app works on the first try. Tools run
    on the terminal app's worker thread, and that thread never learned which
    session it serves - so working-memory writes (plan, notes, tasks) landed
    in a global store while the plan check read the session's own, empty one.
    The agent then got "set a plan first" bounces despite having just set one,
    retried with reworded plans, and finally got through only because the
    check gives up after three blocks. Every worker thread now knows its
    session, so the plan lands where the check looks - first try.

  • An edit-only coding run no longer reports failure. The coding agent
    counted only files it CREATED, so a task like "add a section to the
    README" ended with "Task Failed - No files were created" over a
    successful, even committed edit. When nothing was created, the verdict
    now asks git what changed since the run began; edits count as the
    outcome, and only a run that truly changed nothing keeps the honest
    failure message.

  • The coder works in the folder you started VAF in. Open a terminal in
    your project (an IDE terminal counts), run vaf run, ask for a code
    change - the coding agent now works on THAT project. Before, the separate
    terminal it runs in started in your home directory instead of your
    project, so the project-detection never matched and the work landed in a
    fresh VAF_Projects folder. The main agent hands its working directory
    to every spawned sub-agent and workflow now; explicit paths in the task
    still win, and "create a new project" still gets a fresh folder.

  • Running project tests in the sandbox works on a fresh container. The
    sandbox image ships without pytest while pytest is the default test
    command, so every container recreation broke "run the tests" with "No
    module named pytest" until someone installed it by hand. The runner now
    installs pytest on demand (once per container) and reports honestly when
    it cannot.

  • Old chats without an owner no longer show up in every user's list.
    Sessions created before per-user ownership existed carried no owner mark,
    and the session list showed such sessions to every signed-in user - their
    titles were visible to people they never belonged to (opening them was
    always refused). On startup VAF now marks these legacy chats as the
    machine owner's, which is the only person they can belong to, and they
    disappear from everyone else's list.

  • The terminal app starts the Docker services, and a sleeping memory
    database is named instead of impersonating an empty memory.
    Quitting the
    desktop tray stops the service stack (database, sandbox, speech) - so a
    terminal-only session afterwards ran against a stopped memory database,
    and asking the agent what it remembered got "I have no stored information"
    over a database full of it. vaf run now brings the stack up in the
    background exactly like the tray does (the whole start/stop logic lives in
    one place now instead of only inside the tray), and when the database
    really is unreachable, the memory search says so - the agent will tell you
    the memory stack is down rather than declare itself amnesic. Without
    Docker, everything keeps working as before, minus the services.

  • Typing anything now interrupts the agent's speech in the terminal app.
    The classic terminal always treated any input as "stop talking, I have
    something to say" - spoken output is asynchronous and routinely outlives the
    reply that produced it. The full-screen app only silenced speech when a new
    turn actually started, so a slash command, a typo, or a message queued behind
    a running turn left the agent talking over you. Every submitted input now
    stops running speech before it is even parsed, silently; the explicit halt
    still says "speech stopped".

  • The settings no longer advertise a wake word. Both terminal settings
    menus carried "Wake Word" labels pointing at a feature that was removed from
    VAF months ago (the always-on listener was dropped in February together with
    its dependency). The dead row and the labels are gone; if a wake word
    returns, it returns as a real feature, not as a menu entry that leads
    nowhere.

  • Closing the "what's new" window no longer wipes parts of your profile. Dismissing
    the update announcement sent a single value to the server, but the profile endpoint
    treated everything the message did not mention as "set this to empty" - so your main
    messenger, city, country, timezone and date and time format were silently cleared, and
    the change was recorded as if you had edited it yourself. It happened on every release.
    Emptying a field on purpose still works: the settings forms send it as an explicit
    "make this empty" so it cannot be confused with a field that was simply not part
    of the request.

  • The profile history says who changed something, and admits when a value was
    removed.
    Entries recorded only what was touched, and always said "updated" even when
    a field had been emptied. Both made the earlier bug look like a manual edit.

  • Security logs are kept for two weeks instead of two days. They sit in the same
    folder as ordinary logs and follow the same naming, so the routine cleanup deleted them
    after 48 hours. Nobody noticed, because a missing log looks exactly like a quiet period.
    They now have their own retention (security_log_retention_days, default 14).

  • Voice input works in the terminal app. Pressing l (or listen) opens the
    recording overlay with a live level meter showing what the microphone actually
    hears, and the transcribed sentence is sent as your message - the same flow the
    classic terminal always had, and the conversation shows your words above the
    answer. If you would rather check the transcription first, turn on "Voice:
    review before send" (Settings, Voice): the sentence then lands in the input
    box for you to read and fix, and enter sends it. Escape cancels the recording
    itself, not just the window. The speech resources are prepared at startup
    while the terminal is still plain (Piper voice download, microphone check with
    an honest "pyaudio is not installed" where that is the reason, language
    detection warmup), so the first use does not stall mid-chat.

  • Voice capture works on machines using the Docker speech stack - which is the
    default.
    Recording answered "no speech detected" within half a second, in the
    terminal app and the classic lane alike: with the default speech engine the
    microphone was simply never set up, because the engine choice was misread as
    "no local capture needed" - it only decides where the audio is transcribed.
    The microphone is now prepared when recording starts, and the recording goes to
    the transcription lane you chose: your cloud STT provider if configured,
    otherwise the local Whisper container - the same path Telegram and WhatsApp
    voice messages take. It is never quietly rerouted to Google's free web API, and
    a dead speech stack is named as what it is instead of "no speech detected".

  • The classic recording line no longer prints formatting tags. The level
    meter wrote styling markup to the raw terminal, so the classic lane showed
    literally "[bold red]● SPEAKING[/bold red]" while recording - since the day it
    was written. It now paints plain text.

  • Browsing themes no longer changes your startup theme. Pressing t (or
    theme <name>) now switches the look for the current session only, exactly as
    the classic terminal always did - the Settings > Theme row is what saves a
    choice. Until now every press wrote the config immediately, so looking through
    the catalog once left the LAST theme in the list as your new default: matrix,
    which looks like a plain green terminal - and the next start seemed to have
    lost the VAF theme entirely. The switch note now says it changed this session,
    and where to save.

  • Workflow variable filling is deterministic, and its log tells the truth.
    When a matched workflow was missing inputs, which template default got applied
    could depend on Python's hash order (a fill loop removed items from the list it
    was walking), the log promised "using defaults" at a point where no default
    could exist, and the same missing input was reported twice. Defaults now fill
    first, the per-variable repair only handles inputs without one, and a single
    line says what actually happens: the turn falls back to the agent.

  • German answers are asked to use real umlauts again. For a while the assistant
    had taken to writing "fuer" and "laeuft" instead of "für" and "läuft", sometimes
    switching between both inside one sentence. That comes from the language model, not
    from VAF, and it feeds itself: the model reads its own earlier replies and copies the
    habit. The instruction VAF sends with every turn now asks for proper German spelling
    explicitly, which curbs it. It will not be perfect, and a fresh chat shows it best.

  • A bundled browser script that nobody used is gone. It was a copy of a third-party
    fingerprinting library, 43 KB, kept in the tree long after VAF stopped injecting it,
    and it carried no author credit. Deleting it is the honest repair: nothing changes for
    you, and one piece of somebody else's code no longer travels with every download.

  • The bundled PDF viewer now ships the license it is used under. VAF includes a copy
    of Mozilla's pdf.js worker so documents can be displayed; its license asks that
    recipients get the license text itself, and that text is now included rather than only
    linked.

  • A comment claimed the recommended voice model was Apache-licensed. It is not. The
    Gemma weights come under Google's own terms with usage restrictions. VAF never shipped
    the weights and still downloads them only when you choose that model, so nothing about
    your install changes - but the note in the code was wrong and is corrected.

  • Setting the sub-agent timeout to "no limit" no longer arms a zero-minute
    timeout.
    The row stored 0 minutes while the timeout stayed switched on - and a
    zero-minute timeout means every running sub-agent is stopped at the next cleanup
    pass. Choosing "no limit" now switches the timeout off, exactly as the classic
    menu always did, and choosing a duration switches it on.

  • The microphone list selects the device you picked. The classic picker
    numbers the list by position, but the list is filtered - so on machines with
    virtual audio devices the position could name a different microphone than the
    one shown. The terminal app reads the device number printed in each entry.

  • A long conversation no longer animates dozens of invisible dots. Every reply
    in the terminal app carries the agent's living dot, but only the newest one shows
    it - the hidden ones kept animating anyway, ten times a second each, so a long
    session burned more and more CPU drawing into nothing. The visible dot animates
    exactly as before; the hidden ones now rest until it is their turn again.

  • vaf update now tells you why it could not answer. Three different situations
    used to collapse into one sentence, "offline, or none published yet", whose two
    halves call for opposite reactions. The real case that exposed it was neither:
    GitHub allows unsigned-in requests only 60 per hour for a whole network address,
    so any busy tool on the same connection could make the updater claim there was no
    release minutes after one went live. It now says which it is - rate limit (with
    the time to try again), unreachable, or genuinely no release - and a plain
    permission error is not dressed up as a rate limit.

Security

  • DOMPurify updated (3.4.13). A sanitizer bug could leave a removed
    element's hidden children able to run scripts in applications that use one
    specific advanced mode. VAF's interface never uses that mode - the library
    only arrives through the code editor and the PDF export - so no VAF
    installation was exposed; the update keeps the dependency clean regardless.
  • PostCSS updated (8.5.26). The build toolchain's CSS processor could be
    tricked into reading arbitrary .map files when it processes CSS from an
    untrusted source without a known input file, disclosing their contents in
    the generated source map. VAF only ever runs it over its own stylesheets at
    build time, so no VAF installation was exposed - the update keeps the
    dependency clean regardless.
  • js-yaml updated (4.3.1). The YAML parser that the linter uses to read its
    own configuration resolved ordered maps in quadratic time, so a crafted
    document could stall the process that parses it. It reaches VAF only as a
    build-time dependency of ESLint and never sees anything but VAF's own config
    files, so no VAF installation was exposed - the update keeps the dependency
    clean regardless.