Commit Graph

2409 Commits

Author SHA1 Message Date
Peter Steinberger 706a06eab6 refactor(channels): consolidate account logout cleanup (#130976)
* refactor(channels): consolidate account logout cleanup

* fix(channels): initialize local logout plugins
2026-08-27 09:18:11 -07:00
Peter Steinberger bdd8f33f5d fix(telegram): surface media failures in the agent-facing body (#130849) 2026-08-27 02:18:26 -07:00
Josh Lehman 26939b2708 fix(telegram): show errors when message-only agent runs fail (#129311)
* fix(telegram): visibly settle failed agent runs

* fix(reply): settle pre-output provider failures

* fix(reply): preserve visible partial fallback

* test(telegram): cover provider failure before output

* fix(auto-reply): propagate terminal run failures

* fix(telegram): silence terminal failure fallback
2026-08-27 01:51:23 -07:00
Peter Steinberger 1d28e156fc fix(telegram): preserve literal backticks in inbound code (#130800) 2026-08-27 00:58:46 -07:00
Peter Steinberger 6871fec307 fix(telegram): consolidate physical sends and preserve accepted delivery custody (#130643) 2026-08-26 23:36:17 -07:00
Peter Steinberger 63f7df85bb feat(channels): post a grounded introduction when the bot joins a group room (#130103)
* feat(channels): introduce bots when they join group rooms

* feat(channels): add Discord and Telegram join introductions

* fix(channels): isolate untrusted evidence and select allowed join targets

* refactor(channels): scope joinIntro to implementing channels

* fix(channels): keep a delivered join introduction settled when its durable commit fails

* feat(channels): read more room history and document join introductions in detail

* chore(config): regenerate bundled channel metadata after rebase
2026-08-26 21:02:26 -07:00
Ayaan Zaidi 1cb914d6bf fix(telegram): make ask_user controls native and reliable (#130262)
Make ask_user use native Telegram controls when one single-select question can be represented directly, while keeping multi-select and batch questions on the text fallback. Add native Other-to-ForceReply input, preserve Gateway-owned option ordering across Telegram, Slack, and Discord, and prevent later progress from overwriting the delivered question.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-27 08:14:39 +05:30
Peter Steinberger 98017ad71e fix(telegram): preserve complete rich message edits (#130526)
Keep one-message replacements whole through existing rich-to-plain recovery instead of selecting only the first send page. Preserve send pagination, preview clamping, and visible oversized-edit failures.

Fixes #130525
2026-08-26 17:55:29 -07:00
Peter Steinberger 395e5db41b chore(deps): refresh dependencies after seven-day cooldown (#130296)
* chore(deps): refresh cooled npm and plugin dependencies

* chore(deps): refresh cooled build and workflow tooling

* chore(deps): retain formatter compatibility

* chore(deps): retain lint compatibility
2026-08-26 16:13:18 -07:00
Peter Steinberger 549360bc42 fix(telegram): keep rejected voice attachments out of reply history (#130399) 2026-08-26 14:12:51 -07:00
Peter Steinberger 057d194372 refactor(telegram): simplify model picker callback ownership (#130336) 2026-08-26 13:39:00 -07:00
Heming Zeng 2555e9fa4e fix: stop retry storms after definitive channel rejections (#127353)
* fix(outbound): terminalize definitive channel rejections

* refactor(outbound): rethrow unclassified Slack rejections by identity

The Slack send boundary replaced every non-Error rejection with a synthetic
Error before classifying. That changed the propagated value at all four send
call sites, contradicting the stated contract that unlisted rejections keep
their previous path, and forced a compensating one-level `cause` walk in
`isSlackInvalidBlocksError` so the downstream `invalid_blocks` fallback could
still match. The guard's second operand was also dead: `isRecord` accepts Error
instances, so `!(err instanceof Error) || !isRecord(err)` never reached its
right side for a plain object.

Classify off the raw value and rethrow unclassified rejections by identity;
the `cause`-walking compensator and its test go away with it. Distill the
Telegram migration classifier's three-state result object into a
message-or-nothing, and document the description-first and 52-bit id contracts
inline.

Production surface for the PR drops from +71/-11 to +62/-8.

* test(agents): remove clock-tick race from workspace bootstrap ctime coverage

The in-place-edit case added in #127769 assumes restoring mtime leaves ctime as
the only changed stat field, and that it therefore differs. Linux and macOS
stamp ctime from a coarse per-tick clock, so an edit landing in the same tick as
the cached stat leaves ctimeMs equal: the ctime-only scenario never occurs, the
cache correctly serves its entry, and the assertion fails. Measured 199/200
identical ctimes in a tight loop; the test failed 1 in 8 local runs and broke
checks-node-compact-large-14 on CI.

Re-touch until the kernel advances ctimeMs, then assert mtimeMs and size are
unchanged so the scenario is provably ctime-only. Stripping ctimeMs from the
cache identity still fails the test.

* fix(slack): keep post-dispatch upload completion rejections ambiguous

PlatformMessageNotDispatchedError is a provider assertion that no
recipient-visible send began, and its contract says never use it after an
ambiguous send. files.completeUploadExternal runs after onPlatformSendDispatch
and is the one-time share operation, so a rejection there cannot prove the file
was never shared however definitive its code reads.

Drop the permanent-rejection classifier from that call and keep it on the
pre-dispatch calls only (chat.postMessage, files.getUploadURLExternal,
resolveChannelId). The upload test that pinned the old behavior asserted
onPlatformSendDispatch had already fired, which is exactly the condition that
forbids the claim; it now pins ambiguity instead.

Also widens the workspace bootstrap ctime wait to a 1s deadline and reshapes it
as a while loop, so a coarser filesystem tick cannot exhaust the bound.

* test(slack): prove permanent rejection recovery

* fix(test): stabilize Slack channel action routing

* fix(test): retain channel parity for precise targets

* refactor(outbound): drop unrelated test-routing changes

* fix(telegram): require Bot API error code for migration rejection

* test: repair Telegram tuples and preserve Slack test routing

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 13:16:48 -07:00
Peter Steinberger 99a02bf115 feat(approvals): typed approval scope summaries on channel cards (#130116)
* feat(approvals): typed approval scope summaries on channel cards

Approval owners can attach a closed ApprovalScope union (message-send,
payment, external-post) describing an action's blast radius. The gateway
sanitizes it once at the producer boundary, the core view model renders a
Scope metadata row so Slack/Discord/Google Chat cards show it unchanged,
shared text builders cover Telegram/WhatsApp/Signal/iMessage/Matrix, and
the durable presentation carries it additively for operator surfaces.
Scope is display-only, never authorization; missing scope keeps today's
cards.

* fix(approvals): emit native ApprovalScope union and clamp recipient previews

Name the three scope variants as registered protocol schemas so the Swift
generator emits the ApprovalScope discriminated union the presentation
structs reference, and commit the regenerated GatewayModels.swift. Clamp
recipient previews to the declared recipientCount at the sanitize boundary
so a count of 1 with 2 previews can no longer render inconsistently.
Addresses both ClawSweeper findings on #130116.

* refactor(approvals): extract text sanitizer to break the exec-approvals import cycle

check:architecture flagged approval-scope joining the exec-approvals SCC
through exec-approval-command-display. Move the self-contained display
sanitizer into a leaf module (exec-approval-text-sanitize) with no
exec-approvals imports and migrate all sanitize importers; command-display
keeps only the payload-typed command/preview resolver.

* chore(plugin-sdk): ratchet public surface budgets down after sanitizer extraction

The approval display sanitizers left the publicly reachable SDK graph when
they moved to the exec-approval-text-sanitize leaf: exports 4343 -> 4338,
callable exports 2582 -> 2578. Shrink-only budget pin.
2026-08-26 12:13:49 -07:00
Dallin Romney 70838da513 fix(test): refresh Telegram dispatch runtime mocks (#129778)
* fix(test): refresh Telegram dispatch runtime mocks

* test(telegram): drop obsolete timeout dead-letter scenario (#129785)
2026-08-26 09:55:17 -07:00
Ayaan Zaidi fc8a56daad fix(telegram): show buttonless ask-user prompts (#130200)
Telegram progress streaming treated buttonless ask-user replies as transient progress, so multi-question prompts could disappear without a visible delivery. Keep ask-user payloads on the durable question path and cover the owner boundary with a regression test.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-26 22:17:00 +05:30
Peter Steinberger 60e3d5f194 fix: prevent Feishu and Mattermost suite collection stalls (#130142)
* test(extensions): narrow ingress state import graph

* test(extensions): migrate ingress-only state imports

* test(extensions): sync xai ingress boundary alias

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-26 08:00:58 -07:00
Peter Steinberger 4151625001 fix(channels): restore retry accounting for abandoned ingress (#130077) 2026-08-26 05:02:30 -07:00
jchoi-atn 880a2a6299 fix(telegram): requeue aborted ingress claims (#122864)
Requeue Telegram ingress claims when their owner aborts before adoption, without spending retry attempts or misclassifying late aborts as delivery failures. During managed shutdown, drain active embedded model and tool runs before exit, with a 330-second generated systemd stop budget for the 315-second cooperative gateway drain.

Co-authored-by: jisubi <jisubi@gmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-26 15:27:22 +05:30
datenpapst 34694d4279 fix(telegram): resolve General topic session lanes from the cached forum flag (#126656)
Use the cached Telegram forum flag to keep General-topic updates on their `topic:1` session lane during admission and durable-row reconciliation. This prevents the session-init retry loop while preserving explicit forum hints.

Co-authored-by: datenpapst <94785785+datenpapst@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-26 14:47:11 +05:30
gaoanze888 24f4f2b486 fix(telegram): preserve rich message chunk limits before outbound chunking (#129292)
Preserve rich Telegram responses by resolving the account limit before outbound chunking, while keeping explicit legacy HTML at the existing 4,000-character limit.

Co-authored-by: gaoanze <gaoanze@meituan.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-26 13:40:02 +05:30
Peter Steinberger e8d1ee8e18 fix(telegram): honor explicit reaction message targets (#129932) 2026-08-26 00:05:00 -07:00
Peter Steinberger 580210423c fix(reply): prevent private prompt context leaking into delivered replies (#115745)
* fix(reply): redact private prompt context before delivery

Protect final and streaming replies from exact copied inbound prompts, including same-line, fenced, quoted, and partial streaming variants. Preserve safe literal examples and suppress empty exec-output placeholders. Fixes #78177.

Co-authored-by: SnowSky1 <3060176569@qq.com>

* test(telegram): own reply privacy delivery integration

Move real Telegram HTTP privacy regressions into the plugin-owned test graph and drive finalized inbound dispatch through the public SDK.

Co-authored-by: SnowSky1 <3060176569@qq.com>

* fix(reply): redact multiline quoted private prompt context

Recognize standard, indented, and nested Markdown blockquotes in final replies and withhold every incremental quoted streaming prefix before private history can reach Telegram.

Co-authored-by: SnowSky1 <3060176569@qq.com>

* fix(reply): redact decorated private prompt streams

Match exact prompt-owned Markdown formatting per line and withhold every streamed prefix, including headings, indented code, list continuations, mixed wrappers, repeated markers, and safe same-line text.

Co-authored-by: SnowSky1 <3060176569@qq.com>

* fix(reply): redact carriage-return prompt copies

Accept every source-normalized line-ending variant before private context reaches final replies, streaming, or Telegram delivery.

Co-authored-by: SnowSky1 <3060176569@qq.com>

* fix(reply): bound streamed private prompt candidate scans

Reject non-marker candidates before allocating suffixes and fail closed on repeated verified marker floods to prevent quadratic streaming work.

Co-authored-by: SnowSky1 <3060176569@qq.com>

* fix(reply): keep prompt-line character extraction type-safe

Use the canonical non-empty source-line character once so strict core, test, lint, and plugin boundary compilers agree without changing privacy behavior.

Co-authored-by: SnowSky1 <3060176569@qq.com>

---------

Co-authored-by: SnowSky1 <3060176569@qq.com>
2026-08-25 23:39:31 -07:00
Peter Steinberger f4ebfd59a7 test(telegram): remove duplicate durable target case (#129883)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b5-3918-749f-90bd-5c9ac1dced16

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 22:12:29 -07:00
sunlit-deng bd474922cf fix(telegram): describe reaction emoji syntax (#129080)
* fix(telegram): describe reaction emoji syntax

* fix(telegram): keep reactions cross-channel

* test(telegram): verify disabled reactions remove emoji guidance

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 22:00:28 -07:00
Parker Fawcett 9234b9f566 fix(telegram): route commentary through one frozen progress owner (#128259)
* fix(telegram): route commentary through one frozen progress owner

Telegram progress mode enabled both the commentary-capable draft and
durable commentary payloads without supplying the shared
shouldDeliverCommentaryPayloads owner callback, so core defaulted
durable delivery on while the draft also rendered each completed
preamble (#128038). Wire the callback to the same verbose-visibility
slot core freezes at turn start, gated exactly when the compositor can
render interleaved commentary lines, mirroring the Slack/Discord
wiring from #121009. Commentary-disabled configs keep today's
durable-only path unchanged.

Closes #128038

AI-assisted (Claude); regression tests fail pre-fix and pass post-fix.

* test(telegram): cover commentary ownership across streaming modes

---------

Co-authored-by: Parker Fawcett <Parkerscottfawcett@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 21:11:22 -07:00
Peter Steinberger d670f20be2 test(telegram): remove duplicate reaction case (#129848)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b5-3918-749f-90bd-5c9ac1dced16

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 21:10:22 -07:00
Peter Steinberger 8954634b15 fix(telegram): keep long model names selectable (#114472) 2026-08-25 20:17:24 -07:00
Peter Steinberger 6f61184d1e fix(telegram): support polls lasting up to seven days (#129461) 2026-08-25 17:36:11 -07:00
Peter Steinberger 433cf95d71 fix(telegram): preserve sent replies when required pins fail (#129342) 2026-08-25 07:20:39 -07:00
Peter Steinberger 474d7855e4 fix(telegram): preserve exact whitespace in selected reply quotes (#129254) 2026-08-25 06:45:57 -07:00
Peter Steinberger 4dc7bb7411 chore(deps): refresh dependencies after seven-day cooldown (#129187)
* chore(deps): refresh dependencies after cooldown

* fix(gateway): emit append-only Responses content events

* chore(deps): retain unverified Sherpa runtime
2026-08-25 05:00:46 -07:00
Han Yang 15826de945 fix(telegram): honor human delay for streamed replies (#69022)
Punchcard-Session: calm-brook-harbor-jm
2026-08-25 18:25:35 +08:00
Peter Steinberger c5d1cb38e2 fix(channels): attachment filenames disappear from model context (#129140)
* fix(channels): preserve inbound attachment filenames

Fixes #128956

* test(discord): verify names on successfully downloaded media

* test(discord): verify referenced attachment filenames

* fix(telegram): preserve accepted resolved-media shapes
2026-08-25 02:15:34 -07:00
Peter Steinberger 0903eaddfb fix(telegram): deduplicate state migration targets (#129096) 2026-08-25 02:07:47 -07:00
Peter Steinberger 2a39c50227 fix: make full verification hermetic across local environments (#128777)
* test: harden full verification fixtures

* test: resolve main fixture overlap
2026-08-24 13:26:00 -07:00
ClawSweeper 29f39affc2 fix(agents): resolve terminal from admitted gateway (#128348)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-08-24 12:46:14 -04:00
Peter Steinberger 15e9bea3cb refactor(telegram): unify interactive keyboard rendering (#128728)
* refactor(telegram): unify interactive keyboard rendering

* chore(telegram): ratchet removed keyboard assertion
2026-08-24 06:24:36 -07:00
Peter Steinberger 234df15a6d chore: refresh dependencies after seven-day cooldown (#128414)
* build(deps): refresh dependencies after cooldown

Apply dependency, toolchain, action, image, and exact tool updates released by the inclusive 2026-08-16 seven-day cutoff. Adapt owner boundaries for the resulting CUA, logging, Teams, Markdown, native, and test-harness contract changes while retaining versions blocked by upstream compatibility constraints.

* fix(ui): align markdown renderer env typing

* fix(deps): align postcss and mistral peer contracts

* fix(deps): repair refreshed dependency contracts

* fix(deps): retain tslog startup budget

* fix(ci): verify Android tools with SHA-256

* fix(ci): fence Android SDK cache version
2026-08-24 03:01:54 -07:00
Peter Steinberger b84292cec8 fix(telegram): preserve accepted rich fallback reply chunks (#128622) 2026-08-24 02:23:24 -07:00
Rocco Russo 235b693ea4 fix(telegram): accept threadName for topic actions (#99505)
Punchcard-Session: amber-lantern-timber-w7

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-24 01:07:29 -07:00
SunnyShu 02b8ed7b02 fix(channels/turn): clear pending history on error paths (#123193)
Failed channel turns could leave caller-owned pending group history in the next prompt. Finalize it on every terminal path, and filter Telegram rolling context while preserving explicit reply ancestry.

Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-24 12:29:55 +05:30
Peter Steinberger 3202183b2b fix(telegram): finalize answered media captions correctly (#128526) 2026-08-23 23:37:25 -07:00
Peter Steinberger 2aa5eee34e feat(channels): custom emoji discovery via emoji-list across Discord, Slack, Telegram (#128435)
* feat(channels): custom emoji discovery via emoji-list across Discord, Slack, Telegram

Make custom emojis discoverable by the agent. The message tool's emoji
param now documents custom-emoji syntax per channel (gate-aware, only
naming emoji-list when the action is actually advertised). Discord
emoji-list defaults guildId from the current conversation and returns
reaction-ready { name, identifier, animated? } entries; Slack returns
normalized shortcodes with aliasOf. Telegram gains emoji-list backed by
one canonical allowed-reactions owner (getChat available_reactions,
custom_emoji entries preserved), numeric custom-emoji reactions, and
replaces the dead 'reaction disallow list' error advice with a bounded
sample of the chat's allowed reactions.

* test(channels): expect telegram emoji-list provider-owned read gate in plugin shape contract

* test(telegram): prove emoji-list authority chain via mock-gateway e2e

Ephemeral gateway + mock Bot API + mock OpenAI provider: current-chat
emoji-list returns normalized standard and custom_emoji identifiers with
exactly one getChat call; a delegated cross-chat request is rejected with
the conversation-binding error and zero Bot API requests reference the
foreign chat.
2026-08-23 20:39:06 -07:00
lsr911 5527dfea5e fix(telegram): bound invalid allowFrom warning dedupe (#109646)
Punchcard-Session: clear-valley-lantern-qm
2026-08-23 18:07:23 -07:00
Peter Steinberger 629e00776c fix(telegram): preserve business callback deletion ownership (#128358) 2026-08-23 14:12:38 -07:00
Peter Steinberger f256c63526 fix(telegram): preserve inbound Markdown link destinations and labels (#128297) 2026-08-23 11:09:36 -07:00
Peter Steinberger 000aea1d7a perf(telegram): reuse prepared outbound thread params (#128308)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f5-984a-7628-a30c-491c166ff247

Co-authored-by: Amp <amp@ampcode.com>
2026-08-23 11:05:00 -07:00
zengLingbiao dd9a1bdca6 fix(telegram): align Unicode table fallbacks (#117890)
Punchcard-Session: ember-lantern-willow-yk

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-23 09:18:55 -07:00
Peter Steinberger 3b14c819e6 fix(telegram): preserve accepted media delivery after failures (#128181) 2026-08-23 04:57:50 -07:00
synth 5e1a28bb56 fix(outbound): prevent duplicate sends from proven-not-sent message-tool failures (#124310)
A message-tool send that failed with proven-not-sent evidence (pre-connect
ECONNREFUSED/ETIMEDOUT, PlatformMessageNotDispatchedError) was retried twice:
the model resent it after seeing the error, and the durable outbound queue
row stayed replay-eligible, so the reconnect/poll drain sent it again.

Record retry ownership at the two producers of model-authored sends and
dead-letter caller-owned rows in the queue executor:

- in-process sends derive `deliveryRetryOwner: "caller"` from
  `actionOrigin: "message-tool"` in message-action-send;
- gateway-owned plugin sends (telegram runs `message.action` in gateway
  mode) derive it from the signed agent-runtime turn context
  (`runtimeAgentId`) in the gateway handler and forward it through
  ChannelMessageActionContext into the plugin's durable send.

Reporting-only callers (CLI, RPC clients, cron reusable intents) carry no
owner and keep recovery's replay (#100979). Remote gateway mode mints no
runtime identity and keeps the replayable row; tracked as a follow-up.

Fixes #124279

Co-authored-by: synthclaw <synthalorian@gmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-23 16:02:20 +05:30