Skip to content

[release] v0.121.6 - #7232

Merged
ashrafchowdury merged 65 commits into
mainfrom
release/v0.121.6
Sep 30, 2026
Merged

ashrafchowdury merged 65 commits into
mainfrom
release/v0.121.6

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

New version v0.121.6 in

  • web
    • web/oss
    • web/ee
    • web/mobile
  • services
  • api
  • sdks
    • sdks/python
  • clients
    • clients/python
    • clients/typescript
  • kubernetes
    • kubernetes/helm

Agenta Team and others added 30 commits September 28, 2026 11:27
A record body holding a NUL (U+0000) cannot be stored: Postgres rejects it
from both `text` and `jsonb` with `UntranslatableCharacterError` (SQLSTATE
22P05). The record is already off the runner by the time the INSERT runs, so
the batch could only be redelivered — and it was, every 30s for over a day,
from one `tool_result` carrying console output.

It never isolated because the rejection was not recognised as permanent.
SQLAlchemy's asyncpg dialect wraps the driver error in its own generic
`AsyncAdapt_asyncpg_dbapi.Error`, which it then cannot map to a typed
subclass, so it arrives as a bare `DBAPIError` and not `DataError`.
`_append_committed` therefore returned before its one-record isolation pass,
leaving the good records in the batch uncommitted too.

Fix both ends:

* strip NULs at the producer boundary that already bounds body size, so the
  record is stored intact rather than quarantined. Record bodies carry
  arbitrary tool output, so a NUL is reachable from ordinary use — a `grep`
  over a binary file is enough.
* classify the rejection by unwrapping to the driver exception and reading
  Postgres's SQLSTATE class 22 ("data exception"), which is always a property
  of the row. Testing `DBAPIError` itself would be wrong: `OperationalError`
  and `InterfaceError` are subclasses too, and treating an outage as permanent
  is the silent record loss this worker exists to prevent.

Claude-Session: https://claude.ai/code/session_018YBQfPLZ8FVqcLevxcTmVU
A dropped connection (API restarting, laptop waking, offline) made every
polled session read log console.error, which Next forwards to the dev
terminal. The browser already reports these, so callFern now returns null
without logging when the request never reached the server.
A bare TypeError thrown by a callFern callback is a bug and must still log.
The session list scrolls with no scrollbar and fades at an edge with more
to scroll. Long session names fade at the row's edge instead of ending in
an ellipsis. Agent headings stay pinned while their sessions scroll, and a
reload scrolls the selected session into view.
The reveal ran only on a resize, so a selection that arrived after the rows
rendered was never scrolled into view.
Integrations, Skills and Automations headers in the agent config panel
now open a menu with 'Create with AI' beside the manual add. It writes a
starter prompt into the chat composer so the agent runs the setup.
The connect dispatcher dropped the host's bare flag, so each connect row drew the app icon twice. A connect the runner deferred to next turn drew the failed glyph instead of the app's mark. Client-tool rows had no minimum height, so their spacing did not match the other steps.
The run is still in progress while it waits on the user, so the header keeps the live shimmer. The glyph drops the warning color and matches the step glyph size.
A closed text became the answer after a 1.2s hold. A model that took longer to start its next call showed its aside as the reply, then pulled it back into the fold. A closed trailing text now stays in the fold while the run is open.
A failed profile read (network, 5xx, an aborted request on reload) resolved to no user and wrote sessionAtom false. Every entity query then stayed off, so after a refresh the agent name fell back to "Agent" and the agent's revision never loaded. Only a real signed-out answer now clears the session, shared user and user id.
An observer that unmounted during the first records read cancelled the shared flight, and hydration took the cancel as an empty log: the session showed as having no stored history. The read now retries a cancel, and a read that truly failed shows a load error instead of claiming the history is gone.
A send can flip this tab's stream on and off and then run on the shared reader. The closed local stream read as a finished run, so the first closed text (an "Auto mode unavailable" notice) showed as the answer while the header still said Answering. The hold now uses the same live signal as the header.
A request_input call that errored (a bad schema, a runner refusal, a stop) showed as "The question could not be shown". Failed tool calls are already hidden from the fold; failed questions now follow the same rule and stay in the parts and the trace.
A long reply lands whole when its run ends, and following the bottom dropped the reader at its end. An answer that arrives while the reader follows is now anchored at its first line until their first scroll input. A reload or session open still lands on the latest message, and a message sent after the answer resumes following.
The composer cleared the request before the lazy input was ready, which
cancelled its own retry and could drop the prompt. The request now stays
set until the text lands, and only the matching request is cleared.

Simplify: remove the composer-count atom and the plain-plus fallback. The
config panel only renders beside a composer, and a pending request now
waits for one.
The dock opened on a question whose input was still streaming or was the empty {} announce, so the card showed "This request couldn't be shown as a form" until the full schema landed. The dock now shows a question once its payload has arrived and parses; a bad payload still settles in the background, and a parked one still shows its Skip.
A failed header or records read was cached as an empty answer, so an unreachable server showed "Read-only - this session has no agent" and "no replayable history". The header read now throws on failure, and the session shows a "Couldn't load this session" state with Try again.
The deferred-connect helper import was out of order, and the records retry test still expected the old failed-read result without the failed flag.
A session that fails to load no longer borrows the last session's revision. A failed re-read of a tentative empty header counts as unreachable. The failed-history notice gets Try again, which re-runs hydration in place. A replay kept mounted across a session switch resets its follow and anchor state.
…ices

