Commit Graph

455 Commits

Author SHA1 Message Date
Peter Steinberger 5760fcdae1 fix(ci): record 2026-08-15 Control UI startup JS growth in the budget baseline
Tonight's UI fix stream (stale-tab retry, session attention, talk
backpressure) consumed the 1 KiB tolerance and broke build-artifacts plus
both QA smoke ui:build paths on main (run 31861213699, 333309 B vs
332040+1024). Recorded with CI bytes per the checker contract; the 350 KiB
maintainer-approved ceiling still bounds cumulative creep.
2026-08-14 20:19:16 -07:00
Peter Steinberger 98a8e0d63f fix(macos): prevent mismatched CUA driver endpoints (#123845)
* fix(macos): make CUA driver endpoint handoff atomic

* ci: record approved CUA env budget increase

* test: satisfy changed-gate hygiene

* style(macos): use failable endpoint string conversion

* fix(macos): strip retired CUA worker environment

* ci: constrain CUA env budget approval

* test(macos): isolate inherited CUA environment
2026-08-14 16:04:43 -07:00
Vyctor H. Brzezowski 3f006ba0fc fix(ui): complete mobile pairing after code redemption (#120933)
* fix(ui): complete pairing setup lifecycle

Redeemed and expired mobile setup codes stayed on screen as usable QR
codes, so a successful pairing had no visible outcome and expired bearer
material still looked live.

The Gateway now mints an opaque, non-authorizing setupId beside each
setup credential, returns its authoritative expiresAtMs, records the
terminal outcome of the exact redemption, and broadcasts
device.pair.setup.completed. Because that broadcast is dropped for
buffered operator sockets, the completion is persisted first and can be
reconciled through the new device.pair.setupStatus method: the Control UI
asks for the recorded outcome before it may present a credential as
expired, so a pairing that succeeds is never shown as a failure.

The Control UI models one closed lifecycle (selection, loading, waiting,
success, expired, error) correlated only by the active setupId, and
Pairing help now carries the external-link affordance.

* fix(ui): preserve unknown pairing outcomes

* test(ui): target pairing terminal headings

* test(ui): align pairing completion fixture

* fix(gateway-protocol): decode setup-code results from older gateways

Older protocol-v4 gateways omit the new setupId and expiresAtMs
lifecycle fields, so requiring them in the generated native model broke
decoding an existing device.pair.setupCode response. Keep both optional
at the wire boundary, require lifecycle metadata before the Control UI
enters its waiting state so a missing outcome stays visible, and cover
the legacy payload with Swift and schema regressions.

* fix(ui): surface rejected pairing dialog loads

The lazy pairing chunk could reject while its overlay was already open,
leaving the shell rendering nothing at all. Record the rejection on the
shell and render a recoverable modal with a reason and a retry so the
open action always ends in a visible outcome.

* fix(state): preserve pairing setup schema compatibility

* test(gateway): cover pairing setup release train

* fix(gateway): commit pairing setup completion atomically

* refactor(state): distinguish setup transaction helpers

* refactor(state): remove obsolete bootstrap restore path

* fix(gateway): preserve setup handoff type safety

* fix(gateway): keep pairing completion terminal after consume

* fix(gateway): validate Watch binding during setup commit

* fix(gateway): revalidate setup credential expiry at commit

* chore: refresh Plugin SDK API contracts after rebase

* fix(pairing): prune expired setup completions

* chore: retrigger CI

* fix(protocol): deduplicate setup expiry field

* fix(protocol): refresh pairing setup clients

* fix(gateway): make pairing setup completion durable

* fix(ui): retire expired pairing credentials immediately

* fix(ui): keep pairing dialog visible while loading

* fix(macos): align setup result initializer order

* fix(gateway): restore generic bootstrap retries

* chore(ui): record pairing startup budget

* chore(ui): refresh pairing startup budget

* style(gateway): format maintenance imports

* test(gateway): cover session-sharing mock

* fix(state): defer setup correlation schema

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-14 11:10:30 -07:00
Peter Steinberger 7fb47729c3 test: trim failover classifier duplicates (#123753)
* test: trim failover classifier duplicates

* test: prune failover max-lines baseline
2026-08-14 11:05:06 -07:00
Peter Steinberger 8c7e86a2ea fix(backup): reject unrestorable symlinks during create (#123672) 2026-08-14 06:55:48 -07:00
Peter Steinberger 946e49cb80 fix(ui): renaming a config map key that holds a stored secret dead-ends the draft or binds the wrong credential (#123571)
* fix(ui): block renaming config map keys that still hold redacted secrets

Renaming a map entry whose value is the server redaction sentinel moves
the sentinel to a new key. The gateway's exact-key restore then fails
closed forever (dead-end draft with a Retry that can never succeed), and
when the rename is folded with a delete of the target key inside one
autosave window, the restore silently binds the deleted entry's old
credential under the new name and drops the intended one — a green
Saved with the wrong secret.

The rename handler is the only owner that knows a sentinel was moved
rather than typed, so it now rejects the rename like the existing
duplicate-key guard and explains the retype path via input validity.
Plain values rename exactly as before.

* chore(ui): record startup JS growth for the redacted-rename guard string

The renameRedactedBlocked validity message in the startup en locale adds
65 gzip bytes over the recorded baseline; record the CI-measured size
per the established baseline pattern.
2026-08-14 06:34:24 -07:00
Josh Lehman f49eaf8639 fix(ci): prevent type-aware lint timeouts on constrained runners (#123328)
* oc-073.1: target UI style lint in changed checks

* oc-073.2: reuse tsgolint programs on hosted CI

* fix(ci): repair lint scope validation

* oc-073.3: restore no-target core lint fallback
2026-08-14 05:43:54 -07:00
Peter Steinberger ad400d810b fix(ci): record startup JS growth in the Control UI budget baseline
CI build-artifacts now measures 330521 B startup JS gzip, 14 B past
baseline+tolerance (329483+1024) after today's Control UI fixes. Every
PR building artifacts fails the budget check until the baseline records
the measured bytes; max committed baseline (358400 B) still bounds growth.
2026-08-14 05:10:12 -07:00
Peter Steinberger 860aeed8f6 feat(gateway): transfer node worker workspaces (#123280)
* feat(gateway): transfer node worker workspaces

* fix(gateway): harden node workspace transfer

* fix(gateway): isolate transfer HTTP contract

* fix(gateway): trim transfer HTTP exports
2026-08-13 21:00:44 -07:00
Peter Steinberger 438d035885 feat(gateway): launch workers on paired nodes (#123157)
* feat(gateway): launch workers on paired nodes

* docs(plan): track node worker launch wire

* fix(runners): restore node workspace ownership

Rehydrate durable workspace bindings after Gateway restart, fence timed-out node tunnel starts, and refuse incomplete clone fallback for submodule and Git LFS workspaces.

* test(runners): isolate node launch fixtures
2026-08-13 18:02:18 -07:00
Peter Steinberger 1348387076 refactor(plugins): replace node-llama-cpp with managed llama-server (#123105)
Move llama.cpp chat and local embeddings onto a verified externally managed llama-server runtime. Remove the in-process native runtime, forked embedding workers, and node-llama-cpp dependency while preserving guided setup, local GGUF models, tool-capable agent runs, diagnostics, and operator docs.
2026-08-13 16:58:20 -07:00
joshavant 1cb9f70cb3 fix(gateway): isolate full model catalog discovery 2026-08-13 18:57:50 -05:00
Peter Steinberger 12ada43464 refactor(ui): resolve duplicate stylesheet selectors and restore no-duplicate-selectors (#123166)
* refactor(ui): resolve duplicate stylesheet selectors and restore no-duplicate-selectors

* refactor(ui): merge duplicate .kbd block in file-preview modal instead of config carve-out
2026-08-13 12:50:18 -07:00
Peter Steinberger f2f3ba2eaf refactor(ui): consolidate responsive breakpoints onto a canonical ladder (#123160)
Use the 400, 560, 640, 768, 900, 1100, and 1320px max-width ladder. Round noncanonical thresholds up to the next rung so compact layouts engage before desktop layouts become cramped.

Move the 1180px agent-tool summary breakpoint to 1320px because the persistent desktop rail leaves about a 1020px content column at that viewport; 1100px would coincide with the rail disappearing and the content expanding.

Stylelint now enforces the ladder and the existing compound-query exceptions.
2026-08-13 12:34:50 -07:00
Peter Steinberger 843017073c refactor(ui): route stylesheet colors through the token layer and gate hex literals (#123156)
Add semantic, presentation, brand, and shared highlight tokens in base.css.
Remove dead fallbacks and consolidate dark/light syntax colors behind tokens.
Enforce color-no-hex for CSS while exempting token definitions and sprite artwork.
2026-08-13 05:36:52 -07:00
Peter Steinberger 3b6e54041f ci: replace dependency sticky disk with exact cache (#123040)
Amp-Thread-ID: https://ampcode.com/threads/T-019ff3db-c467-70ad-8ed3-81f2ba94b0c0

Co-authored-by: Amp <amp@ampcode.com>
2026-08-13 01:13:25 -07:00
Peter Steinberger 10a1a43f4b fix(zalo): keep packaged setup wizard loadable (#122902)
* fix(zalo): package setup runtime surface

* fix(tooling): track setup surface artifacts
2026-08-12 18:49:41 -07:00
Peter Steinberger add6b20bd2 fix(ci): record startup JS growth in the Control UI budget baseline
Startup JS gzip reached 329483 B on main (build-artifacts, af49764206),
1198 B over the 328285 B baseline + 1024 B tolerance, after cumulative
chat/session UI growth landed in #122296, #122713, #122870, and #122876.
Record the CI-measured bytes (within the 4096 B ratchet) to restore green
build-artifacts and QA Smoke lanes.
2026-08-12 18:03:39 -07:00
Peter Steinberger f3f203f31d refactor(agents): split subagent-control.ts into owner modules (#122875) 2026-08-12 17:23:39 -07:00
Peter Steinberger ae6f813e73 refactor(agents): split subagent announce delivery (#122853)
* refactor(agents): split subagent announce delivery

* fix(agents): defer announce runtime dependency reads
2026-08-12 16:23:34 -07:00
Peter Steinberger d003e08756 refactor(plugin-sdk): remove final test-only facades (#122844) 2026-08-12 15:28:22 -07:00
Peter Steinberger 307021eca4 refactor(agents): split subagent-registry-run-manager.ts into owner modules (#122826) 2026-08-12 14:54:10 -07:00
Peter Steinberger 5fda9d09f0 feat(deploy): add experimental Cloudflare deployment template (#122768)
* feat(deploy): add experimental Cloudflare template

* fix(deploy): keep container SSH debug access opt-in

* fix(deploy): satisfy scripts tsgo lane and model wrangler entrypoint in knip

* fix(deploy): model wrangler-consumed exports and isolated dependency in knip

The Worker default export and Durable Object class are instantiated by
wrangler from wrangler.jsonc, and @cloudflare/containers lives in the
template's isolated package.json — modeled per the deadcode checks' own
guidance rather than root-manifest changes.

* docs(deploy): align SSH bootstrap flow with the disabled-by-default policy
2026-08-12 14:07:48 -07:00
Peter Steinberger 79380000e0 refactor(plugin-sdk): remove test-only facades (#122807) 2026-08-12 13:57:07 -07:00
Peter Steinberger c23d66e3b5 refactor: consolidate coercion ownership (#122692)
* refactor: consolidate coercion ownership

* test: align shard check with weighted planning

* chore: refresh plugin SDK API baseline
2026-08-12 09:25:28 -07:00
Peter Steinberger 8060ef8937 refactor(gateway): split Control UI auth test coverage (#122660)
* test(gateway): split control UI auth suite

* test(gateway): consolidate control UI auth fixtures

* test(gateway): clean up split auth fixtures
2026-08-12 08:32:06 -07:00
Peter Steinberger 7e42dae611 refactor(memory-core): split index manager along the inheritance chain (#122540)
* refactor(memory-core): split index manager along the inheritance chain

* fix(memory): restore the manager lazy boundary

* refactor(memory-core): delete dead manager plumbing

* chore(lint): ratchet max-lines baseline after memory manager split

* fix(memory): keep the manager out of the runtime facade

* test(memory): cover transitive manager facade imports
2026-08-12 02:28:20 -07:00
Peter Steinberger 31aa7c7c75 refactor(agents): split cli-runner into concept modules (#122442)
* refactor(agents): split CLI runner concepts

* chore(lint): ratchet cli-runner max-lines baseline

* refactor(agents): remove stale runner import

* refactor(agents): preserve cleanup error typing

* refactor(agents): disambiguate CLI backend predicate

* test(agents): align code-mode pending boundary

Fixes red main: both host calls are unsettled when the guest snapshot is first parked; later waits still prove that settled calls are filtered.

* test(agents): tolerate code-mode settlement race

Fixes red main: the fast host call may settle as the guest snapshot is parked, while the deliberately slow call must remain pending.
2026-08-12 01:20:27 -07:00
Peter Steinberger 90beb639e7 refactor(discord): split voice lifecycle ownership (#122479)
* refactor(discord): split voice subsystem by lifecycle owner

* fix(discord): make one generation the voice lifecycle authority

* refactor(discord): delete superseded voice plumbing

* test(discord): split voice coverage by lifecycle owner

* chore(lint): ratchet max-lines baseline after voice split

* fix(discord): re-read voice lifecycle after realtime connect

* test(discord): move wake follow-up coverage to turns owner

* refactor(discord): keep realtime lifecycle state private

* refactor(discord): keep voice test harness type private

* refactor(discord): remove split voice test accessors

* test(discord): type split voice fixtures at owners

* test(discord): trim split voice test imports
2026-08-11 23:23:26 -07:00
Peter Steinberger dac940bf3a refactor(openai): split realtime voice by layer (#122414)
* refactor(openai): split realtime voice by layer

* refactor(openai): delete dead realtime auth branches

* chore(lint): ratchet max-lines baseline after realtime-voice split

* style(openai): prune split leftovers
2026-08-11 22:06:53 -07:00
Peter Steinberger f6459a3255 refactor(ui): split chat thread into transcript owners (#122420)
* refactor(ui): split chat thread into transcript owners

* refactor(ui): delete orphaned pinned-messages surface

* chore(lint): ratchet max-lines baseline after chat-thread split

* fix(ui): tighten transcript owner type boundaries

* refactor(ui): prune pinned-message orphans
2026-08-11 21:49:47 -07:00
Peter Steinberger cb52ded58d refactor(telegram): split native commands by executor (#122419)
* refactor(telegram): split native commands by executor

* refactor(telegram): deduplicate DM-thread target session

* chore(lint): ratchet max-lines baseline after telegram commands split

* test(telegram): fix native command split checks
2026-08-11 21:45:17 -07:00
Peter Steinberger 722e20b675 test(agents): prune final Responses duplicates (#122424)
* test(agents): prune final Responses duplicates

* fix(tooling): honor inclusive compat removal dates
2026-08-11 21:22:42 -07:00
Peter Steinberger 6b0be0215f refactor(ui): split new-session page into draft owners (#122413)
* refactor(ui): split new-session page into draft owners

* refactor(ui): delete duplicated draft plumbing

* chore(lint): ratchet max-lines baseline after new-session split
2026-08-11 21:15:32 -07:00
Peter Steinberger 22b3c2530f refactor: split agent and chat orchestration ownership (#122318)
* refactor(agents): split subscription controllers

* refactor(gateway): split chat send dispatch

* style(gateway): format chat send handler
2026-08-11 17:33:20 -07:00
Sliverp 84c7d45f15 refactor(qqbot): install plugin from Tencent package (#107295)
* refactor(qqbot): remove bundled extension source

Mechanical deletion half of the #107295 squashed rebase; the catalog
repoint and host integration land in the follow-up commit.

Co-authored-by: sliverp <870080352@qq.com>

* refactor(qqbot): install plugin from Tencent package

Squashed rebase of #107295 onto current main. Repoints the official
external channel catalog at @tencent-connect/openclaw-qqbot@2.0.1 and
adapts onboarding, doctor migrations, secrets, build guards, and tests.

Documents the known limitation that the external package does not
support structured SecretRef clientSecret values; operators move those
to QQBOT_CLIENT_SECRET or clientSecretFile before upgrading.

Co-authored-by: sliverp <870080352@qq.com>

* fix(doctor): reuse shared hasOwnKey record helper

The rebased QQBot migration carried its own hasOwnKey export, colliding
with the one main now ships in legacy-config-record-shared.ts.

Co-authored-by: sliverp <870080352@qq.com>

* fix(plugins): carry catalog integrity through the update bridge

The externalized-bundled-plugin bridge dropped the official catalog's
expectedIntegrity pin, so bundled-user updates installed the external
npm package without integrity verification. The bridge now carries the
pin for the catalog's exact npm spec and both bridge install calls pass
it through; update-channel spec overrides intentionally skip the pin
since it only covers the pinned version.

Co-authored-by: sliverp <870080352@qq.com>

* chore(plugin-sdk): refresh per-entrypoint API baselines

The QQBot compat export and bundled-type removal shift 26 entrypoint
closure hashes in the new split baseline layout.

Co-authored-by: sliverp <870080352@qq.com>

* refactor(qqbot): drop helper reintroduced during rebase

Main's coercion consolidation added this file after the deletion
commit's base; its only consumers were the removed qqbot sources.

Co-authored-by: sliverp <870080352@qq.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-11 15:10:27 -07:00
Peter Steinberger 87b3c0e5df refactor(agents): split subscribe leaf ownership (#122249)
* refactor(agents): split embedded tool result ownership

* refactor(agents): split embedded message ownership
2026-08-11 15:04:07 -07:00
Peter Steinberger a40df57bae refactor(agent-runner): split run policy ownership (#122209)
* refactor(agent-runner): split tool-call normalization ownership

* refactor(agent-runner): split incomplete-turn ownership

* test(agent-runner): hide incomplete-turn test helper

* test(ci): route split incomplete-turn tests

* test(ci): enumerate split incomplete-turn tests

* test(vitest): route split incomplete-turn tests to their serial shard
2026-08-11 13:06:29 -07:00
Ayaan Zaidi 746a188c90 refactor(media): collapse attachment byte classification into media-core (#122168)
Attachment MIME gating and extraction dispatch used nine separate byte policies across five files; the allowlist could approve one MIME while dispatch observed another after a second sniff. @openclaw/media-core/attachment-classify now owns byte sniffing, text heuristics, extension mapping, and the seven attachment classes; the cache stores one classification that gates and dispatch share. Channel-declared MIME leads with the transport Content-Type as a byte-arbitrated hint, normalizeMimeType folds YAML/XML synonyms so existing configured allowlists keep matching, and input_file API callers keep declared-MIME precedence over cosmetic filenames. Net -135 production LOC.

Proof: 2,153 focused tests across media-core/media-understanding/media plus boundary-contract and deadcode-mirror suites; ClawSweeper local review clean (round 5, zero findings); live Telegram default-turn probe green.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-11 19:10:49 +00:00
Peter Steinberger 2d6a5d7356 refactor(gateway): split worker environment service by ownership (#122138)
* refactor(gateway): split worker environment service by ownership

* refactor(gateway): derive environment intent at the contract owner

* chore(lint): ratchet max-lines baseline after worker-service split

* style(gateway): prune unused symbols after worker-service split

* refactor(gateway): narrow worker-service seam exports

* chore(plugin-sdk): refresh API baseline
2026-08-11 11:48:28 -07:00
Peter Steinberger 5c81ed5883 refactor(ui): split runtime config into layered modules (#122117)
* refactor(ui): split runtime config into layered modules

* refactor(ui): delete redundant config wrappers

* chore(lint): ratchet max-lines baseline after ui config split
2026-08-11 10:17:00 -07:00
Peter Steinberger cc9119e22a refactor(agent-runner): split run leaf ownership (#122148)
* refactor(agent-runner): split payload warning ownership

* refactor(agent-runner): split model diagnostic ownership
2026-08-11 10:08:21 -07:00
Vyctor H. Brzezowski e7ba2e1f6b fix(ui): give the Gateway update a visible, truthful outcome (#121686)
* fix(ui): give the Gateway update a visible, truthful outcome

Confirming an update in the Control UI could end in nothing the operator
could see. The sidebar card only knew `updateRunning`, which clears as soon
as `update.run` answers, so a dev-channel handoff — git pull, install, full
build, restart — spent minutes back on the stale "N commits behind" call to
action. A verified install then published a null banner, so success was
never announced at all, and the reload that a verified install triggers
would have destroyed any in-memory notice anyway.

The lifecycle was already recorded; nothing rendered it. Feed the sidebar
the reconciliation fact the settings page already uses, narrate the wait in
the shell callout that survives the restart, and record the verified result
so it outlives the reload it causes.

Failures now name their cause. The updater already stores the failing step
and its captured output in the restart sentinel and `update.status` returns
it whole, so a disk-full install reads "The update failed at install:
ENOSPC: no space left on device" instead of a reason slug plus "see the
gateway logs". Missing handoff-reason guidance is filled in, and the
duplicate post-restart banner resolver is folded into the shared one.

Also fixes a callout clipped by the fixed shell chrome controls, and the
"Available 246 commits behind" double framing in the confirmation.

* fix(ui): report the Gateway update in the dialog that starts it

Follow-up to the first pass: the shell-top callout was the wrong surface for
this. The dialog the operator clicked is now the one that reports the whole
update, and the ambient surfaces are the fallback for anyone who leaves it.

Confirming no longer closes the dialog. It becomes stateful — the danger
button turns into a disabled "Updating…" with a spinner, and the body
narrates the phases in place: installing, then "The Gateway is restarting.
This page disconnects and reconnects on its own." The dialog is mounted on
document.body, outside the shell, so losing the connection cannot unmount
the only surface still reporting. A request the Gateway never accepts stops
spinning after a bounded grace and says so.

A failure lands in the dialog with its recorded cause and next step. Success
still arrives after the reload a verified install triggers, so it stays a
toast — no dialog exists by then.

The shell-top status callout is gone. The same outcome now renders beside
the sidebar update card that started the update, and stays hidden while the
dialog owns the report so the two surfaces never duplicate each other.

Splits the wire-payload readers out of update-overlay-helpers into
update-schedule-dto and moves update.run answer classification next to them,
keeping both owners under the file-size budget.

* fix(ui): keep the update dialog open through the install in E2E and use a defined warn token

* refactor(ui): wire the update progress stream into the floating card and drop unused video capture

* fix(ui): report the current update, not the previous failure

The dialog subscribed to progress before starting the update. Producers
replay their current snapshot synchronously on subscribe, so a retry
still carrying the previous attempt's failure banner painted that old
error as this update's outcome.

Start the request first, and treat a failure present on the subscribe
emit as the previous attempt's: an accepted run clears the banner before
its first await, so a failure that survives means the request was
refused, which the accept timer already reports truthfully.

* fix(ui): keep update helpers internal

* chore(perf): raise startup-JS budget to 350 KiB

Approved by maintainer Vyctor on 2026-08-11.

Trigger: after #121734, main measured 326650 B—6 B below the prior 319 KiB hard ceiling. Current main subsequently moved the ceiling to 320 KiB; this records the authorized final 350 KiB decision for #121686.

* fix(ui): announce update success without session storage

Show the verified install identity directly when the current document does not reload, so denied session storage cannot suppress the operator-visible outcome.

* test(ui): isolate update toast in overlay tests

The Node-only overlay suite now reaches the direct non-reload success toast. Mock the DOM-owned toast boundary so reconciliation assertions can complete without a browser document.
2026-08-11 13:49:12 -03:00
Peter Steinberger fe4cff7a6b refactor(ai): split completions transport into concept modules (#122122)
* refactor(ai): split completions transport into concept modules

* refactor(ai): delete duplicated transport helpers

* chore(lint): ratchet max-lines baseline after transport split

* test(scripts): update prefix expansion expectation
2026-08-11 09:47:52 -07:00
Vincent Koc 8d3f3377da fix(ci): make Control UI artifact validation consistent (#122086) 2026-08-12 00:11:22 +08:00
Peter Steinberger 1ccd701808 chore(deadcode): remove stale Knip scaffolding (#122069) 2026-08-11 08:15:11 -07:00
Ayaan Zaidi d699ed0198 fix(ui): record chat-header startup JS growth in the budget baseline
#121734 landed 982 B of startup JS, leaving merge-ref builds 1 B over the
baseline ceiling; every open PR's build-artifacts job fails inherited red.
CI-measured bytes per the updater contract.
2026-08-11 15:08:53 +02:00
Peter Steinberger 8327504c84 refactor(agents): split systemd into concept modules (#122002) 2026-08-11 04:09:49 -07:00
Peter Steinberger bef753b278 refactor(agents): split reply-run registry into concept modules (#121995) 2026-08-11 03:38:54 -07:00
Peter Steinberger 226c699a23 feat(ai): add provider video input contract (#121887)
* feat(llm): add user video input contract

* fix(ai): preserve structured tool results

* refactor(ai): isolate provider video input types

* style(ai): format provider transform imports

* chore(ai): register provider type entrypoint
2026-08-11 03:08:27 -07:00