[release] v0.114.8 - #6526
Merged
Merged
Conversation
…ceptor Prevents destructive mutation of the caller's kwargs dict. If the intercepted function is retried, the request key remains available.
Adds @lru_cache(maxsize=1) to avoid recreating the Fernet instance on every encrypt/decrypt call. Reduces SHA-256 + base64 overhead for vault operations under load.
'mretrics' → 'metrics'. No behavior change.
…ser_profile assert statements are stripped when Python runs with -O (optimize). This caused silent failures where None leaked into downstream code. - db_manager.py: assert workspace_id → if + raise ValueError - user_profile.py: assert user_id → if + raise HTTPException Verified with custom test script under both python and python -O. No behavior change under normal execution — only makes the code safe under python -O.
The deprecation warning system was a no-op because it used getattr(env, old_var, None), which always returns None. env is a module/object, not os.environ. Changed to os.getenv(old_var) so deprecation warnings actually fire when users set old environment variable names. Verified with local test script showing warnings now emit correctly.
…hs in dispatch_schedule
On a keyless account, a message typed in the /m composer was stashed in pendingTasksAtom and held correctly, but nothing rendered it. The screen showed only the AgentIntroCard below the connect-model strip, so the person could not see what they had typed. This matches the desktop behavior: the desktop renders the held seed as a visible user turn above the connect-model banner. Mobile now matches that. Changes: - Read pendingTasksAtom non-destructively (without consuming the entry) in LiveConversation to get the held task text. - Render it as a right-aligned user bubble in the transcript whenever heldTaskText is set, placed above the AgentIntroCard. The bubble disappears automatically once the gate drops and the send effect fires (takePendingTaskAtom removes the entry from the atom). - Pass 'Connect a model to start chatting...' as the composer placeholder when modelBlocked is true, matching the desktop disabled-state copy. - Thread a placeholder prop through Composer to ChatComposer so the host can override the default idle placeholder. Fixes #6209 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Christian-Sidak <61099993+Christian-Sidak@users.noreply.github.com>
The rail orders agents by chat-session count and sessions by recency, with no way to override either. This adds the persistence port and the pure merge helpers behind a manual order, and folds it into the agent ranks. Ranks are the one choke point every agent surface reads — the Agents group and the agent headings under Sessions — so applying the arrangement there makes it impossible for the two lists to disagree. No UI yet: nothing writes a zone.
…gement Applies the manual order at the ref and group atoms, not at render: the row cap slices before grouping, so a render-layer sort could never promote an agent past the fifth row. Each heading arranges its own rows, so a cross-heading drop is impossible by construction. Buckets with no zone — Pinned, Recent, any date heading — pass through untouched, which is how pins keep leading. Rows and headings now carry a dragItem describing their zone; nothing acts on it yet. The rail also holds its children still while a drag is in flight, so a poll cannot move a row under the pointer.
Press a row and move, and it drags; a 2px accent line marks where it will land while the source fades in place. No row reflows under the pointer, because nothing in the list is animated: the rects are measured once at dragstart and only a chip and a line move per frame. The engine runs outside React and loads lazily on the first press that lands on a draggable row — NavMenu is a static import on every page, and most sessions never drag. Rows are anchors, so the native link drag is suppressed or its ghost would ride along with ours. Alt+Arrow moves a row without a pointer.
Touch cannot both long-press a row's menu and long-press to drag it, so Move up / Move down join the row menu as reserved keys the shared verbs never see. They are equally the keyboard path. The filter menu's Reset now clears the arrangement alongside the filters, so trying a drag is reversible. It reads 'Reset' rather than 'Reset to defaults' because it covers two things now. Its enabled state comes from a new atom, not the existing filters-dirty one: that also picks the empty-state copy, and widening it would make a hand-arranged rail claim no sessions matched its filters.
Moves the drag geometry into @agenta/navigation beside the other order helpers: it is pure math over cached numbers, and that package has the vitest harness while navigation-ui has none. Covers the case the merge exists for — a drop in the 5-row Agents group must leave a twelve-agent arrangement intact — and composes the rank injection through the real sorter, where a sign error would otherwise only show up on screen.
…wser An agent heading saved itself under its group key (agent:<id>) while the Agents group saved bare workflow ids. Both write the same zone, so the two surfaces disagreed and a heading drag reordered nothing. Headings now map their key to the bare id through the reorder descriptor. The drop also read the index only the animation frame sets, so a drag released before any frame ran — a fast flick, a backgrounded tab — committed the index it started with and dropped nothing. The index is now resolved at drop time.
Date and flat grouping must offer none, agent headings must save under the bare agent id so they share the Agents group's zone, and pins must never be arrangeable. All of it is a table the browser cannot easily be driven through, and getting it wrong is silent.
Rows no longer swap to a grab cursor on hover, and the drag no longer forces a grabbing cursor on the body. The reference interaction keeps a plain arrow throughout; the swap was an affordance it does not have. The chip and the insertion line remain the feedback that a drag is on.
A group's drop slot was measured from its heading element alone, so the line snapped just under the heading text and a group could never be dropped past another group's sessions. Each group now measures its whole block — heading plus the rows under it — which also puts the midpoint that picks the gap where the eye expects it. The drag chip was rendering in the browser's default font: preflight is off and the chip is a sibling of #__next, so it inherits none of the app's typography. It also shrank to its own text; it is the row lifted out, so it now keeps the row's width and height and rides centred on the pointer.
font-sans did nothing: Next declares its font variable on the app's root element, and the chip is a sibling of #__next, so the class resolved to no family and the chip fell back to the browser's default serif. The chip now copies the dragged row's computed type instead of declaring its own — which also makes a heading chip read like a heading and a session chip like a session, rather than both taking one hardcoded size.
…e the rail Pinned is a group heading like any other, so it was stamped draggable in the agents zone — and slicing "agent:" off "pinned" left an EMPTY id, so dragging it would have written "" into the agent order. "No agent yet" hit the same path and resolved to "none". A heading now opts out by resolving to no id, and Pinned opts out of the status heading order too. The chip also tracked the pointer horizontally. Now that it carries the row's full width, that hung it out of the rail and over the page whenever a drag did not start at the row's far left. It is pinned to the row's own left edge and moves vertically only, as the reference does.
The chip copied the row's line-height, which on a leaf row is 28px, and was then forced to the row's full height on top of that — a tall box with the label riding high in it, since a heading's box is padded pt-2/pb-0.5 rather than symmetrically. It is now a compact pill: the row's width, its own symmetric padding, leading-none, and the label centred. Its half-height is measured once after append rather than read per frame, so the drag loop stays free of layout.
The reset clears the hand-arranged order alongside the filters, and both are what defaults means here. Every other filter menu in the app uses the component's own label, so the override went away rather than this one menu reading differently.
Dragging and Alt+Arrow already cover reordering, and the verbs pushed a row's position and neighbours through the wrapper contract into both hosts just to render two menu items. The row wrapper goes back to two arguments, so nothing about a row's place in its zone has to travel with it.
The kebab is now the only way into a row's verbs, and a rail row keeps the browser's own context menu. Scoped to SessionRowActions, which is the sidebar's wrapper — the sessions list, the tab rail and the chat tag bar keep theirs. It also removes a touch collision: that menu opened on a 700ms hold and the drag starts at 350ms, so the two could not both exist on a finger.
…arately Both agent lists wrote one zone and read one rank atom, so dragging a heading in Sessions silently reordered the Agents nav group too. They answer different questions, and arranging one is not a statement about the other. The headings now carry their own zone and reorder like the status headings do, while the nav group keeps the rank injection. Their DEFAULT order still agrees — both fall back to the same chat-session counts — so the two only diverge where the user has actually placed something. Splitting the zones also retires the reason mergeManualOrder was argued for; it stays for the real one, which is filters and the fetch window hiding part of a zone at drop time.
…q-triggers-worker Fix/malformed UUID in taskiq triggers worker
…n-user-id fix: emit wildcard for omitted user_id in cache invalidation pattern
Contributor
Author
Railway Preview Environment
Updated at 2026-09-05T09:44:47.153Z |
…-5659 doc(agent-workflows): remove stale built-in tool guidance
Contributor
Author
📘 Docs preview
This comment updates in place on every push. |
…s-db-manager fix(api): replace assert with explicit exceptions in db_manager and u…
* docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
|
|
* docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
…6466) * feat(frontend): add agent version history drawer with config diffs and revert Replaces the agent header's version dropdown with a drawer that lists every version and its commit message, shows what a selected version would change against the configuration on screen, and restores one behind a confirmation. Revert is a normal commit whose content happens to be old, so history is never rewritten: the selected version's parameters and schemas are staged onto the current revision and committed as a new version. It goes through the auto-commit flush rather than committing directly — staging a draft arms that debounce, and a second independent commit would race it and could mint two versions from one click. If the commit does not land, the staged draft is rolled back, unless the revision was already dirty, so a failed revert never discards the user's edits. Extracts the commit modal's section list into @agenta/entity-ui/changes as ChangeSections. AgentChangesSummary statically imports DiffView and the Lexical editor behind it; the drawer also runs on mobile, which bans Lexical outright. AgentChangesSummary now wraps the extracted list and keeps the JSON view and drill-ins, so the commit modal is unchanged. Both surfaces get this from the shared AgentRevisionStatus, so the desktop playground has version history for the first time. pickerWorkflowId becomes historyWorkflowId — it no longer names a picker. * fix(frontend): pick the latest revision by version, not timestamp The playground could open on a stale revision and stay there. "Latest" was scored by created_at with version reachable only when every timestamp was missing, and the picker compared with a strict >, so revisions an agent commits itself — which land in bursts that tie to the second — let array order decide which one won. The wrong pick then stuck: it is written to the latestRevision key, mirrored to IndexedDB, and that query is disabled whenever the key already holds a value, so nothing revalidated it. Version is server-assigned and monotonic, so it decides; timestamps only break ties within a version. One shared isLaterWorkflowRevision replaces the three sites that each had the bug: the recency picker, the latestRevision prime guard, and the by-workflow refs sort. Opening the drawer re-primes latestRevision through the same picker, so a poisoned cache repairs itself. The drawer keyed its disabled row, hover, default selection and the footer's version arithmetic off the revision on screen. With the surface parked on an older one that auto-selected the latest and offered to revert to it. All four now key off the latest revision instead. Also drops the last path from a version to switching the playground: selecting a version only ever previews it now. That removes the per-row "Open" action, and with it the mobile top bar's revision pin — SessionWorkspace still pins on auto-commit, which is what that atom is for. The desktop agent header loses its variant picker: an agent is edited as one thing, and the vN chip is now the single control, opening the drawer exactly as it does on mobile. Other workflow kinds keep SelectVariant. The save-status tooltip is gone from Saved/Draft/Saving, where it only repeated the word beside it, and kept on failure, where it carries the error and the retry hint. * fix(frontend): name gateway tools in the diff by what they do The tools section of a config diff read "Gateway", "Gateway", "Gateway connection" — the type discriminator, not the tool. A reader could see that something changed but not which tool was added or removed. Canonical gateway tools carry no function.name, so normalizeTool fell past its function branch into the bare-type fallback and title-cased raw.type. The identifying fields were in the object all along; only the label ignored them. The config panel's describeTool already reads them, so the same tool had two names depending on where you looked. Both now go through the shared humanizeActionKey / parseGatewayToolSlug helpers, and the legacy slug encoding resolves to the same name as the canonical one. The technical action key stays on rawKey for the detail view. Also gives canonical gateway tools a stable identity. They had none, so agentItemIdentity fell to a positional key: replacing one action with another at the same index read as a single edited slot instead of an add and a remove, and reordering tools reported false adds and removes. Keyed on provider:integration:action:connection now — the config panel's per-row draft indicators share that function and get the fix too. Advanced parameters still render raw dotted paths; that needs wording decisions and is left alone here. * fix(frontend): name advanced settings in the diff, not their storage paths An advanced-settings row read `runner.permissions.default allow → allow_reads` — the JSON path and the stored enum. That describes where the value lives, not what the setting is, so a reader who has not seen the schema learns nothing. Adds a label map keyed by exact path: the same leaf means different things under different parents, so `harness.permissions.default_mode` is not `runner.permissions.default`. Wording follows the config panel's own controls so one setting is not called two things in two places. Unmapped keys humanize (`sandbox.network_access` → "Sandbox › network access") rather than being hidden — a new template key should read imperfectly, never disappear. Model & harness reaches the same renderer and had the same problem, so its keys are mapped too. The four permission-policy names lived in @agenta/entity-ui, which @agenta/ entities cannot import. Moves that vocabulary to @agenta/shared and leaves the entity-ui module re-exporting it, so no call site moves and the config drawer, the /permissions palette and the diff cannot drift. Labels are ADDITIVE. The first cut overwrote before/after with display strings and broke sectionChanges.changeFor(), which reads those back to tell the config panel what a property was committed as — it started receiving "Ask" where it expected "ask". Stored values are untouched; beforeLabel/afterLabel carry the display form, and the renderer falls back to the stored value when there is none. * fix(frontend): stop the diff depending on an unlanded shared helper CI failed on four jobs: mobile types, the web unit tests, and both agenta-web image builds. All of them on one error — accessors.ts: Module '@agenta/shared/utils' has no exported member 'humanizeActionKey' The gateway-naming fix was written against a two-argument humanizeActionKey in @agenta/shared. That function is not on this branch or on the release base: it exists as a one-argument version inside @agenta/entity-ui, and a branch in flight is moving a two-argument one into shared. Locally it resolved because that unlanded work is present in the shared working tree, so every local run was a false green. Adds humanizeGatewayAction to the diff's own gatewayName module instead, with the same behaviour, so this branch depends only on itself. @agenta/entities cannot import @agenta/entity-ui, so the base's copy was never reachable either. When the shared helper lands, converge on it rather than keeping a third copy — the comment on the function says so. * fix(frontend): land the other half of the subagent description diff Commit otq was meant to carry the whole subagent fix but only its accessors half reached the branch: subagents were named correctly while classify still skipped field diffs for non-function tools, so an edited description registered as "edited" with nothing to show — the exact defect that commit claims to fix. The three regression tests went missing with it. Every tool kind now goes through diffToolFields. A subagent has no function parameters, so the params half finds nothing, but the description half works. * chore(frontend): cut the new comments to the repo's one-line rule web/CLAUDE.md: at most one short line per comment, no multi-line blocks narrating why. The new code broke that in ten places. CodeRabbit flagged nine; the tenth was the storybook header. Trimmed every block this branch introduced. Pre-existing blocks elsewhere in these files are left alone, and function/file JSDoc stays as the repo writes it. * fix(frontend): resolve the review findings on the version history drawer Accessibility: the section header, the detail-card header and the edited-tool row were clickable divs with no tab stop or key handler, so a keyboard user could not expand a section or open a tool detail at all. They are buttons now, with a focus ring. The commit modal renders the same component and gets the fix. Over-engineering: the revert phase and the reverted-from version were global atom families, exported as package API, read by nobody but the drawer, while mobileView three lines away was useState. Phase is local state now, and revertedFrom is gone entirely: it always equalled the selected version, because a revert never clears the selection. Correctness: - diffLoading ignored currentParams, so an unresolved current configuration rendered as "nothing to compare" and disabled Revert. - mobileView never reset on close, so a phone reopened on the diff pane. - Rows stayed clickable during a revert, and selecting one reset the phase that the in-flight revert then overwrote with a result for the abandoned version. - A failed revert left OUR staged parameters in the draft. It snapshots a pre-existing draft and restores it now, so "your agent is unchanged" is true. The test mock never modelled the draft atom, which is why this passed before. - scalarValueLabel saw fmtScalar's output, so the string "false" rendered as "Off". It takes the raw value and maps only real booleans. Also drops `any` from the new test mocks and trims the last long comments, both per the repo's guidelines. * fix(frontend): ignore a revert that resolves after the drawer is abandoned EnhancedDrawer dismisses on Escape and on an outside click, so a commit can outlive the drawer that started it. handleClose reset the phase to idle, then the in-flight revert overwrote that with done or failed, and reopening showed a terminal footer for a flow the user had walked away from. A run counter, bumped on close and on selecting another version, makes a stale result recognisable so it is dropped. Same race the row-selection guard closed, reached the other way. * fix(frontend): render MCP and Skills rows in the change diff The section renderer gated its item list on id === "tools", so an expanded MCPs or Skills section painted a header over an empty body — in the version history drawer and in the commit modal alike. Rows now render for any section that has them; the drill-in stays tools-only, since that is the only kind with a detail view. * feat(frontend): give subagents their own section in the change diff Subagents are stored as {type:"reference"} entries inside the agent's tools array, so the diff listed them among the real tools — "hourly-news-3vhu · Subagent" under a Tools header, and "Added 1 tool." in the commit message. The config panel has kept them apart since #4860; the diff now matches it. The classifier splits that array by kind and emits Tools and Subagents separately, so the panel's Subagents accordion also stops borrowing the tools change key — adding a subagent no longer lights the Integrations header. * feat(frontend): match the change diff's sections to the config panel Same icons for the same sections (Integrations, Subagents, Instructions, MCPs, Skills, Model, Advanced), so the diff reads as the panel it describes, and the instructions detail card takes its icon from that one map rather than its own. Tools becomes Integrations only for an agent template. The prompt playground shares this classifier and has no integrations, so its section keeps the old name — the commit message follows the same split ("Added 1 integration"). * chore(frontend): reach the version-history panes through the package boundary The stories imported ChangesPane, RevertFooter and VersionList by relative path into playground-ui's src/, past an export map that already had a subpath for them, and Storybook declared neither playground package as a dependency. The subpath now exports the three panes, and @agenta/storybook depends on the packages it renders. * fix(frontend): put the diff, its section headers and the footer on one edge The ghost accordion bled its header band 8px left and right but hung its body off a one-sided -ml-3.5, and the text-diff branch added another 14px indent on top, so the header band, the diff rows and the drawer's footer buttons each ended on a different line. The bleed is now one constant applied to both boxes, rows inset by the same amount instead of a hardcoded 3.5, and the drawer's footer takes the matching padding. * fix(frontend): drop the Reverted tag from the version list A row already says it was a revert — its commit message reads "Revert to v1". The tag repeated that next to Latest, and it was the only reader of isReverted, which sniffed the message prefix to derive display state. Both are gone. * fix(frontend): align the diff bands by filling the pane, not by bleeding out The previous attempt hung the section bands on negative margins, which cannot work here: the body sits inside HeightCollapse, whose overflow-hidden clips a band bled outward, so the header band and the diff rows still landed on different edges. The pane now carries the smaller inset and the bands fill it edge to edge, padding their content inward — no negative margins anywhere, so header band, diff rows and the footer buttons share one left and one right edge. * fix(frontend): list a lone first version as a normal row A single-version agent replaced the whole rail with a notice saying there was nothing to compare, hiding the one version it does have. v1 now lists like any other row — disabled, as the latest always is — and the pane beside it still says there is nothing to compare. * fix(frontend): title the diff's model section Model, as the config panel does The section header read "Model & harness" while the panel it mirrors calls the same grouping "Model". Label only — the harness engine still belongs to this bucket, exactly as it does in the panel. * fix(frontend): say the version pane previews the revert, not the version The rows are the diff between the selected version and what is on screen, so a tool added in v5 shows as a REMOVAL on v1-v4 — restoring any of them would take it away. Read as the version's contents, that looks like the tool is in every version. The pane now names what it is showing. * fix(frontend): stop an empty diff claiming a version matches the current one No sections only means nothing the classifier RECOGNISES changed, but the pane said "This is the current configuration" and the footer disabled Revert — so a version differing in an unclassified field looked identical and could not be restored at all. The stored configurations are now compared directly. Identical and "you are on this version" each get their own line and keep Revert disabled; a real but undescribable difference says so and stays restorable. * fix(frontend): give the version drawer one baseline, the latest version The pane diffed against the revision the surface happened to sit on while the footer counted from the latest, so on an older revision the drawer quoted two different versions without naming either. Everything now measures from the latest: the diff, the identical check, and the footer's counts. isCurrent goes with it — nothing rendered it once the list keyed disabling off isLatest. The done notice stops naming a version too; it fired before the list refetched, so the number it printed was the version being replaced. * feat(frontend): show what each version changed, not what restoring it would do The pane diffed the selected version against the head, so a tool added in v9 appeared as a REMOVAL on every older version, the newest version could never be inspected at all, and the first version showed a change despite changing nothing. Four separate confusions, one cause: the rail's messages are history while the pane answered a question about a button. Each version is now diffed against its predecessor, so the pane and the message beside it say the same thing. The latest becomes selectable and is where the drawer opens; the oldest says it has nothing before it. Revert is unchanged and still measures against the head, since restoring a version that already matches it does nothing. * fix(frontend): make the history trigger and the permission rows say what they are * fix(frontend): put the per-section change counts back in the drawer * fix(frontend): let the pane title carry the tense "Version 9" plus a separate "What v9 changed" line said the same thing twice and buried the tense in the smallest text on screen. One title now: "What version 9 changed", with the commit message under it. * feat(frontend): diff an edited skill's body, like the instructions A skill is prose — its SKILL.md body — but an edit showed only the skill's name under a pencil, so what actually changed was unreadable. Edited entries now carry the same folded hunk diff Instructions uses, and the row names which half moved: description, instructions, or both. * fix(frontend): read a renamed skill as an edit, not a swap A list entry is keyed by its name, so renaming one in place read as "1 added, 1 removed" — two rows, and the body diff behind them never computed, which is the change you most want to see when a skill is rewritten. Leftover additions and removals are now paired by the slot they occupy. The row shows both names ("stop-slop-1 → stop-slop-2") and names what moved. * feat(frontend): describe an integration's permission change An integration's policy lives on its tools entry as policy.permissions, which normalizeTool dropped — so the whole-entry fingerprint caught the edit and the row said only "changed". Every permission edit looked the same and carried no information. The policy is now read and diffed: the default reads "permission Ask → Allow", per-tool overrides become their own field changes, and neither is counted as a parameter any more. * fix(frontend): separate the diff gutter from the line it marks A removed line whose content is a Markdown bullet rendered as "− - Greet the user warmly", two markers deep. The sign column now sits a clear step away. * fix(frontend): make the diff describe every change kind it reports Swept each kind of config change through the classifier and read what the row actually said. Five carried little or nothing: - A key no section claims was dropped SILENTLY — the diff reported no change at all. The unclaimed rest of an agent template now lands in Advanced. - Object settings printed their JSON: retry_policy read {"max_attempts":3,...}, now "max attempts: 3, backoff: exponential". - Sandbox rows printed storage paths; they take the control's labels and its mode vocabulary ("Filesystem: Read-only", "Network egress: Block all egress"). - harness.permissions.default_mode was labelled "Harness permissions" with a raw enum; it is "Permission mode: Accept edits". - An MCP server has no prose, so an edit showed only its name. The row names the field that moved. * fix(frontend): drop the redundant count and name what every tool edit moved The "N changed" tag on a scalar section counted rows already listed beneath it. Lists keep their added/removed counts, which say something the rows do not. The two findings from the sweep, both of which ended at a bare "changed": - A single changed parameter is now named rather than counted ("to changed"), with the count kept once there are several. - Builtin, platform and reference entries carry no inspected fields, so only the whole-entry fingerprint fired. Their authored fields are now diffed too, so a builtin's option or a subagent's version is named. * style(frontend): square off the change tags rounded-full read as a pill next to the squared section band it sits on. * feat(frontend): show what an added or removed skill contains An added skill listed its name and nothing else, which says nothing about what the agent gained. The body IS the skill, so it now renders as an all-added diff (all-removed when the skill goes), with the description on the row. Whole-body diffs have no unchanged region to fold, so every item diff is capped at 12 lines with a "… N more lines" marker; the reported counts stay true. Built without the line differ, which reports an empty side as its own removed line. * feat(frontend): merge the version chip and save status into one control The version and its save state describe the same thing, and as two chips beside each other they competed — and the version chip still had to prove it was not a dropdown. They are now one button: a history icon, the version, and the save dot, opening the drawer. A failed save keeps its own chip: there the status IS the retry control, so it cannot share a button that opens history. * style(frontend): shrink the save dot 7px carried more weight than the status needs beside the version it now shares a control with. * style(frontend): fill only the version, not the status beside it The chip now wraps the icon and the version alone. The save state is a fact about that version, not a second control, so it sits outside the fill as a plain label — while the whole row stays one button, hovering as a unit.
[feat] Drag-and-drop reorder of agents and sessions in the sidebar
…afety [fix] Preserve agent drafts during version restores
[fix] Repair web acceptance tests and shorten preview CI
mmabrouk
approved these changes
Sep 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New version v0.114.8 in