- Blog index and authors index descriptions no longer describe Agenta as
  prompt management / evaluation / LLM observability; they use the current
  workspace-for-agents definition.
- Every post published before the July 2026 relaunch now renders a dated
  update note (HTML page and markdown twin) linking to what Agenta is
  today. Publication dates and post content are untouched.
Agenta Team and others added 28 commits September 29, 2026 11:35
CodeRabbit review: {"type": "tool_result", "ty\x00pe": "other"} used to strip to
{"type": "other"}, letting a poisoned key displace the discriminator record
reconstruction depends on. The kept entry now wins on collision, and a clean
key always wins over a stripped one regardless of insertion order.

Also make the size-order test able to fail if truncation ran before
stripping: the body is oversized only because of the NULs, so the output
must survive whole with no truncation marker.
A message sent while a run was going flashed as a sent bubble in the chat, then jumped into the queue once the server parked it. When the queue released it, it vanished until its user row arrived. A busy-time send now shows as a queue row at once, matched to its server row by the send's idempotency key. A started row stays in the queue until its user row lands, for at most 2s. A send the server starts right away moves to the chat as before.
fix(api): stop a NUL in a record body from looping the records stream
…n-on-secret-change

[fix] Keep the Advanced drawer open after removing a custom secret
The composer upload sent only session_id, so the API fell back to the callers default project and stored the attachment there. The runner, scoped to the sessions real project, then got 404 and never read the file. Send the sessions project_id on upload like every other session-scoped call, make it a required uploadAttachment param, and guard the pre-hydration null.
…project guard

CodeRabbit: the transport test used a literal project, so a composer regression could pass. These hook tests assert the projectIdAtom value reaches uploadAttachment and that a missing project refuses the upload before any network call.
The rendered <img> read /sessions/attachments/<id>/content with only session_id, so the API fell back to the default project and a session in another project got a 404 (broken image). Send project_id from the same shared store the upload uses. The acceptance test (attach-send-render-reload) exercises this end to end; unit tests cover the URL builder.
…arker working

Two small, independent robustness fixes in the session record persistence path, from investigating the 2026-09-28 EU runner OOM incident (production-session-investigation).

1. Bound each ingest POST with a per-request timeout (AbortSignal.timeout, env AGENTA_RECORDS_INGEST_TIMEOUT_MS, default 30s). Without it a single stalled request holds the per-session persist chain, and behind it the turn-end drain, open for as long as the socket stays open. A timeout now throws and is retried like any other transient error.

2. Stop flush() from consuming the per-session drop count. The turn-end finally in server.ts is the authoritative reader that marks a session incomplete when a record was dropped; flush() consumed and cleared the count first, so that reader always saw zero and the session was never marked. flush() now drains only and leaves the single read to the caller.

Unit tests updated: the flush test now asserts the count survives for the caller. Typecheck clean; runner unit suite green apart from 4 pre-existing gateway-gating failures unrelated to this change.

NOTE: the larger runaway-output memory bound (the actual OOM cause: unbounded events[] and streamed-text accumulators in tracing/otel.ts) is a separate follow-up, to be placed at the otel choke point and terminalized through the existing run-limits RUN_LIMIT_TRIPPED path, pending a recorded full-stack QA pass.
Use the durable record project_id when rendering attachment references. Navigation can change or clear the active project while records are loading. Covers both changed and cleared project scope, explicit overrides, and null overrides.
Following the bottom snapped the scroller to each new message. Pins after the first now glide with native smooth scrolling, and stay instant on first load, a session switch, a jump past two screens, or reduced motion. A glide's own scroll events do not end following; any reader input does.
* fix(mobile): scope permission checks to the requested project

Without an explicit project_id query param, the auth middleware resolves
the request scope to the workspace's default project. The access check
then compares that default project against the requested scope_id and
denies every permission on a non-default project, which disabled the
custom-secret Attach button (and other edit_secret gates) there.

* test(api): pin the permission-check scope contract; docs per review

Codex review follow-ups: document on check_permissions that scope_id
asserts the authenticated scope (it never selects it), add a regression
test for the 403 on a scope mismatch, and shorten the client comment.

---------

Co-authored-by: Mahmoud Mabrouk <mmabrouk@users.noreply.github.com>
fix(runner): bound runaway output and preserve crash recovery context
…-scope

fix(frontend): scope session attachment uploads to the session project
[feat] Polish the sidebar session list and rail details
Stopping the mic without speaking showed "No speech was recognized".
Track the recogniser's speechstart event and raise the notice only when
the browser heard speech but returned no words.
[fix] Stop logging network failures of session reads as errors
…snapshot

fix(runner): version Daytona sandbox snapshots
[feat] Create with AI in the agent config add menus
…efresh

[fix] Polish the session timeline and survive failed reads on refresh
[fix] Show the no-speech notice only when speech was heard
@ashrafchowdury
ashrafchowdury merged commit 3ef280e into main Sep 30, 2026
57 of 59 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants