Commit Graph

595 Commits

Author SHA1 Message Date
Samuel Judson 24a1139188 fix: move raw call transcripts from system to user prompt to protect provenance (#123846)
* Move raw transcript from system to user prompt to protect provenance.

* Type fix.

* fix(voice-call): harden transcript context handling

* fix(voice-call): initialize inbound Twilio control state

* test(voice-call): align runtime coordinator fixture

---------

Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-08-19 13:07:59 -07:00
Peter Steinberger 3378e07d50 refactor(plugin-sdk): promote shared runtime primitives (#126193)
* refactor(plugin-sdk): promote shared runtime primitives

* test(codex): keep one attempt tools owner
2026-08-19 01:10:18 -07:00
Peter Steinberger 3eecab1bee refactor(plugins): adopt shared retry runtime (#126065) 2026-08-18 17:46:38 -07:00
Josh Avant 72783bcdc2 fix(voice-call): preserve caller ownership context (#125953) 2026-08-18 12:10:13 -07:00
Peter Steinberger 5e3e52431e fix(voice-call): preserve carrier-confirmed termination state (#125717)
* fix(voice-call): serialize realtime termination

* fix(ui): trim debug overlay startup path
2026-08-18 02:17:11 -07:00
Peter Steinberger 6cc40431d1 fix(voice): prevent choppy audio in realtime calls (#125620)
* fix(voice-call): pace realtime audio from stream clock

* fix(voice): preserve resampler state across audio chunks

* fix(voice-call): honor telephony TTS audio formats

* fix(voice-call): await acknowledged stream playback

* fix(voice): bound realtime input audio backlog

* chore(voice-call): shrink assertion baseline and localize tts format error

* test(voice-call): split playback-mark coverage into its own suite

* test(voice-call): drop helper left unused by suite split

* test(openai): scope queued audio copy assertion

* fix(openai): flush realtime resampler at response end

* fix(voice-call): reject containerized mulaw TTS
2026-08-18 00:07:01 -07:00
Peter Steinberger b7ccf62fbd fix(voice-call): keep Funnel off occupied HTTPS ports (#125552)
* fix(voice-call): support alternate Tailscale HTTPS ports

* refactor(voice-call): keep Tailscale DNS lookup private

* fix(voice-call): preserve config normalization contract
2026-08-17 21:04:17 -07:00
Peter Steinberger 1acabe40a9 feat(voice-call): let realtime agents end calls (#125525) 2026-08-17 20:39:13 -07:00
Peter Steinberger 75fcaba919 fix(voice-call): survive gateway in-process restart and stop CLI dead-ends (#125458)
* fix(voice-call): survive gateway in-process restart and stop CLI dead-ends

The gateway's in-process restart (SIGUSR1 config reload) reuses the cached
plugin registry, so service stop/start run on the same retained voice-call
registration. Generation fencing from #120289 treated that restart as a stale
actor: stop retired the generation forever, the next start silently bailed,
and every voicecall.* RPC answered UNAVAILABLE "runtime generation is
retired" while the webhook never rebound.

- Registrations now hold a replaceable generation: service start after stop
  mints a fresh generation, takes over a running slot owned by a retired
  predecessor, and reports start failures to service health instead of
  silently returning.
- The voicecall CLI classifies gateway failures with typed guards instead of
  message substrings: standalone/store fallback only when the gateway is
  genuinely absent; reachable-but-failed (request errors, auth, timeout)
  exits with actionable text; a standalone webhook port collision explains
  that a running Gateway probably owns the port instead of raw EADDRINUSE.
- Plugin SDK gateway-runtime exports structural isGatewayTransportError /
  isGatewayClientRequestError guards (+2 documented surface budget).
- Regression coverage: same-registration stop/start restart, retired-owner
  takeover, typed CLI fallback classification, and a real token-auth gateway
  server routing voicecall.status through callGatewayFromCli.

* refactor(voice-call): split CLI modules and dedupe gateway fallbacks

Collapse the four duplicated gateway-or-runtime command blocks (speak, dtmf,
end, continue fallback) into one generic runGatewayManagerCommand helper —
the continue command owns its legacy-method fallback and operation polling
via a gatewayCall closure, so the helper carries no per-command policy.
Smoke reuses the shared initiateVoiceCall path instead of a bespoke
fallback.

Split the 988-line cli.ts into concept modules (cli-gateway-call,
cli-call-log, cli-command-io) and drop its grandfathered max-lines
suppression plus the now-stale max-lines and assertion-safety baseline
entries (shrink-only ratchet maintenance).

Behavior-frozen: stdout/exit semantics unchanged; net -2 production LOC.

* fix(voice-call): redact gateway URLs in CLI operational errors

ClawSweeper P1: the operational-error formatter interpolated the raw
connectionDetails.url, so a configured gateway URL with userinfo or query
tokens would print credentials into terminal output. Redact the composed
message once with the canonical net-policy redactor (also covers
remote-controlled close-reason text), exported through the plugin SDK
gateway-runtime subpath (+1 documented surface budget). Regression test
covers a credential-bearing URL in both the URL and message fields.
2026-08-17 18:59:19 -07:00
Peter Steinberger 1ca4103fe9 fix(voice-call): expose realtime/streaming stream paths through tailscale serve/funnel (#125468)
* fix(voice-call): expose realtime/streaming stream paths through tailscale serve/funnel

Tailscale serve/funnel now auto-exposes the realtime and streaming WebSocket stream paths when those audio modes are enabled; previously Twilio <Connect><Stream> could not reach wss://<ts-host><streamPath> and realtime calls dropped after ~1s with no log.

Also: CLI voicecall expose mounts/clears stream paths symmetrically, partial tailscale mounts roll back on failure, and a warning now fires when a call's stream WebSocket never arrives within the token TTL. Reported/observed live by Peter Steinberger.

* fix(voice-call): make tailscale stream exposure atomic

Preserve configured public Tailscale prefixes when mapping realtime and streaming routes, and roll back the full route set when any mount fails. The CLI now uses the same transactional setup path and reports failure instead of accepting a partial exposure.

* fix(voice-call): expose Twilio's configured streaming path

Keep realtime routes under the public webhook prefix they advertise, while mounting streaming.streamPath exactly as Twilio emits it. This preserves the canonical public-to-local route list without expanding the provider API outside the scoped repair.
2026-08-17 18:10:45 -07:00
Peter Steinberger 720da745d9 fix(voice-call): keep realtime calls alive through brief stream reconnects (#125469)
* fix(voice-call): grace realtime stream disconnects

Share reconnect grace by CallSid and stream ID across classic and realtime streams while cleaning realtime bridge resources immediately.

Log terminal call reasons and document Twilio inbound voice and status callback setup.

* test(voice-call): align reconnect grace after rebase

Preserve the newly landed realtime generation and inactivity coverage while updating its terminal expectations for shared delayed finalization.

Remove the redundant replacement cross-product case so the lifecycle suite remains below the max-lines limit.
2026-08-17 17:51:46 -07:00
Peter Steinberger 244712f69a fix(voice-call): tear down realtime calls on stream close and media inactivity (#125463)
Realtime call teardown previously depended on an object-identity guard
that silently skipped ending the call record when bridge instances were
replaced, and had no transport-liveness backstop: a WS close that never
propagated left an answered call running forever. Bindings are now
socket-bound with current-generation terminal ownership, predecessor
audio is retired on successor admission (the overlapping-voices bug),
a 30s media-inactivity watchdog with 2s grace ends calls whose
transport dies silently, and every realtime call end is logged with
its cause.
2026-08-17 17:17:47 -07:00
Peter Steinberger 9f5776e071 fix(voice-call): status exits after offline lookup (#125354)
* fix(voice-call): keep status fallback read-only

* test(voice-call): assert offline status stays read-only

* chore: keep changelog release-owned

* test(voice-call): share status fallback harness
2026-08-17 12:34:19 -07:00
Peter Steinberger 5ebfbbf8d7 fix(plugins): honor per-agent runtime config (#124978)
* fix(plugins): resolve per-agent config through SDK

* test(codex): preserve agent runtime exports

* test(telegram): make default owner explicit

* refactor(plugins): use lightweight agent scope runtime

* fix(codex): preserve multi-agent execution ownership

* chore(plugin-sdk): record approved agent scope exports

* fix(codex): keep scoped sandbox ownership authoritative

* fix(codex): preserve agent scope in native side actions

* fix(ci): avoid counting node check as environment variable
2026-08-17 01:53:08 -07:00
Peter Steinberger 5275eae477 fix(voice-call): honor routed agent credentials for realtime calls (#125144)
* fix(voice-call): select realtime provider per routed call

* test(voice-call): track routing temp directory

* fix(ci): stop counting node check as environment variable
2026-08-17 01:47:16 -07:00
Peter Steinberger 73ab74eccc fix(discord): preserve routed agent for realtime voice (#125111) 2026-08-16 23:41:38 -07:00
Peter Steinberger 5168b5d4ab feat(voice-call): sessionScope "main" routes calls into the agent main session (#124708)
* feat(voice-call): add sessionScope "main" for main-session call routing

Inbound and outbound calls can now share the configured agent's main
session instead of a dedicated voice session. The new scope resolves
through the existing explicit-key canonicalization path, honoring core
session.mainKey and global-scope aliasing. The inbound webhook path now
forwards coreSession like every other resolver call site.

* style: format events.test.ts

* test(voice-call): split events.test.ts under the max-lines cap
2026-08-16 11:47:47 -07:00
Peter Steinberger f43544f752 refactor: remove vestigial runtime indirection (#124554)
* refactor: remove vestigial indirection

* test: update Slack runtime API guard
2026-08-16 05:31:36 -07:00
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 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 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
zengLingbiao 0eeb9db216 fix(voice-call): redact credential material from provider error bodies (#117304) 2026-08-08 11:51:23 +08: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 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
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