* feat(gateway): advertise chat attachment limits on hello-ok
Clients had no way to learn the gateway attachment ceilings, so external
clients hardcoded guesses that drifted from server enforcement. Publish the
two unconditional decoded-size ceilings on hello-ok policy.attachments from
one shared resolver so advertised values cannot drift from the parser.
MIME acceptance and per-message counts stay server-side: they depend on the
entrypoint, the resolved model, and payload sniffing, so they cannot be stated
once per connection.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 17d6c355-8948-4b48-a936-e08b1c8806ef
* feat(gateway): advertise chat attachment limits on hello-ok
---------
Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Copilot-Session: 17d6c355-8948-4b48-a936-e08b1c8806ef
* fix(cron): bound restart catch-up to the active schedule
Editing a recurring job's schedule made the gateway fire it immediately on
the next restart. Startup catch-up compares the new schedule's previous slot
against lastRunAtMs, which still belongs to the retired schedule, so a slot
that never existed under the old schedule counted as missed.
Record when scheduling inputs take effect and replay a missed slot only when
it is newer than that. Jobs whose schedule never changed carry no stamp and
keep replaying every computed slot, so catch-up is unchanged for them.
The missed-slot predicate was duplicated in the runnable check and the
backoff-deferral pass; both now share one helper so the bound cannot drift.
Fixes#91944
* fix(cron): protect schedule activation ownership
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* feat(gateway): manage audio and video attachments
* feat(gateway): preserve generated media metadata
* fix(gateway): align seeded managed media
* fix(gateway): scope pending media trust by URL
* fix(gateway): split managed media by trust
* fix(gateway): require terminal media trust unanimity
* fix(gateway): align managed media metadata types
* fix(gateway): refresh managed media contracts
* chore(ci): model managed media test seams
* test(sessions): expect canonical media kinds
* perf(gateway): warm handler families and cache identity avatars
* chore: drop changelog edit (release-generation-owned)
* fix(ci): regenerate protocol models, satisfy knip, absorb sidecar drift
- commit regenerated Swift GatewayModels for the additive cron.list param
- split the avatar data-url cache into assistant-avatar-cache.ts so its
factory has a production consumer (knip production scan)
- de-export prewarm family names/type; test now drives fake families only
- postReadySidecarCount 2 -> 3: main added a post-ready sidecar in parallel
* feat(ui): offer normally-absent core files instead of flagging them missing
The Agents core-files editor rendered every unwritten workspace file as a
permanently-badged MISSING tab, so an ordinary workspace looked broken. Absence
is only a fault for required files; SOUL.md, USER.md, and MEMORY.md are normal
to be absent until written.
agents.files.list now marks those entries expectedAbsent, and the editor keeps
them out of the tab strip behind an add picker that creates the file on save.
A missing AGENTS.md still shows as a fault.
* chore(protocol): regenerate Swift gateway models for expectedAbsent
* fix(gateway): carry expectedAbsent through agents.files.get
Clients merge the get response over the listed entry, so a missing-file get
that dropped the flag made a file picked from the add picker re-render as a
MISSING fault. Caught by live Control UI proof, not by the unit tests.
Add agent ownership to observer digests, scope global observer delivery and reconciliation, and centralize application session selection across navigation and reconnects.
Co-authored-by: xbrxr03 <abrarhabib03@gmail.com>
* fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp
* fix(ui): keep live rows within current turn
* fix(ui): keep current work above queued turns
* fix(ui): keep streamed replies above queued turns
* fix(ui): preserve reconnecting run order
* fix(ui): preserve causal terminal ordering
* fix(ui): bound replay rows to owning turns
* fix(ui): keep question summaries in owning turns
* fix(ui): scope question run ownership to session
* fix(ui): restore reconnecting chat run identity
* fix(ui): remove unused chatItemTimestamp import in chat-thread-build.ts
* fix(ui): correlate question summaries with agent runs
Co-authored-by: Peter Lee <li.xialong@xydigit.com>
* chore(i18n): refresh native source baseline
Co-authored-by: Peter Lee <li.xialong@xydigit.com>
* fix(ui): remove unused chatItemTimestamp export and split tool-stream test file
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(ui): durable session board face and dashboards index
Board face lived only in client-side boardSessionViews, capped at 50 entries,
so the preference never followed the user to another device, evicted as
sessions accumulated, and could not be seen as a set.
Persist it as SessionEntry.boardFace, which rides the existing entry_json blob
and so needs no SQLite schema change or version bump. Expose it on the session
list row and add it to the sessions.patch write-scope allowlist alongside label,
pinned, and archived: setting your own view preference is user-level chat
organization, not policy. Unknown patch fields still fail closed to
operator.admin.
Generic navigation now reads the stored face, so the sidebar and session list
open a thread on the face you left it on. boardSessionViews keeps only
activeTabId and reopenDockByTab, which are genuinely per-device.
Add /dashboards listing threads whose preferred face is dashboard. Filtering
runs server-side in filterSessionEntries before pagination, because the client
holds only a capped page and a client-side filter would silently omit
dashboards.
* test(protocol): assert the pre-rename face param is rejected
The gateway-protocol validator test still passed the pre-rename 'face' key,
which the closed schema rejects. Use boardFace, and pin the old name as a
negative case so it cannot silently return.
* chore(protocol): regenerate Swift bindings and docs map for boardFace
Adding boardFace to the sessions schema changes two committed generated
artifacts: the Swift gateway models (pnpm protocol:gen:swift) and the docs map
(pnpm docs:map:gen), which now lists the dashboards index section.
* build(deps): remove npm shrinkwrap; mirror pnpm lock into transient package locks
npm 12 removed shrinkwrap (command + tarball/root loading). Delete all 82
committed npm-shrinkwrap.json files and stop publishing lockfiles; keep
pnpm-lock.yaml as the single reviewed dependency boundary. The generator
becomes scripts/generate-npm-package-lock.mjs and feeds plugin bundling via
a transient package-lock.json + npm ci (works on npm 11 and 12). Tarball
validation treats the published 2026.7.2 beta train as a shrinkwrap
transition; self-update npm detection now uses install topology instead of
the shipped shrinkwrap.
* fix(deps): repair lint, deadcode, and test-type lanes for the npm 12 migration
- sort integrity comparisons with an explicit comparator (oxlint)
- keep resolveBunGlobalNodeModules module-local (knip unused-export gate)
- model npm pack --json as npm<=11 array / npm 12 name-keyed object
- default calver destructuring in the tarball test fixture
* feat(ui): gateway-owned sidebar section order with hover-only drag grips
* fix(ui): repair sidebar section order CI gates
* fix(protocol): keep sectionOrder optional for older gateways
Native Swift clients ship separately from gateways, so new clients must decode older gateway responses that omit sectionOrder.
* fix(ui): reconcile gateway section ordering with main
* fix(state): allow lazy tables in v5 maintenance
* refactor(ui): retire prefs session section order in favor of gateway-owned order
Supersedes #113948 by deleting the unreleased ui.prefs.sessionSectionOrder key and its browser plumbing. Gateway SQLite sidebar_sections remains the single canonical store.
* refactor(gateway): remove dead sessions.observer.ask rpc
* docs: record btw and companion contract split
* fix(gateway): unexport observer model sanitizer after ask removal