Commit Graph

824 Commits

Author SHA1 Message Date
Peter Steinberger 964c8c84c1 refactor: consolidate coercion ownership (#122299)
* refactor: consolidate coercion ownership

Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.

The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.

* fix: guard integer option ownership

Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.

* fix: keep integer helpers on numeric facade

Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.

* fix: point numeric coercion to number runtime

Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.
2026-08-11 17:14:53 -07:00
Peter Steinberger 42a4d0a9b8 fix(openai): surface failed realtime response outcomes (#121177)
* fix(talk): type realtime response outcomes

* fix(ci): align realtime outcome contracts

* test(ui): identify completed realtime responses

* chore(plugin-sdk): refresh realtime voice baselines
2026-08-11 14:14:22 -07:00
Peter Steinberger cad77fb39c refactor: consolidate remaining coercion helpers (#122020) 2026-08-11 10:22:01 -07:00
Peter Steinberger fa03d9b913 refactor: consolidate coercion helpers (#121366)
* refactor: consolidate coercion helpers

* fix: remove duplicate coercion imports

* fix: preserve serialized coercion guard

* chore: ratchet coercion helper carve-outs

* fix(test): keep gauntlet subprocess startup lean

* fix: preserve imported session timestamp semantics

* fix: preserve catalog timestamp string semantics

* chore: align plugin SDK surface ratchet

* fix: preserve trajectory and SDK string contracts

* fix(test): preserve QA record assertion semantics

* fix: complete standalone record guard rename

* refactor(cron): use canonical string coercion

* fix(acpx): preserve Pi timestamp parsing

* test(channels): adapt custody test harnesses

* test(telegram): classify media harness as test support

* test(acpx): split timestamp contract coverage

* test(channels): support generated custody contracts

* chore: ban the full coercion helper name set

Extends the declaration guard to all eleven consolidated helper names and
renames the cron schedule-identity readNumber wrapper to readScheduleInteger
so the banned generic name cannot regrow.

* fix(scripts): repair release-validation guard drift and lint cause

Restores the renamed isJsonRecord guard in assertTrustedWorkflowHarness after
main added isRecord call sites in parallel, and attaches the caught YAML error
as the thrown error cause (preserve-caught-error was red on main).

* fix: preserve Claude timestamp string semantics

* fix: preserve persisted timestamp string semantics

* fix: preserve date-first timestamp contracts

* fix(openai): harden delegation failure formatting

* chore: close coercion helper guard gaps

* test(openai): model non-error delegation rejection

* chore: refresh plugin SDK API contract

* fix(tasks): use canonical string field reader

* fix(ai): use canonical provider error field coercion

* fix(browser): migrate native bootstrap coercion

* docs(plugin-sdk): clarify text record export compatibility

* fix(gateway): normalize approval execution identity

* test(outbound): isolate message action poll harness
2026-08-11 00:02:18 -07:00
Peter Steinberger a0ad38e71a feat(docs-ci): validate docs config examples against the schema (#121336)
* feat(docs-ci): validate config examples against schema

* docs: teach canonical agent roster configuration

* docs: nest inline environment variables under vars

* docs: update canonical media model keys

* docs: remove retired config keys from examples

* fix(docs-ci): keep audit internals private

* feat(docs-ci): validate plugin-owned config examples

* fix(docs-ci): validate indented config fences

* fix(ci): route manifest changes through docs audit

* chore(docs): refresh generated config baselines
2026-08-10 07:57:56 -07:00
Peter Steinberger 620fcd0e27 refactor(plugins): make manifests own config ui hints (#121329) 2026-08-09 18:48:49 -07:00
Peter Steinberger 8616c0c374 refactor: finish shared test helper migrations (#120996)
* test: finish shared helper migrations

* test: fix helper migration CI

* style: fix test import ordering

* test(acpx): restore deferred void types

* test: fix helper migrations after rebase
2026-08-09 06:00:06 -07:00
Peter Steinberger 6192673da4 perf(doctor): delete the heavy doctor barrel and finish slimming enumeration (#120882)
* refactor(plugin-sdk): delete the heavy runtime-doctor barrel

Nothing may pull the state-db/kysely graph through a doctor barrel anymore.
The barrel's remaining heavy exports move to two narrow private-local
subpaths, each with a single purpose:

- doctor-repair-runtime: install-path diagnosis, plugin config removal, and
  state-database schema detect/repair (matrix doctor, voice-call lazy import)
- plugin-state-store-runtime: the sync keyed-store factory. It stays out of
  plugin-state-runtime because hot channel entrypoints import that at module
  load and opening a store pulls the state-database graph.

Doctor closures also stop pulling ssrf-runtime (fetch-guard + gateway net)
for two legacy private-network helpers that live in the lighter ssrf-policy
subpath: mattermost, nextcloud-talk, tlon, matrix.

The closure guard now forbids the two new heavy subpaths instead of the
deleted barrel, so the invariant keeps being enforced where it still applies.

* perf(doctor): keep heavy graphs out of every doctor closure

Doctor enumeration cold-loads each declaring plugin's contract closure, so
one heavy import in a closure is paid by the whole sweep. Four barrels were
still dragging unrelated graphs in for trivial helpers; each is repaired at
the leaf rather than by caching downstream:

- Legacy private-network config migration moves to a config leaf. It only
  reshapes records, but lived beside the SSRF runtime (DNS, proxy, logging),
  costing mattermost ~2.7s. ssrf-policy re-exports it, surface unchanged.
- Streaming config readers move to a leaf. They read two config keys, but
  streaming.ts also formats tool aggregates, pulling tool-display/logging/
  acp-core; that cost slack ~2.3s.
- signal took the channel-secret barrel for isRecord; the canonical plugin
  record guard is string-coerce-runtime (root AGENTS.md).
- llm-task took the provider-model barrel for parseModelRef, now a narrow
  model-ref-parse subpath.

Full doctor enumeration of all 42 declaring plugins, built mode:
legacy config rules 6668ms -> 1265ms, state migrations 184ms -> 127ms.
No plugin remains an outlier; the slowest is now ~380ms against a ~200ms floor.

Public export surfaces of every touched SDK subpath are byte-identical
(verified by diffing built module exports before/after); the API baseline
hashes move only because re-exported declarations emit differently.

The closure guard gains rules for each repaired barrel so the invariant
holds for future closures.

* fix(release): exclude new private-local declarations from the published package

Same pack-path rule as c41da3759f: private-local subpaths ship without d.ts.

* fix(doctor): repair the closure guard violations that break main

The landed guard fails on main: three closures import heavy barrels for one
symbol each. Two more surfaced once the guard learned about the provider-model
barrel. Each gets a narrow subpath at the leaf:

- telegram sent-message-cache + state-migrations took the session-store barrel
  (session accessor + state-db) for resolveStorePath -> session-store-paths
- discord thread-bindings.state took the channel-outbound barrel (reply
  pipeline + channel registry) for one identity write -> outbound-echo-runtime
- discord model-picker took the provider-model barrel for normalizeProviderId,
  which model-ref-parse now exposes beside parseModelRef

The guard also stops walking artifacts of plugins whose manifest declares no
doctor surface. Such a declaration gates the artifact off every enumeration
path exactly as resolvePluginDoctorContracts does, so its closure cost is never
paid; anthropic ("doctorContract": {}) was being held to a cost it cannot
incur. Absent declarations still load eagerly and stay enforced.

Side effect worth naming: discord's built doctor contract now loads again.
On main both discord and telegram fail to require in packaged builds (an
ESM-only transitive dep) and silently lose their repairs; this restores
discord and takes enumerated legacy config rules from 87 to 99. Telegram's
built artifact still pulls execa through dist chunking - a build-level defect
with a different owner, filed as follow-up.
2026-08-08 22:01:44 -07:00
Peter Steinberger 8cb53c7b55 perf(doctor): keep bundled doctor contract closures dependency-light (#120698)
* perf(doctor): keep bundled doctor contract closures dependency-light

Doctor contract enumeration cold-loads each plugin's doctor-contract-api
closure via jiti, so a static value import of openclaw/plugin-sdk/runtime-doctor
pulled the state-db/kysely graph (~4.3s per closure) into
listPluginDoctorLegacyConfigRules / listPluginDoctorStateMigrationEntries.

- migrate all light doctor-contract closures (66 files) to the
  dependency-light openclaw/plugin-sdk/runtime-doctor-migrations subpath
- voice-call: load detect/repairOpenClawStateDatabaseSchema* lazily inside
  the migration bodies; keep only a type-only static runtime-doctor import
- matrix: split pure credential record shapes/normalizers into
  credentials-state.ts so the doctor closure no longer imports the sync
  plugin-state store through credentials-read
- guard: doctor-contract-closure-guard.test.ts now forbids static value
  imports of runtime-doctor in closures alongside agent-runtime

* fix(matrix): keep credential revocation record type module-local

Knip production scan flags the export as consumer-less; the type is only
referenced by the exported union and revocation guard signature.
2026-08-08 17:51:31 -07:00
Peter Steinberger da4a656cdb improve: doctor migration checks no longer load every bundled plugin runtime (#120678)
* perf(plugins): declare doctor contract surfaces

* perf(doctor): slim migration import closures

* perf(plugins): narrow doctor declaration record surface and wire owner-test lane

Registry records carry only the doctorContract declaration instead of the whole
parsed manifest, and check:changed now selects the src/plugins-owned declaration
honesty and closure-guard tests for extension module/manifest changes so
cross-lane drift cannot pass PR classification.

* fix(doctor): keep control-plane dist imports require-safe

Keep doctor and channel control-plane chunks off exec-class dependencies, and enforce native require(esm) loading during postbuild.

* chore(plugin-sdk): regenerate API baseline

* chore(plugin-sdk): sync export ordering

* fix(plugins): satisfy doctor contract CI boundaries

* perf(doctor): make qqbot doctor closure dependency-light

qqbot was the last plugin above 5s in doctor state-migration enumeration
(~8s under tsx/jiti). The cost was not the state-key builder (already a
leaf): its doctor closure value-imported the runtime-doctor SDK barrel,
whose plugin-state-store/state-db re-exports pull kysely (~330 modules),
plus security-runtime for one fileExists (~200 modules), all resolved
per-module by jiti during enumeration.

Split the migration-define helpers and light re-exports into a new
private-local plugin-sdk/runtime-doctor-migrations subpath; runtime-doctor
re-exports it so its public surface is byte-identical (API baseline hash
unchanged). qqbot's doctor-contract and state-migrations now import only
the light subpath, swapping fileExists for the equivalent async
legacyStateFileExists already in the closure.

qqbot enumeration: ~8.0s/531 modules -> ~0.25s/18 modules.

* chore(plugin-sdk): drop private-local subpath from API baseline

runtime-doctor-migrations is private-local-only; the baseline tracks public
modules, and the earlier line was generated before the classification.

* fix(plugins): register runtime-doctor-migrations boundary paths

The private-local subpath list feeds the extension package boundary map;
the shared paths config and xai's derived overrides must carry the same
entry or the boundary contract test fails.
2026-08-08 13:29:18 -07:00
zengLingbiao 0eeb9db216 fix(voice-call): redact credential material from provider error bodies (#117304) 2026-08-08 11:51:23 +08:00
Peter Steinberger 48639663b0 chore(release): prepare 2026.8.1 (#120375) 2026-08-07 18:44:12 -07:00
Peter Steinberger 32361e749a fix(voice-call): isolate runtime generations (#120289)
Prevent retained plugin closures from recreating, adopting, or stopping successor runtimes across shutdown and restart.

Add deterministic lifecycle regressions for pending startup, exact-owner stop, retained tools, and generation restart.
2026-08-07 13:56:26 -07:00
Peter Steinberger b4a26783f7 refactor(test): consolidate duplicated requireRecord and provider HTTP mock helpers (#119982)
* refactor(test): consolidate duplicated test helpers

* test: remove stale record guard import

* fix(test): remove orphaned record guards

* refactor(test): keep record requirement messages exhaustively typed

* fix(test): keep packages/ai record guard package-local
2026-08-06 14:48:01 -07:00
Dinesh H Suthar 50c7444edf fix(sessions): preserve compatible auth profiles on model changes (#117550)
* fix(model-picker): preserve compatible auth profiles
* chore(plugin-sdk): refresh API baseline
* fix(model-picker): keep profile policy core-owned
* fix(model-picker): preserve profiles across auth aliases
* chore(plugin-sdk): update public surface budgets
* fix(model-picker): honor explicit profile clearing
* fix: preserve compatible auth profiles on model changes
* perf: reuse prepared auth profile metadata
* docs(plugin-sdk): document direct model persistence fallback
* test: expose auth snapshot in directive mock

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Dinesh Suthar <dineshsld20@gmail.com>
2026-08-05 07:40:00 +05:30
Peter Steinberger 03bec9d438 fix(voice): make signed callback replay reservations durable and retryable (#118754) 2026-08-03 10:35:32 -07:00
Peter Steinberger eb76bf499b fix(voice-call): terminate carrier calls after realtime startup failures (#118699) 2026-08-03 07:38:42 -07:00
Peter Steinberger deb682abfe refactor(plugins): consolidate extension runtime helpers (#118509)
* refactor(plugins): consolidate extension runtime helpers

* fix(ci): satisfy extension type and lint checks

* chore(plugin-sdk): regenerate API baseline for #118509
2026-08-03 02:56:43 -07:00
Peter Steinberger ae4a95faad fix(voice-call): stop superseded realtime consult work (#118301)
* fix(voice-call): abort superseded realtime consults

* test(voice-call): use error abort rejections

* chore: defer voice-call release note

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-02 17:19:01 -07:00
Vincent Koc b65d010408 fix(voice-call): avoid retaining replaced bridges 2026-08-02 18:44:26 +08:00
Vincent Koc b738c6e2d9 fix(voice-call): preserve predecessor on provisional close 2026-08-02 18:32:38 +08:00
Vincent Koc 67dc58cb62 test(voice-call): cover provisional replacement close 2026-08-02 18:32:37 +08:00
Vincent Koc f478b906f6 fix(voice-call): make transcript adoption transactional 2026-08-02 07:42:55 +08:00
Vincent Koc 058812a466 fix(voice-call): isolate replacement transcript state 2026-08-02 07:42:55 +08:00
Vincent Koc 570eddd29b test(voice-call): preserve transcript fragment spacing 2026-08-02 07:42:55 +08:00
Vincent Koc dd7d31743f test(voice-call): cover replacement transcript ownership 2026-08-02 07:42:54 +08:00
Vincent Koc 2f06ed30d8 test(ci): stabilize plugin prerelease async waits (#117684)
* test(voice-call): await replaced bridge cleanup

* test(mistral): await runaway transcript error
2026-08-02 07:31:34 +08:00
Vincent Koc 980550ffcb test(voice-call): use provider audio callback 2026-08-02 02:32:20 +08:00
Vincent Koc ab3109a598 fix(voice-call): close stale realtime sockets 2026-08-02 01:33:40 +08:00
Vincent Koc e745f53014 fix(voice-call): isolate replaced realtime bridges 2026-08-02 01:23:30 +08:00
Vincent Koc e1cc00f9b6 fix(voice-call): guard continuity reset ownership 2026-08-02 01:10:36 +08:00
Vincent Koc 4f2429a817 merge: refresh realtime continuity onto main
* origin/main: (41 commits)
  fix(plugins): compare authoring metadata by canonical JSON semantics (#117486)
  fix(doctor): reject contradictory lint check selectors (#117495)
  fix(anthropic): honor configured model pricing (#117275)
  refactor(plugins): reuse scoped loader for capability discovery (#117373)
  refactor(test): derive changed tooling routes (#117407)
  fix(kova): clarify extension memory attribution (#117500)
  fix(imessage): sanitize private context on every outbound path (#117501)
  fix(ci): align release validation fixtures (#117494)
  fix(talk): preserve owner authorization in realtime consults (#114163)
  fix(ui): surface aborted-run diagnostics (#117497)
  perf(models): skip Ollama row runtime loading (#117465)
  fix(cli): report user profile command outcomes (#117466)
  fix(active-memory): detect Chinese recall intent in escalate mode (#117338) (#117419)
  fix(workboard): ignore caller-supplied archivedAt when creating a card (#116412)
  fix(models): avoid waiting on promotions before listing models (#117322)
  refactor(plugins): inherit shared package boundary settings (#117474)
  fix(systemd): parse all inline environment assignments (#117484)
  feat(web-fetch): add tools.web.fetch.headers for operator request headers (#115545)
  fix(qa): Slack progress lane misses successful delivery (#117391)
  refactor: deduplicate Codex prompt snapshot fixtures (#117476)
  ...
2026-08-02 01:00:52 +08:00
Peter Steinberger 568ea29d2e refactor(plugins): inherit shared package boundary settings (#117474) 2026-08-01 09:11:09 -07:00
Vincent Koc f8609ce1a5 fix(voice-call): reset fresh-session turn state 2026-08-01 23:08:58 +08:00
Vincent Koc 02c8e76d7f fix(voice-call): keep replay caps production-owned 2026-08-01 22:12:12 +08:00
Vincent Koc c90983d59d test(voice-call): share replay cap constants 2026-08-01 22:07:05 +08:00
Vincent Koc 0d29bd929e test(voice-call): assert replay collection bounds 2026-08-01 21:46:46 +08:00
Vincent Koc f93f71bde4 test(voice-call): cover replay ownership bounds 2026-08-01 21:37:16 +08:00
Vincent Koc fd65405485 fix(voice-call): bound manager replay ownership 2026-08-01 21:37:13 +08:00
Dallin Romney 8b1a9ccaa4 fix(voice-call): preserve tool invocation context (#116856)
* fix(voice-call): preserve tool invocation context

* fix(voice-call): trust requester tool context

* style(voice-call): format invocation context test
2026-08-01 13:23:24 +08:00
Vincent Koc 1b3572d08b Merge pull request #117201 from openclaw/fix/voice-call-provider-state-cleanup
fix(voice-call): release terminal provider state
2026-08-01 12:36:02 +08:00
xingzhou 8f8b23ff2c fix(voice-call): reject malformed UTF-8 provider JSON (#114267) 2026-07-31 21:13:42 -07:00
Vincent Koc 6c886107c3 merge(main): refresh voice call provider state cleanup
* commit '441d6ab254df14fb6939a8a261f474904ff9c500': (388 commits)
  fix(qqbot): ignore blank app id fallbacks (#109460)
  fix(feishu): consume implicit reply targets across media delivery (#117196)
  fix(exec): preserve approved command output when sessions resume (#117177)
  fix(qa): use public subagent fanout evidence (#116832)
  fix(googlechat): cancel unread auth response bodies before release (#115873)
  fix(queue): prevent cron saturation from starving hook dispatch (#116666)
  fix(gateway): sessions.steer retry no longer interrupts an active run when replaying a cached idempotency key (#116969)
  fix(irc): config validation rejects documented channels.irc.configWrites key (#112392)
  fix(mistral): keep terminal error branch lint-clean
  fix(onboard): stop a full reset from resetting the default workspace when the config is unreadable (#114110)
  refactor(i18n): remove unused Apple contradiction report (#117182)
  fix(google): stop scraping Gemini CLI OAuth credentials (#117167)
  perf: count large histories before Gateway prewarm (#117118)
  fix(signal): restore provider-safe original attachment filenames (#115107)
  refactor(channels): unify setup ownership across bundled channels (#117188)
  fix: allow gateway service commands for named profiles (#116314)
  fix(plugins): invalidate bundled artifact locations after metadata refresh (#117041)
  fix(ollama): honor model requests and pull completion contracts (#117171)
  fix(agents): prevent fallback after stale lifecycle abort (#117168)
  fix(telegram): confirm polling before long poll (#116970)
  ...
2026-08-01 12:03:58 +08:00
Vincent Koc deac0559c7 test(voice-call): cover Twilio hangup retries 2026-07-31 18:10:13 +08:00
Vincent Koc c3b378401c fix(voice-call): preserve Twilio hangup retry state 2026-07-31 18:10:12 +08:00
Vincent Koc 1067083b3c test(voice-call): stress paced audio queue drains 2026-07-31 18:08:24 +08:00
Vincent Koc 8beca170ea fix(voice-call): avoid shifting paced audio queues 2026-07-31 18:08:23 +08:00
Vincent Koc cab3245d87 test(voice-call): cover Plivo cleanup retry paths 2026-07-31 18:08:14 +08:00
Vincent Koc 8b95c2c88d fix(voice-call): preserve Plivo hangup retry state 2026-07-31 18:08:11 +08:00
Vincent Koc 00a587fcce test(voice-call): cover terminal webhook provider cleanup 2026-07-31 18:04:47 +08:00