Commit Graph

38996 Commits

Author SHA1 Message Date
cxbAsDev
4b2b5bcf89 fix(hooks): bound hook workspace manifest and HOOK.md reads (#101472)
* fix(hooks): bound hook workspace manifest and HOOK.md reads

* fix(hooks): enforce maxBytes while reading hook metadata fd

ClawSweeper review noted that openRootFileSync validates stat size
before returning the fd, but the subsequent fs.readFileSync of the fd
was unbounded. A file that grows after validation could still OOM
workspace discovery. Replace the full fd read with a chunked bounded
reader that throws once maxBytes is exceeded, and add regression
coverage for the overflow case.

* test(hooks): cover bounded hook reads through public workspace API

* refactor(hooks): use canonical bounded fd reader for hook metadata

* fix(hooks): warn and skip oversized hook metadata during discovery

ClawSweeper review required the maintainer-selected oversized-metadata
diagnostic contract: warn and skip. readRootFileUtf8 now catches the
RangeError from the canonical readFileDescriptorBoundedSync helper and
emits one warning per oversized package.json/HOOK.md identifying the
path and the byte limit, while discovery continues for other hooks.

The redundant open-time maxBytes stat check is removed so the shared
bounded reader is the single owner of the byte cap; overflow always
surfaces as RangeError, keeping the warning accurate for both static
oversized files and post-open growth.

Add focused tests: warning content for both oversized surfaces,
continued discovery alongside an oversized hook, exact-limit acceptance,
and the plain-hook fallback when a package manifest is oversized.

* chore: retrigger CI after rebase

* refactor(hooks): tighten bounded metadata coverage

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 11:23:21 +01:00
Peter Steinberger
2920ec1fab docs(channels): settle replay-guard vs ingress-drain layering contract (#109799)
* docs(channels): settle replay-guard vs ingress-drain layering contract in code comments and SDK docs

* docs: refresh SDK channel docs map
2026-07-17 11:13:00 +01:00
Peter Steinberger
f82511762f test: reuse device pairing database fixture (#109894) 2026-07-17 11:05:25 +01:00
Peter Steinberger
8f3b2ab021 style: format spawn-ps and agents display test
Both landed unformatted on main (6th/7th merge-skew format break today),
failing check-lint repo-wide. Repo-wide oxfmt --check is clean after this.
2026-07-17 02:51:45 -07:00
juyaohuidt
89780d5a60 fix(infra): gateway pid probe no longer hangs when ps sampling stalls (#109731)
* fix(infra): gateway pid probe no longer hangs when ps sampling stalls

readGatewayProcessArgsSync probes ps to verify gateway argv before
signaling or reporting listener PIDs. The darwin branch already passed
timeout: 1000, but spawnSync defaults killSignal to SIGTERM, which an
unresponsive or hung ps child can ignore and keep the gateway process
blocked past the timeout.

Force killSignal: SIGKILL (matching the doctor probe fix in #109243) so
a stalled ps probe is reaped at the deadline instead of hanging gateway
signal verification and listener PID discovery.

Extract GATEWAY_PS_PROBE_TIMEOUT_MS for the named timeout and assert the
full spawnSync options (encoding / killSignal / timeout) in the darwin
test.

* refactor: centralize bounded ps probes

Co-authored-by: 琚耀辉0668001366 <ju.yaohui@xydigit.com>

* refactor: leave doctor ps hardening to main

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:41:52 +01:00
Peter Steinberger
1a2d9e5e5c refactor(meeting-bot): extract browser meeting-bot core behind MeetingPlatformAdapter (#109755)
* refactor(meeting-bot): extract browser meeting-bot core behind MeetingPlatformAdapter

* chore(google-meet): prune max-lines baseline entries shrunk by extraction

* fix(meeting-bot): drop orphaned extension realtime files and refresh lint/test types after extraction

* chore(google-meet): prune deleted realtime max-lines baseline

* chore(meeting-bot): remove release-owned changelog entry

* fix(meeting-bot): harden session leave, cleanup retry, and engine teardown paths
2026-07-17 10:35:56 +01:00
zhanxingxin1998
16f658d0c6 fix(gateway): reap stale MCP processes on session reset regardless of… (#93559)
* fix(gateway): defer MCP cleanup until active leases release

Mark session MCP runtimes for retirement before reset/delete waits, preserve active work through leases, and complete deferred cleanup when the final materialized run lease releases.\n\nCo-Authored-By: Codex <noreply@openai.com>

* test(mcp): prove deferred child process retirement

Co-Authored-By: Codex <noreply@openai.com>

* test(mcp): prove deferred database lock release

* fix(gateway): bind MCP retirement to timed-out runs

* style(mcp): avoid lifecycle callback shadowing

* test(mcp): align nullable wait mocks

* fix(gateway): follow replacement runs during cleanup

* fix(gateway): close MCP watcher overlap races

* test(agents): prove reply-backed run draining

* test(gateway): reuse MCP retirement parameter type

* fix(gateway): type MCP watcher identity safely

* perf(gateway): lazy-load session cleanup runtime

* perf(gateway): lazy-load MCP cleanup runtime

* perf(agents): lazy-load MCP retirement manager

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:34:29 +01:00
Peter Steinberger
0890f7f914 fix(ci): repair main test and script type checks (#109826) 2026-07-17 10:33:55 +01:00
Monkey-wusky
065223c438 fix(apns): cancel redirect relay response body before returning (#109728)
* fix(apns): cancel redirect relay response body before returning

* test: fold APNS redirect body cleanup proof

Co-authored-by: 毛宇豪0668001457 <mao.yuhao@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:25:00 +01:00
Peter Steinberger
01961bbd38 fix(ci): restore web push migration lint (#109845) 2026-07-17 10:24:06 +01:00
wangmiao0668000666
bd7b0ad85f fix(plugins): remove abort listener when channel runtime context is disposed (#109708) 2026-07-17 10:11:21 +01:00
Peter Steinberger
62db322715 chore(channels): mark the legacy plan-step wire branch for removal (#109773)
@openclaw/codex is force-updated with core, so string plan steps can only
reach the normalizer from a plugin pinned against an update. Record that
as a TODO instead of a standing version-skew contract.
2026-07-17 10:11:10 +01:00
krissding
4612b1692c fix: guard terminateStaleProcessesSync against non-ESRCH kill errors (#109702)
* fix: guard terminateStaleProcessesSync against non-ESRCH kill errors

The two catch blocks silently swallowed all errors, not just ESRCH.
Non-ESRCH errors (e.g. EPERM) indicate the process is still alive but
cannot be signaled — continuing as if it were killed risks leaving a
stale process on the port.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: continue stale PID cleanup after signal errors

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:06:37 +01:00
Peter Steinberger
8ff4f0161f refactor(push-web): split legacy JSON parsing out of the doctor migration
7af9358841 (#109609) pushed state-migrations.web-push.ts past the
max-lines limit (709), failing check-lint repo-wide. Extract the pure
parsing layer (legacy subscriptions/VAPID JSON -> validated shapes) into
state-migrations.web-push-parse.ts; the migration module keeps
detection/claiming/DB import. No behavior change; 23/23 module tests
green.
2026-07-17 02:03:50 -07:00
krissding
af469c85cf fix(cli): guard secrets plan JSON.parse against malformed input (#109721)
* fix(cli): guard secrets plan JSON.parse against malformed input

readPlanFile reads a user-specified file and parses it with JSON.parse
without a try-catch. A malformed or corrupted plan file produces a raw
SyntaxError that is not user-actionable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: tighten malformed secrets plan proof

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:00:35 +01:00
Wynne668
07a36f6eda fix(config): preserve Unicode in validation received values (#109664)
* fix(config): preserve Unicode in validation received values

* test: tighten config diagnostic truncation proof

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

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 01:53:19 -07:00
mushuiyu886
7af9358841 fix(push-web): ignore blank VAPID environment overrides (#109609)
* fix(push-web): ignore blank VAPID environment values

* fix: normalize migrated web push VAPID inputs

Co-authored-by: mushuiyu886 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 01:48:55 -07:00
Peter Steinberger
92e5a10f1a fix(doctor): diagnose ignored web fetch proxy settings (#109778)
* fix(doctor): diagnose direct web fetch proxy routing

* test(doctor): cover proxy diagnostic through public API

* test(doctor): validate emitted proxy diagnostic type
2026-07-17 01:24:32 -07:00
Peter Steinberger
edcf3131ad test(gateway): stop background plugin reloads from wiping test task runtimes (#109801)
Root cause of the flaky 120s timeout in "logs a swallowed finalize error
without blocking the background run" (CI run 29559328261, shard
agentic-gateway-methods): the preceding ACP plugin-subagent test registers a
subagent run whose completion keeps running in the background after the test
ends. That leaked chain (completeSubagentRunAttempt ->
emitSubagentEndedHookForRun -> ensureSubagentRegistryPluginRuntimeLoaded ->
ensureRuntimePluginsLoaded -> loadOpenClawPlugins) starts by calling
clearActivatedPluginRuntimeState(), which clears the process-wide detached
task lifecycle runtime registration. When it lands between the next test's
setDetachedTaskLifecycleRuntime(spy) install and that test's background
finalize, finalizeTaskRunByRunId re-reads the registration at call time,
falls back to the default executor, and finalizes the run successfully - so
the finalize spy is never called while the run itself completes with an ok
frame.

The prior event-driven rework (#109653, 883995f08d) could not fix this: it
only waits longer for a spy call that never comes. The older 2s
waitForAssertion flake ("expected 1 call, got 0") was the same mechanism.

Fix at the harness boundary: gateway agent handler tests now pin the
subagent-registry deps with a no-op ensureRuntimePluginsLoaded (matching
subagent-registry's own suites), applied at harness setup, in the shared
afterEach, and through the one wholesale deps override, so no leaked
ended-run hook can reload the plugin runtime and clear a later test's
runtime seam mid-test.

Proof:
- Deterministic repro (temporary env-gated interleaving patch in
  subagent-registry.ts, not committed): hold the ACP plugin-child run's
  ended-hook load until the next finalize-only runtime registration appears,
  then reload synchronously. Pre-fix this reproduces the exact CI failure
  (target times out at 120000ms; registration observed ABSENT right after
  the reload). Post-fix, with the identical forced interleaving, all 238
  tests pass and the registration stays present.
- Stress post-fix: 10x agent.test.ts and 5x src/gateway/server-methods with
  OPENCLAW_VITEST_MAX_WORKERS=6 - 0 failures (3765 tests per shard run).
- The same wipe-then-re-register window exists in prod plugin activation
  (loadOpenClawPlugins cache-miss path); flagged separately for an
  owner-reviewed atomic-swap follow-up rather than bundled here.
2026-07-17 01:16:34 -07:00
Peter Steinberger
4ecd85e0b7 fix: keep healthy channel accounts running when one credential fails (#109766)
* fix(secrets): isolate channel account credentials

* fix(secrets): normalize Feishu default ownership

* fix(feishu): preserve accountless secret ownership

* fix(matrix): keep accountless top-level refs active
2026-07-17 01:12:18 -07:00
Peter Steinberger
e693d279b3 fix: Bedrock ARN region routing, Copilot device-flow pacing, TUI input fixes (#109740)
* build(deps): bump terminal UI library to 0.80.9

* fix(plugins): Bedrock ARN region routing, stop-reason detail, and Copilot device-flow pacing
2026-07-17 01:09:29 -07: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
Peter Steinberger
543244e7bb perf(ci): remove the anthropic-cli jiti stall and stripe the full-plan whales (#109769)
* perf(sdk): load Claude CLI identity from a narrow plugin artifact

src/plugin-sdk/anthropic-cli.ts snapshots CLAUDE_CLI_BACKEND_ID at module
scope through the sync facade loader, which jiti-evaluates the full
anthropic api.js barrel on source checkouts: 130.86s of self time per
cold worker on CI (Testbox import profile), silently stalling every job
whose graph reaches cli-runner/prepare.ts. A narrow cli-api.js artifact
carries the two static facts; Testbox proof: the reliability+helpers
agents-core pair drops from 157.6s to 14.3s.

* perf(ci): stripe unit-fast and tooling node tests on the full plan

core-fast ran the import-bound unit-fast graph as one job (247s vitest,
181s module evaluation) and core-tooling as one serial job (241s); both
now stripe on the full plan like the compact plan, so the compact-only
expansion is deleted and the docker helper config rides with the
isolated shard on both plans. Group hints refreshed from main run
29551077288; stale per-file commands hints dropped (the consolidation
landed); cache-writer selection and the warm workflow track the stripe
names.

* fix(state): tolerate vanished sqlite sidecars in agent-db permission sweep

existsSync+chmodSync raced SQLite's own WAL/SHM cleanup: a checkpoint or
close between the two calls throws ENOENT (observed from the transcript
reconcile worker in server-startup-web-fetch-bind on CI). chmod directly
and swallow only ENOENT, which removes the TOCTOU window.
2026-07-17 00:58:32 -07:00
Peter Steinberger
0e792b6de3 refactor(channels): centralize inbound orchestration and remove internal compat (#109716)
* refactor(channels): centralize inbound turn orchestration

* refactor(runtime): remove stale compatibility paths

* chore(guards): reject internal deprecated API use

* refactor(channels): simplify core turn planning

* chore(guards): keep deprecated checks boundary-focused

* refactor(memory): keep modern config off compat barrel

* fix(msteams): preserve feedback learning

* test(channels): align modern inbound fixtures

* refactor(channels): finish modern inbound migration

* refactor(channels): tighten core inbound kernel

* fix(channels): preserve turn assembly narrowing

* test(sdk): keep runtime mock binding immutable

* test(matrix): isolate read policy runtime

* test(msteams): mock canonical reply factory

* test(slack): mock core inbound turn dispatch

* test(telegram): inject core session recorder

* test(signal): inject core session recorder

* test(googlechat): assert canonical inbound routing

* test(synology-chat): align core turn fixture

* fix(sdk): preserve direct DM runtime compat

* refactor(channels): own inbound envelope compat in core

* refactor(channels): trim inbound dispatch seams

* refactor(channels): remove redundant async wrappers

* test(synology-chat): type canonical dispatcher mock

* refactor(channels): remove remaining dead compat seams

* chore(sdk): refresh API baseline after rebase

* fix(channels): preserve direct DM identity metadata
2026-07-17 00:56:46 -07:00
Peter Steinberger
765bb37364 feat(setup): stream provider prepare progress to every surface (#109764)
* feat: stream provider preparation progress

* fix(android): refresh gateway method constants
2026-07-17 00:55:04 -07:00
Trevor Malone
b8d43ea49a fix(config): strip obsolete memorySearch keys before schema validation (#68664) (#68685)
* fix(config): strip obsolete memorySearch keys from defaults and list (#68664)

* fix(config): preserve canonical memory migration precedence

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 00:43:14 -07:00
Peter Steinberger
f095549d1d perf(agents): cut CLI runner reliability import cost (#109772) 2026-07-17 00:41:00 -07:00
Peter Steinberger
d26951ae9a fix(secrets): degrade stale auth profile refs on startup (#77213)
* fix(secrets): isolate unavailable auth profile refs

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* fix(secrets): retain current auth profile metadata

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* style(auth): use explicit materialized fields

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* fix(secrets): scrub skipped auth profile material

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* test(auth): separate setup fallback from secret refs

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

* fix(secrets): reuse prepared auth alias metadata

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>

---------

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
2026-07-17 00:38:35 -07:00
Peter Steinberger
2b18ef7426 feat(codex): surface native questions and goals (#109724)
* feat(codex): bridge native questions and goals

Co-authored-by: EVA <eva@100yen.org>

* fix(ui): preserve native question text encoding

* fix(codex): keep secret answers off action paths

* fix(codex): validate native action keys exactly

* fix(codex): isolate new goals and free-form answers

* style(codex): satisfy extension lint

* fix(codex): keep goal replacement non-destructive

* fix(codex): separate native goals from continuation

* fix(codex): preserve exact native answer labels

* test(codex): assert goal continuation stays disabled

* fix(codex): remove unused bridge exports

* test(codex): refresh goal feature snapshots

---------

Co-authored-by: EVA <eva@100yen.org>
2026-07-17 00:35:39 -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
tanshanshan
473dfc2e51 fix(compaction): add circuit breaker to stop token burn when summarizer unavailable (#86900)
* fix(compaction): stop repeated staged fallbacks

Co-authored-by: tanshanshan <tan.shanshan@xydigit.com>

* fix(compaction): preserve degraded summary state

* refactor(compaction): keep result state internal

* fix(compaction): cancel incomplete circuit-open runs

* chore: refresh PR checks

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 00:18:33 -07:00
Yiğit ERDOĞAN
e228a3ca3a fix: gateway.cmd launcher garbles non-ASCII profile paths on non-CJK Windows locales (#108967)
* fix(daemon): encode Windows cmd launcher to the console OEM code page

* fix(infra): unexport resolveWindowsSystemEncoding

The launcher encoder now resolves the boot-time OEM code page via
resolveWindowsOemEncoding, leaving resolveWindowsSystemEncoding with no
external importers; the dead-export ratchet (knip all-exports) fails CI
on exported-but-module-local functions.

* test(windows): cover OEM launcher encoding resolver

* fix(windows): declare launcher OEM code page

* fix(windows): fail closed on unsupported OEM pages

* fix(windows): reject CP1258 precomposition drift

* fix(windows): guard CP864 launcher syntax

* test(windows): pin OEM launcher code page

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 00:16:59 -07:00
Peter Steinberger
b64242a4a9 fix(cron): isolate unavailable webhook secret (#109739) 2026-07-17 00:10:45 -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
007d50f6ff test(commands): pin session freshness fixtures away from the daily-reset boundary (#109705) 2026-07-17 00:01:16 -07:00
Chris
35fa1f9613 fix(reply): resolve abort response prefix context (#45315)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 00:00:50 -07:00
Peter Steinberger
44569ffdda fix(agents): prevent stale replies after transcript rewrites (#109676)
* fix(agents): scope final replies to current run

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

* refactor(agents): internalize attempt helper

* fix(agents): preserve yielded turn classification

* fix(agents): preserve yielded run ownership

---------

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>
2026-07-16 23:58:43 -07:00
Abner Shang
a33ddc9dc5 fix(openai): close OAuth callback prompts cleanly (#89491)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 23:58:41 -07:00
Peter Steinberger
c13925b387 fix(webhooks): keep routes cold when SecretRefs are unavailable (#109715)
* fix(webhooks): isolate unresolved route secrets

* chore(plugin-sdk): refresh API baseline

* docs(secrets): refresh credential surface
2026-07-16 23:56:59 -07:00
Peter Steinberger
a838c68dbe feat(talk): add Gemini Live video (#109719)
Stream bounded browser camera frames directly to Gemini Live and keep camera media off the Gateway. Add lifecycle, function-calling, fake-camera E2E, and live-smoke coverage.

Co-authored-by: shushushu <1064076525@qq.com>
2026-07-16 23:55:06 -07:00
Peter Steinberger
21388da3aa perf(test): poll subagent lifecycle state faster (#109722) 2026-07-16 23:54:54 -07:00
Peter Steinberger
0097363c69 fix(secrets): keep gateway alive when web provider refs fail (#109687)
* fix(secrets): isolate unavailable web providers

* fix(secrets): keep web result type internal

* fix(secrets): hide unavailable web selections
2026-07-16 23:48:37 -07:00
Peter Steinberger
2030ac7438 fix(acp): preserve legacy replay state during doctor repair (#109685)
* fix(acp): move legacy replay migration to doctor

* refactor(acp): use Kysely for replay migration

* style(acp): remove redundant replay coercions

* style(acp): format replay migration
2026-07-16 23:29:29 -07:00
Peter Steinberger
fb946267ae perf(test): poll gateway startup state faster (#109714) 2026-07-16 23:28:20 -07:00
Peter Steinberger
f0aa2c892f refactor(tui): unify local queue fallback admission (#109706) 2026-07-16 23:16:11 -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
Masato Hoshino
45ab24dac4 fix: queued MEDIA attachments survive delivery retries (#108969)
* fix: queued MEDIA attachments survive delivery retries

Local media carried in a legacy MEDIA: text directive was invisible to
queue staging (which reads only structured mediaUrl(s)), so the raw
directive was persisted with no queue-owned copy and a retry read the
already-deleted producer path — burning the retry budget and dropping the
attachment plus its text.

Project each source payload's effective media through the canonical
createOutboundPayloadPlan before staging and fold directive-derived local
sources into the queue copy's structured fields, so the existing spool
takes custody. The custody copy anchors both mediaUrl and mediaUrls to the
effective set so the staged copy overrides the preserved in-text directive
on replay; the rendered-batch plan is recomputed from the deduplicated
effective media to avoid count inflation. Raw pre-hook text, the copy-free
live send, the same media capability, and sensitive-media fail-closed are
all unchanged. No schema/config/TTL change.

Extends the ownership invariant from #108501 / #108502 to the legacy
MEDIA: text-directive carrier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(outbound): localize queue media custody

Trim the direct helper matrix in favor of end-to-end queue recovery proof.

Co-authored-by: Masato Hoshino <g515hoshino@gmail.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 23:15:08 -07:00
Yuval Dinodia
73cf9a8bed fix(plugins): plugins.deny is bypassed by a mixed-case manifest id (#109237)
* fix(plugins): canonicalize manifest plugin ids to lowercase

Plugin config policy lists (plugins.deny, plugins.allow, plugins.entries)
are lowercase-normalized through normalizePluginId, but a plugin's
self-declared manifest id was only trimmed, never lowercased. A plugin
publishing "id": "Malicious-Scraper" therefore never matched an operator
denylist entry of "malicious-scraper" and fell through to default
activation, loading its hooks, channels, secret integrations, and tools.
The same gap let a mixed-case spelling evade the core reserved-id check.

Canonicalize the id at the manifest parse boundary where
PluginManifestRecord.id is minted, so every downstream policy consumer
compares against the same canonical form.

* test(plugins): prove mixed-case deny at gateway startup

* test(plugins): assert denied gateway record is absent

* test(plugins): materialize allowed secret fixture

* fix(plugins): compare a derived policy key instead of rewriting manifest identity

Manifest ids stay exactly as declared. Deny, allow, and per-entry checks now
compare a lowercase policy key derived at each enforcement boundary, matching
the lowercase-normalized config lists.

The previous approach lowercased PluginManifestRecord.id at the parse boundary.
That id is also matched against the plugin runtime export id, and a mismatch is
a hard load failure, so an existing plugin declaring the same mixed-case id in
both its manifest and its runtime export would stop loading after upgrade.

The Gateway fixture now declares a mixed-case manifest id with a matching
mixed-case runtime export, covering that upgrade case, and drops the allowlist
that previously scoped discovery by a lowercase id and masked the denylist
behavior under test.

* fix(plugins): close mixed-case policy gaps

* test(plugins): use tracked policy fixture temp dir

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 23:13:13 -07:00
Peter Steinberger
c63184ee9a fix(acp): persist failed bound turns so transcripts match the channel (#109683)
* fix(acp): persist failed bound turns so transcripts match the channel

A bound ACP turn that failed delivered an error reply to the channel but
wrote nothing to the session transcript: persistAcpDispatchTranscript ran
only on the success path, and turnPromptText was block-scoped inside the
try so the catch could not reach it. The bound transcript then silently
diverged from what the user saw, and the next turn resumed from history
that never mentioned the failure. Persist failures were also swallowed at
verbose level.

Persist exactly once, after the turn's outcome settles:
- success writes after finalization, so a finalizer failure is no longer
  recorded as a clean success;
- failures record the streamed output ahead of the error text, snapshotted
  before delivery so the accumulator cannot fold the error in twice;
- a dispatch flag (not prompt-text truthiness) gates the failure write, so
  attachment-only turns are covered and pre-dispatch setup failures do not
  mint blank-prompt records.

Found while live-testing the ACP connectors: codex and gemini bind lanes
pass 5/5, claude times out with turns that complete but never appear in the
bound transcript. This fixes the silent-divergence class and makes that
failure observable; the claude-specific trigger is tracked separately.

* fix(acp): narrow acp resolution before reading meta in the shared persist helper
2026-07-16 23:12:58 -07:00