Commit Graph

880 Commits

Author SHA1 Message Date
Yiğit ERDOĞAN
19d887169f fix(ai): ChatGPT Responses retries errors it classified as non-retryable (#110655)
* fix(ai): ChatGPT Responses retries errors it classified as non-retryable

The retry loop builds its friendly error and throws it from inside the same
try block whose catch treats unknown failures as retryable network errors.
Authentication and bad-request failures were therefore resent up to
maxRetries times, adding 7s of backoff before surfacing the same message.

Tag the already-classified failure with a private error type and rethrow it
unchanged from the catch, leaving the retryable paths untouched.

* test(ai): move retry classification cases to a dedicated file

The provider test file was already near the 1000-line oxlint max-lines
budget, so the new cases pushed it over. Split them out following the
existing <module>.<topic>.test.ts convention.

* refactor(ai): separate HTTP and transport retries

Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>

* test(ai): clarify synthetic JWT fixture

Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 23:09:42 +01:00
Yiğit ERDOĞAN
9f7c7521f1 fix(agents): Responses turns that end incomplete report zero tokens and zero cost (#109904)
* fix(agents): record token usage when a Responses turn ends incomplete

The agent-side Responses processor only had a terminal branch for
response.completed. A stream that ends with response.incomplete — the
max_output_tokens and content_filter cases, and what Azure emits on early
truncation — matched no branch at all, so the event was dropped: usage was
never recorded and stopReason was never set. The turn reports zero tokens and
zero cost, which is the drift in #100954.

#109615 fixed the same split on the package-side processor by finalizing
completed and incomplete through one finalizeResponse. This does the same for
the agent path, which #109615 did not touch: both terminal events now record
usage, cost and service-tier pricing through one helper.

The helper moves to its own module rather than growing openai-responses-transport.ts,
which is a legacy file the max-lines ratchet will not let grow; extracting the
block drops it from 2502 to 2444 lines.

Content-filtered turns are mapped to a provider error instead of a plain length
stop, matching what the package side already does, so the two terminal surfaces
do not disagree.

* fix(agents): keep Responses output backfill on completed turns

Terminal handling now covers response.incomplete, which also routed those
events into backfillCompletedResponseOutput. That reconstruction exists to
recover a final answer when item events never arrived; an incomplete turn has
no final answer, so replaying its partial output persisted truncated text the
streaming path never emitted. Usage and stop-reason recording still apply to
both terminal events.

* refactor(ai): share one Responses terminal usage mapper

The agent transport mapped terminal usage buckets, cost, and stop reasons in
parallel with the package-side processor, so the two could drift on token
buckets, service-tier pricing, or future terminal-event semantics.

Both now call one canonical mapper. openai-responses-shared.ts cannot be
imported across the package boundary, so the mapper lives in its own module
re-exported through the existing internal/openai entry point; no new subpath
is introduced. The agent module keeps only the reasoning-token accounting the
package path does not track.

Merging the two revealed a real disagreement on totalTokens: the package took
the reported total, the agent summed the split buckets. The canonical rule is
now max(bucket sum, reported total), which keeps the reported value while
covering both payloads that omit total_tokens and payloads whose cached_tokens
exceed input_tokens, where clamping leaves the reported total short.

* fix(agents): preserve partial incomplete Responses output

Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>

* test(agents): cover incomplete terminal output backfill boundaries

The head's partial-output preservation is only safe while it stays a recovery
path. Pin both sides of that guard: text that already streamed must not be
replayed from the terminal payload, and a non-length incomplete stop must not
surface partial text as an answer.

* fix(agents): avoid shadowing Responses options

Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>

* style(agents): apply oxfmt to the incomplete backfill test

* test(agents): register incomplete Responses suite

Co-authored-by: Yiğit ERDOĞAN <yigiterdogan023@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 23:03:53 +01:00
clawsweeper[bot]
b88646cf78 feat(webchat): reply-to a message with hydrated reply context (#110791)
* feat(webchat): reply-to a message with hydrated reply context

Control UI replies now carry the target transcript id as replyToId on
chat.send. The Gateway resolves the replied-to message from session
history and hydrates the channel-agnostic ReplyToId/ReplyToBody/
ReplyToSender envelope fields, so agents receive reply_to_id,
has_reply_context, and the untrusted reply-target block exactly like
Discord replies (mirrors #90263). Reply targets without a persisted
transcript id keep the inline-quote fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(webchat): keep non-reply chat.send dispatch ordering and satisfy CI gates

* docs(webchat): match reply-context doc to webchat conversation-info policy

* fix(webchat): hydrate reply bodies from display-visible content only

---------

Co-authored-by: openclaw-clawsweeper[bot] <openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-07-18 15:57:59 -06:00
Wynne668
d5b2749fd8 fix(ai): skip blank environment credentials during provider auth (#109691)
* fix(ai): ignore blank environment API keys

* test(ai): avoid credential-shaped fixture assignments

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 22:33:54 +01:00
Peter Steinberger
5fe8d6a852 fix(gateway): clients can identify authorization failures (#110925)
* fix(gateway): structure authorization errors

* test(gateway): align authorization contracts

* fix(gateway): regenerate protocol bindings

* fix(gateway): preserve optional scope errors

* fix(gateway): report complete pairing scopes

* style(gateway): format protocol exports
2026-07-18 22:02:28 +01:00
mushuiyu886
1da345e9d3 fix(mcp): clamp oversized MCP timeouts (#105784)
* fix(mcp): clamp oversized MCP timeouts

* fix(mcp): centralize timer-safe timeout normalization

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 21:50:19 +01:00
Peter Steinberger
5fdb0cd24e feat(chat): switch between session transcript branches from the chat header (#110857)
* feat(chat): switch between session transcript branches from the chat header

* fix(chat): type fixes and protocol regen for branch switcher CI
2026-07-18 20:06:36 +01:00
Peter Steinberger
88e5af7097 feat(ui): interleaved sidebar zone with custom session icons and drag ordering (#110682)
* feat(ui): custom session icons with agent-drawable SVG and nav-parity pinned rows

* wip: slice-2 interleaved sidebar zone (pre-review)

* fix(ui): trim icon exports, bypass protocol barrel in startup bundle, regen Swift protocol client

* fix(ui): preserve unknown-agent zone entries on writes, prune entries on any unpin

* fix(ui): reset keeps unloaded session slots; enforce SVG byte cap on canonical form

* fix(ui): archiving a pinned session retires its sidebar zone slot

* fix(ui): persist drag-pinned zone slot only after the pin patch lands

* fix(ui): recompute drop insertion against freshest zone order on pin ack

* fix(ui): consume self-drop events before the zone bailout

* docs(ui): note the non-sidebar unpin pruning contract on pruneSidebarSessionEntry

* refactor(ui): extract pure session-tree projection; drop unused zone type export
2026-07-18 17:13:09 +01:00
Peter Steinberger
0acece4591 feat(chat): rewind and fork a session from a message bubble (#110660)
* feat(chat): rewind and fork a session from a message bubble

* docs(web): document chat rewind and fork bubble actions

* fix(chat): lint cleanups, protocol regen, and test splits for rewind/fork CI

* fix(ui): fit chat rewind disabled styles inside the startup CSS budget
2026-07-18 14:46:34 +01:00
Alix-007
ad3b8e0b6f fix(memory): bound qmd taskkill cleanup (#109265)
* fix(memory): bound qmd taskkill cleanup

* test(memory): satisfy qmd process lint
2026-07-18 06:11:14 -07:00
Peter Steinberger
40793e6f8b fix: bound pasted input and provider response bodies (#110627)
* refactor(runtime): centralize bounded I/O handling

* fix(runtime): finalize bounded I/O contracts

* chore(security): drop stale audit import

* docs(changelog): credit bounded I/O fixes

Co-authored-by: Pick-cat <huang.ting3@xydigit.com>

* fix(agents): keep provider HTTP options private

* fix(ai): traverse OpenAI schema maps by value

* fix(runtime): preserve absolute download deadlines

* ci(ui): stabilize compressed CSS budget

* fix(ai): traverse legacy schema applicators

---------

Co-authored-by: Pick-cat <huang.ting3@xydigit.com>
2026-07-18 13:54:56 +01:00
Peter Steinberger
105aebacea fix: report agent deletion cleanup failures (#110560) 2026-07-18 12:23:39 +01:00
Peter Steinberger
01a9e1d398 feat(memory): default cross-conversation recall for personal installs (#110597)
* feat(memory): default private recall for personal installs

* fix(memory): repair remember-across CI checks
2026-07-18 12:16:49 +01:00
Peter Steinberger
7752e33f79 Revert "fix(security): restore fs import lost in bounded manifest-read merge"
This reverts commit 39528edd74.

That push was an accident: the fs-import fix it described had already landed
on main, and a rebase reduced the commit to unrelated in-progress
gateway-protocol schema edits (nodes/session-placement) that were staged in
the pushing worktree and belong to another work stream. Restore the reviewed
main state; the protocol work can land through its own PR.
2026-07-18 02:45:59 -07:00
Peter Steinberger
39528edd74 fix(security): restore fs import lost in bounded manifest-read merge
#101773 removed the node:fs/promises import while switching plugin manifest
reads to fs-safe helpers, but getSkillCodeSafetySummary (added later by
#109363) still reads SKILL.md via fs.readFile. Main has been red since the
merge (check-prod-types, check-lint, check-test-types, package-boundary
compile, compact-large-5). Restore the import; skill-file reads keep their
pre-existing unbounded contract.
2026-07-18 02:38:23 -07:00
Peter Lee
c791e2b128 fix(cli): restore terminal state before exit in logs and hooks commands (#105863)
* fix(cli): restore terminal state before exit in logs and hooks commands

* fix(cli): route logs/hooks error exit through canonical defaultRuntime.exit

* fix(cli): route terminal reset to stderr in JSON mode to keep stdout parseable

* fix(cli): centralize stream-aware terminal reset exit

Add optional resetStream parameter to RuntimeEnv.exit so JSON-mode
callers can route the terminal reset to stderr through the shared
defaultRuntime.exit path, keeping structured stdout parseable.

- Extend RuntimeEnv.exit signature with optional resetStream option
- Route JSON-mode logs fatal exit through unified defaultRuntime.exit
  instead of manually pairing restoreTerminalState with process.exit
- Update test mock to exercise real terminal restore during exit

* refactor(cli): tighten terminal exit contract

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:25:13 +01:00
Peter Steinberger
e1d87e9a9d fix(sessions): preserve parent lifecycle for parallel children (#110541)
* fix(sessions): declare parent lifecycle disposition

Co-authored-by: Luiz Antonio Busnello <lab@generantis.com.br>

* chore: keep release notes in PR body

* fix(sessions): preserve parallel fallback on old gateways

* chore(i18n): refresh native source inventory

---------

Co-authored-by: Luiz Antonio Busnello <lab@generantis.com.br>
2026-07-18 10:16:14 +01:00
cxbAsDev
1e2d0e29b0 refactor(gateway): adopt closedObject in recently added schema files (#106532)
* refactor(gateway): adopt closedObject in recently added schema files

* test(gateway): prove recently closed node and dispatch schemas reject extra fields
2026-07-18 10:12:18 +01:00
Peter Steinberger
222dc58011 feat(linux): native gateway transport for Quick Chat — device identity, TLS pinning, ack-driven sends (#110491)
* feat(gateway): add Linux native auth surface

* feat(linux): persist Gateway device identity

* feat(linux): add native Gateway WebSocket client

* feat(linux): route Quick Chat through Gateway

* feat(cli): expose dashboard transport handoff

* docs(linux): document native Quick Chat transport

* test(linux): placeholder-shaped fixture token in device-auth payload test

* test: placeholder-shaped credential fixtures; reshape device-token rebind

* test: keep auth-method enums verbatim; rename only credential fixtures

* test(gateway): move Linux native admission coverage to a dedicated test file

* style: replace scanner-evasion literals with honest shapes; shared trim helper for auth material

* style(cli): join-built computed keys instead of literal concatenation

* chore: drop release-owned CHANGELOG edit from feature branch
2026-07-18 09:59:10 +01:00
Alix-007
deccdb5e57 fix(ui): bound browser gateway WebSocket opening (#109037)
* fix(ui): bound browser gateway socket opening

* fix(ui): use browser-safe timeout export
2026-07-18 09:38:37 +01:00
VectorPeak
badb5ae706 fix(memory): reject malformed embedding batch JSONL bytes (#110502)
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
2026-07-18 09:16:19 +01:00
Peter Steinberger
9b556bcd5e feat(system-agent): auto-hatch into the agent after fresh setup (#110331)
* feat(system-agent): hatch into the agent after a fresh setup applies

The hatch is a ceremony: a fresh-install setup apply now announces the hatch
and hands straight off (open-tui in the terminal, open-agent for gateway
clients); the web custodian page lands in agent chat with the birth-sequence
opener prefilled as a draft so one Send wakes the seeded BOOTSTRAP. Non-setup
persistent operations keep their in-place replies.

* fix(system-agent): hatch only on clean post-write verification

* fix(ui): scope hatch draft to setup handoffs

* fix(onboarding): seed hatch handoffs across clients

* fix(i18n): refresh native hatch inventory

* fix(onboarding): seed remote gateway hatch handoff

* fix(macos): localize hatch draft

* fix(onboarding): gate hatch on pending bootstrap

* fix(i18n): sync hatch source to ios catalog

* fix(onboarding): gate hatch on canonical pending state
2026-07-18 03:32:15 -04:00
Dave Morin
4b3ee5e7eb feat: let agents remember across private conversations (#100140)
* feat(memory): remember across private conversations

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>

* chore(docs): regenerate config baseline

* fix(memory): restore recall configuration wiring

* fix(memory): scope recall transcript indexing

* test(memory): repair conversation recall fixtures

* test(memory): split session visibility coverage

* style(memory): format type imports

---------

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 08:21:43 +01:00
Peter Steinberger
ba5752dd63 fix(skills): warn on unterminated frontmatter (#110479) 2026-07-18 07:52:06 +01:00
tzy-17
6709693d39 fix(gradium): return false from isConfigured on invalid baseUrl instead of throwing (#108569)
* fix(tts): wrap tts.status provider enumeration with configuredOrFalse

`tts.status` enumerates provider states by calling
`getResolvedSpeechProviderConfig` then `isConfigured` for each
provider. If a provider's config resolution throws (e.g. Gradium
with an invalid baseUrl), the entire tts.status call fails.

Wrap the provider-state closure with `configuredOrFalse` (already
used by `talk.ts`) so a misconfigured provider is reported as
`configured: false` instead of crashing the enumeration.

Addresses review feedback on #108569.

* fix(tts): isolate provider configuration probes

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 06:29:03 +01:00
Peter Steinberger
b6bac30e33 refactor(agent-core): delete the unused session harness layer (#110287) 2026-07-18 02:27:48 +01:00
Patrick Erichsen
f9b860fc84 feat(plugins): order featured catalog by recency (#110273) 2026-07-17 18:06:13 -07:00
Peter Steinberger
92e8e8bca6 test: move deferred-event-buffer test to its packages/ai owner and drop dead protocol test 2026-07-17 17:36:48 -07:00
Peter Steinberger
897198b9f5 feat(gateway): typed structured questions on openclaw.chat with live option cards (#110242)
* feat(gateway): typed structured questions on openclaw.chat

The chat result gains an additive optional question field (2-4 options, one
recommended max, per-option reply text). Producers: the two onboarding welcome
variants (apply-setup yes/ask, ready next-step) and hosted wizard select/confirm
steps, which mirror the awaited step so card clients render real wizard choices.
Prose replies always stand alone for text-only clients (macOS app, TUI). The
custodian page consumes the typed field and drops the PR1 string-marker parser
(never shipped in a release); cards send the option reply while the transcript
shows the label.

* chore: keep OnboardingWelcome type module-local

* chore(protocol): regenerate Swift bindings for the chat question field
2026-07-18 01:14:44 +01:00
Peter Steinberger
ec8f6e5e03 feat(browser): add secure per-tab copilot panel (#109817)
* feat(browser): add copilot security contracts

* fix(gateway): expose verified client identity to handlers

* feat(browser): add secure per-tab copilot panel

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): separate copilot gateway hint custody

* fix(browser): preserve legacy pairing parse shape

* fix(browser): harden copilot lifecycle custody

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): enforce copilot lifecycle boundaries

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* style(browser): format copilot sources

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): preserve copilot consent revocation

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): split copilot custody owners

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(browser): normalize websocket array buffers

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* chore(protocol): regenerate Swift gateway models

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): model copilot runtime entrypoints

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): honor extension build boundaries

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(gateway): assert targeted chat delivery

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(gateway): cover targeted delivery calls

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): declare copilot build dependencies

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(ci): clear browser copilot gate failures

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(ci): cover copilot lint exclusion

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): gate copilot on relay custody

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(browser): bound copilot relay frames

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

---------

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>
2026-07-18 01:00:23 +01:00
Peter Steinberger
c1ee9c6fb1 fix: network error hardening, session short-id entropy, extension load caching (#110196)
* fix(infra): harden network client errors, session short ids, and extension load caching

* fix(infra): preserve injected dispatcher seams and drop the uncached extension loader
2026-07-18 00:35:13 +01:00
Peter Steinberger
781913025b improve: stream native sessions as hosts finish (#110211)
* perf: stream native session catalogs by host

* fix: satisfy session catalog CI contracts

* fix: retain changed-session refresh timing

* fix: keep catalog refresh helpers private
2026-07-17 23:59:57 +01:00
Peter Steinberger
da44d52ac6 feat: ask_user — structured questions from the agent with web card, channel buttons, and text answers (#109922)
* feat(gateway): add transient question runtime (question.* methods + broadcasts)

* feat(agents): add blocking ask_user question tool with chat prompt delivery and text-reply claim

* feat(ui): interactive in-thread question cards for ask_user

* feat(channels): native tap-to-answer buttons for ask_user on Telegram, Discord, and Slack

* feat(ui): unify codex and gateway question cards with interactive gateway answering

* refactor(agents): collapse ask_user pending state to one registry; docs for ask_user

* fix(agents): include ask_user in normal gateway runs; add question-flow control-ui e2e

* test(ui): avoid credential-shaped fixture in question card test

* refactor(ui): reorder stream-group context keys

* fix(gateway,ui): validate question answers at resolve; reject secret/duplicate-label questions; UI retry and reconnect hardening

* fix(gateway,agents): canonicalize accepted option answers; bound ask_user option labels to 64 chars

* chore(ci): prune unused question exports, allowlist mobile question events, fix discord lint

* chore(ci): regenerate protocol/i18n/docs/tool-display artifacts for question surface

* fix(protocol): flatten QuestionRecord for native codegen; drop TS-only alias from schema registry

* chore(android): regenerate ask-user localization resources

* docs: regenerate docs map after rebase

* fix(ci): avoid stale read-only dependency disks

* test: remove stale reef lint suppression ratchet

* fix(ci): keep source locale drift advisory in release gates

* fix(ci): scope locale advisory handling to parity check
2026-07-17 22:24:17 +01:00
Peter Steinberger
b319493a52 improve: let Code Mode use declared tool result shapes (#109813)
* feat(agents): add Code Mode output contracts

* perf(agents): defer untrusted tool schemas

* chore(plugin-sdk): refresh API baseline

* fix(agents): preserve deferred schema markers

* fix(agents): preserve policy-blocked tool results

* fix(agents): preserve nullable output contracts

* fix(agents): reject policy blocks from success contracts

* fix(agents): preserve output contracts through normalization

* test(agents): type normalized tool fixtures

* fix(agents): validate catalog results before projection

* fix(agents): keep result snapshots internal

* fix(agents): fail closed on unrenderable unions

* fix(agents): preserve empty result markers

* test(agents): keep result fixture discriminator literal

* test(agents): use native own-property check
2026-07-17 14:46:37 +01:00
Peter Steinberger
cbaf112355 fix: compaction usage guards and agent-loop turn correctness (#109709)
* fix(agents): compaction usage guards and agent-loop turn correctness

* fix(agents): manual compaction replans with zero retention for small sessions

* ci: retrigger pull-request validation

* ci: refresh pull-request validation

* test(agents): live end-to-end agent session coverage

* fix(agents): keep yielded runs settled so external delivery can claim the session

* docs(agents): clarify length retry bookkeeping
2026-07-17 14:13:29 +01:00
Peter Steinberger
8020dd3e08 fix(reef): discover trusted peers as conversations (#109905)
* fix(reef): discover trusted peer conversations

* test(reef): document temporary state cleanup

* test(gateway): include conversation discovery in method order

* chore: leave changelog to release automation

* fix(gateway): preserve configured conversation discovery

* fix(gateway): validate turns before session binding

* fix(gateway): preserve directory conversation identity
2026-07-17 13:55:30 +01:00
WhatsSkiLL
4d3b18811e feat(android): add Wear real-time Talk controls (#109483)
* feat(android): add Wear real-time Talk controls

* fix(android): satisfy Wear Talk CI checks

* fix(talk): remove unused client language parameter

* fix(android): harden Wear realtime Talk routing

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>

* chore(android): refresh Wear Talk metadata

* chore(android): align native i18n baseline

---------

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 13:46:05 +01:00
Peter Steinberger
6745f9a553 fix: provider usage accounting, retry/overflow classification, and output clamping (#109796)
* fix(ai): provider usage accounting, retry and overflow classification, output clamping

* ci: refresh pull-request validation

* test(ai): live-probe overflow classification and output clamping
2026-07-17 12:40:01 +01:00
Peter Steinberger
6ac15970a7 feat(onboarding): unified empty-state with provider icons, websites, and recommended installs (#109681)
* feat(onboarding): unify setup recommendations

* fix(control-ui): proxy model setup icons

* fix(onboarding): refresh landing artifacts

* chore(ui): sync translated i18n catalogs

* chore(ui): keep generated locale artifacts on the refresh workflow
2026-07-17 01:01:06 -07:00
ooiuuii
6651813bd0 fix(logging): redact auth-style HTTP headers (#107999)
* fix(logging): redact auth-style HTTP headers

* fix(logging): redact structured auth headers

* test(logging): keep auth fixtures synthetic

* test(logging): preserve existing gateway fixtures

* fix(logging): cover serialized auth credentials

* fix(logging): harden auth header redaction

* fix(logging): cover serialized auth whitespace

* chore(logging): refresh reviewed PR head

* test(logging): expect complete API key redaction

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 00:25:15 -07:00
Peter Steinberger
a2ec3f6904 refactor: separate external conversations from local sessions (#109411)
* feat: separate external conversations from sessions

* test: cover conversation tool authorization

* chore: refresh session schema baseline

* fix: persist effective conversation delivery text

* fix: bind conversation identity to delivery target

* fix: preserve pending conversation deliveries

* fix: make conversation delivery outcomes synchronous

* refactor: make conversation delivery durable

* fix: harden durable conversation retries

* fix: close durable conversation pre-send gaps

* fix: terminally reject invalid conversation deliveries

* refactor: route external conversations through gateway

* fix: namespace conversation delivery queue intents

* refactor: remove obsolete transcript replacement path

* test: prove conversation delivery v10 migration

* test: keep conversation action mock typed

* fix: clear conversation refactor CI gates

* test: align Reef delivery coverage

* chore: refresh Android conversation strings

* fix: harden external conversation state

* fix: close conversation race edges

* fix: preserve conversation delivery identity

* fix: replay durable conversation operations

* fix: unify agent schema at version 11

* chore: move release note context to PR

* fix: make required queue persistence force core delivery

* chore: refresh plugin SDK baseline
2026-07-17 00:09:51 -07:00
Peter Steinberger
b84199644d fix: silent credential-save failures and session/tool hygiene gaps (#109622)
* fix(agents): surface auth persistence failures and harden session, model, and shell tool hygiene

* refactor(agents): keep shell invocation types module-local

* test(agents): derive shell config type locally
2026-07-17 00:02:45 -07:00
Peter Steinberger
0c989568b3 fix: OpenAI-compatible provider compat and error-body surfacing (#109556)
* fix(ai): harden OpenAI-compatible provider compat and error surfacing

* test(ai): add live completions compat coverage

* test(infra): mirror packages live glob in live-config test
2026-07-17 00:02:08 -07:00
Edward Abrams
8fa4867ab4 fix(memory): avoid rebuilding unchanged QMD session exports (#77158)
* perf(memory): cache qmd exports by corpus revision

Co-authored-by: Edward Abrams <zeroaltitude@gmail.com>

* test(memory): track qmd exporter temp dirs

* test(memory): use plugin SDK temp fixture

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 23:22:40 -07:00
Peter Steinberger
03d287d111 fix: Responses streams mishandle interleaved output items and silent truncation (#109615)
* fix(ai): track Responses output items per index and require terminal stream events

* test(ai): add live Responses stream coverage

* test(infra): mirror packages live glob in live-config test
2026-07-16 23:15:35 -07:00
Erick Kinnee
571f1dcef9 fix(dreaming): drop heartbeat assistant responses from dream corpus (#109403)
* fix(dreaming): drop heartbeat assistant responses from dream corpus

The dreaming ingestion pipeline filters heartbeat user messages
(containing [OpenClaw heartbeat poll]) via sanitizeSessionText, but the
paired assistant response is only dropped when it is the exact string
HEARTBEAT_OK. Local models frequently respond with natural-language
acknowledgments (e.g. "Heartbeat received. Main is active.") which pass
through the sanitizer unchanged and enter the dream corpus as
low-confidence (0.58) memory snippets.

Fix: track heartbeat user message drops in buildSessionEntry and skip
the immediately following assistant response. This cross-message coupling
is safe because the heartbeat prompt pattern is injected by the runtime
and cannot be spoofed by user input, unlike [cron:...] or
System (untrusted): ... patterns (see PR #70737).

Refs: #103720

* test(dreaming): add heartbeat assistant response filter test

* fix(dreaming): use provenance-based heartbeat detection instead of text matching

Replace text-based heartbeat detection (isGeneratedHeartbeatPromptMessage)
with provenance-based authentication. The heartbeat turn now carries
provenance: { kind: "heartbeat" } when persisted to the transcript,
and buildSessionEntry checks for this provenance instead of matching
user-spoofable text content.

Changes:
- src/sessions/input-provenance.ts: Add "heartbeat" to
  INPUT_PROVENANCE_KIND_VALUES
- src/auto-reply/reply/get-reply-run.ts: Attach heartbeat provenance
  to user turn input when isHeartbeat is true
- packages/memory-host-sdk/src/host/session-files.ts: Check
  message.provenance.kind === "heartbeat" instead of text matching
- packages/memory-host-sdk/src/host/session-files.test.ts: Update
  heartbeat test to include provenance; add lookalike regression test

This addresses the ClawSweeper review finding [P1] about user-spoofable
text matching. The cross-message coupling is now authenticated by
runtime provenance, not user-typed content.

Refs: #103720

* fix(dreaming): add targeted heartbeat-derived corpus repair

* fix(dreaming): fix TS return type for clearScopedLegacySessionIngestionJson catch

* fix(dreaming): match chunked SQLite seen-state keys by stored scope

* fix(dreaming): repair SQLite-backed session transcript lookup in doctor

The findHeartbeatContaminatedCorpusLines function could not read
SQLite-backed session transcripts. When a corpus ref had no .jsonl
extension (SQLite logical path format), it appended .jsonl, read an
empty file, and silently skipped — leaving pre-fix heartbeat
contamination intact for SQLite users.

Fix:
- Add loadTranscriptLinesFromSqlite helper that reads events via
  the canonical loadTranscriptEventsSync API
- Serialize all events to preserve original event positions for
  corpus #L<n> line-number references
- Fall back to SQLite reader when filesystem read fails on a
  non-.jsonl corpus ref path

Test: add SQLite-backed session regression test that seeds a
session, writes corpus refs without .jsonl extension, and
verifies both audit detection and targeted repair.

* fix(dreaming): address autoreview P1 and P2 for checkpoint clearing and early return

P1: Remove clearScopedSessionIngestionState call after heartbeat line
removal. Clearing the cursor causes the next ingestion to re-process the
transcript from the beginning, duplicating normal corpus lines that were
deliberately retained.

P2: Remove early return after heartbeat cleanup so the self-ingestion
narrative content check and archiveDiary request still run.

* fix(dreaming): resolve corpus ref session path without duplicate agent ID

The session path in corpus refs is already in the format
'sessions/main/abc.jsonl' (includes agent subdirectory). The
previous code prepended source.agentId again, creating a path
like 'agents/main/sessions/main/abc.jsonl' — which silently
returned empty in production workspaces.

Fix: use path.basename to extract just the filename from the
session path, then construct the transcript path correctly.

* refactor(dreaming): split repair utils into separate file to satisfy LOC ratchet

The dreaming-repair.ts file grew from 337 to 831 lines, exceeding the
500-line LOC ratchet limit. Split helper utilities into a new
dreaming-repair-utils.ts file:

- dreaming-repair.ts (365 lines): imports, types, public API functions
  (auditDreamingArtifacts, repairDreamingArtifacts)
- dreaming-repair-utils.ts (498 lines): all helper functions, constants,
  and internal types

* fix(ts): add missing type imports for return types in dreaming-repair.ts

* fix(deadcode): remove unused exports from dreaming-repair-utils.ts

* fix: resolve merge conflict marker in get-reply-run.ts

* fix: remove unnecessary export from INPUT_PROVENANCE_KIND_VALUES

* fix(dreaming): converge targeted repair path with wholesale archive+clear

When heartbeat contamination is found, archive the entire session-corpus directory and clear all SQLite checkpoints instead of doing targeted line-by-line rewrite. This ensures the cleaned corpus gets re-ingested under the new provenance-based forward filter.

* fix(dreaming): authenticate heartbeat transcript turns

Co-authored-by: Erick Kinnee <1707617+ekinnee@users.noreply.github.com>

---------

Co-authored-by: Erick Kinnee <erick@ekinnee.dev>
Co-authored-by: Erick Kinnee <ekinnee@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 22:00:21 -07:00
Peter Steinberger
a77c0770ff refactor(speech-core): share TTS request pre-resolution across discord and voice-call (#109640) 2026-07-16 21:47:06 -07:00
ooiuuii
7641aa80c2 fix: plugins update rewrites config for install-record-only updates (#98422)
* Avoid config rewrites for plugin index updates

* Preserve config freshness for records-only plugin updates

* Validate records-only plugin update config

* fix(plugins): reload index-only updates

Co-authored-by: luyifan <al3060388206@gmail.com>

* chore(protocol): refresh generated clients

Co-authored-by: luyifan <al3060388206@gmail.com>

* fix(gateway): wire plugin refresh handler

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 21:38:45 -07:00
Peter Steinberger
a0fac37f14 feat: add OpenAI Video Talk (#109579)
* feat(talk): add OpenAI Video Talk

Co-authored-by: wuxuanshu <1064076525@qq.com>

* fix(protocol): refresh native Talk capability model

* chore(i18n): refresh control UI fallback baseline

* chore(i18n): defer locale refresh to workflow

---------

Co-authored-by: wuxuanshu <1064076525@qq.com>
2026-07-16 21:25:09 -07:00
snowzlmbot
17c2ce05d8 fix(secrets): keep startup alive when TTS SecretRefs are missing (#101265)
* fix(secrets): degrade missing TTS SecretRefs at startup

* test(secrets): keep non-activating startup strict

* test(secrets): mark denied key fixture synthetic

* test(secrets): use synthetic TTS key fixture

* test(secrets): use neutral TTS key placeholder

* test(secrets): isolate TTS key placeholder

* test(secrets): shorten TTS ref fixture name

* test(secrets): normalize synthetic credential fixtures

* test(secrets): isolate optional redaction coverage

* fix(secrets): preserve degraded TTS ref ownership

* refactor(secrets): keep optional resolver internal

* test(secrets): cover default provider alias misses

* test(secrets): pin explicit provider ownership

* style(secrets): format optional assignment imports

* refactor(secrets): keep optional metadata private

* style(secrets): restore collector file header

* fix(secrets): isolate unavailable SecretRef owners

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>

* test(secrets): complete provider fixtures

* style(status): avoid degraded path shadowing

* style(secrets): satisfy runtime lint

* refactor(secrets): keep error codes internal

* fix(secrets): keep unowned assignments fail closed

* fix(secrets): preserve provider resolution batching

* fix(secrets): normalize stalled resolution errors

* fix(secrets): reject provider limit violations

---------

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 21:07:01 -07:00