Commit Graph

32 Commits

Author SHA1 Message Date
Peter Steinberger
574d3c5213 fix: make same-chat approvals work across channels 2026-03-30 06:35:04 +09:00
Josh Avant
6ade9c474c feat(hooks): add async requireApproval to before_tool_call (#55339)
* Plugins: add native ask dialog for before_tool_call hooks

Extend the before_tool_call plugin hook with a requireApproval return field
that pauses agent execution and waits for real user approval via channels
(Telegram, Discord, /approve command) instead of relying on the agent to
cooperate with a soft block.

- Add requireApproval field to PluginHookBeforeToolCallResult with id, title,
  description, severity, timeout, and timeoutBehavior options
- Extend runModifyingHook merge callback to receive hook registration so
  mergers can stamp pluginId; always invoke merger even for the first result
- Make ExecApprovalManager generic so it can be reused for plugin approvals
- Add plugin.approval.request/waitDecision/resolve gateway methods with
  schemas, scope guards, and broadcast events
- Handle requireApproval in pi-tools via two-phase gateway RPC with fallback
  to soft block when the gateway is unavailable
- Extend the exec approval forwarder with plugin approval message builders
  and forwarding methods
- Update /approve command to fall back to plugin.approval.resolve when exec
  approval lookup fails
- Document before_tool_call requireApproval in hooks docs and unified
  /approve behavior in exec-approvals docs

* Plugins: simplify plugin approval code

- Extract mergeParamsWithApprovalOverrides helper to deduplicate param
  merge logic in before_tool_call hook handling
- Use idiomatic conditional spread syntax in toolContext construction
- Extract callApprovalMethod helper in /approve command to eliminate
  duplicated callGateway calls
- Simplify plugin approval schema by removing unnecessary Type.Union
  with Type.Null on optional fields
- Extract normalizeTrimmedString helper for turn source field trimming

* Tests: add plugin approval wiring and /approve fallback coverage

Fix 3 broken assertions expecting old "Exec approval" message text.
Add tests for the /approve command's exec→plugin fallback path,
plugin approval method registration and scope authorization, and
handler factory key verification.

* UI: wire plugin approval events into the exec approval overlay

Handle plugin.approval.requested and plugin.approval.resolved gateway
events by extending the existing exec approval queue with a kind
discriminator. Plugin approvals reuse the same overlay, queue management,
and expiry timer, with branched rendering for plugin-specific content
(title, description, severity). The decision handler routes resolve calls
to the correct gateway method based on kind.

* fix: read plugin approval fields from nested request payload

The gateway broadcasts plugin approval payloads with title, description,
severity, pluginId, agentId, and sessionKey nested inside the request
object (PluginApprovalRequestPayload), not at the top level. Fix the
parser to read from the correct location so the overlay actually appears.

* feat: invoke plugin onResolution callback after approval decision

Adds onResolution to the requireApproval type and invokes it after
the user resolves the approval dialog, enabling plugins to react to
allow-always vs allow-once decisions.

* docs: add onResolution callback to requireApproval hook documentation

* test: fix /approve assertion for unified approval response text

* docs: regenerate plugin SDK API baseline

* docs: add changelog entry for plugin approval hooks

* fix: harden plugin approval hook reliability

- Add APPROVAL_NOT_FOUND error code so /approve fallback uses structured
  matching instead of fragile string comparison
- Check block before requireApproval so higher-priority plugin blocks
  cannot be overridden by a lower-priority approval
- Race waitDecision against abort signal so users are not stuck waiting
  for the full approval timeout after cancelling a run
- Use null consistently for missing pluginDescription instead of
  converting to undefined
- Add comments explaining the +10s timeout buffer on gateway RPCs

* docs: document block > requireApproval precedence in hooks

* fix: address Phase 1 critical correctness issues for plugin approval hooks

- Fix timeout-allow param bug: return merged hook params instead of
  original params when timeoutBehavior is "allow", preventing security
  plugins from having their parameter rewrites silently discarded.

- Host-generate approval IDs: remove plugin-provided id field from the
  requireApproval type, gateway request, and protocol schema. Server
  always generates IDs via randomUUID() to prevent forged/predictable
  ID attacks.

- Define onResolution semantics: add PluginApprovalResolutions constants
  and PluginApprovalResolution type. onResolution callback now fires on
  every exit path (allow, deny, timeout, abort, gateway error, no-ID).
  Decision branching uses constants instead of hard-coded strings.

- Fix pre-existing test infrastructure issues: bypass CJS mock cache for
  getGlobalHookRunner global singleton, reset gateway mock between tests,
  fix hook merger priority ordering in block+requireApproval test.

* fix: tighten plugin approval schema and add kind-prefixed IDs

Harden the plugin approval request schema: restrict severity to
enum (info|warning|critical), cap timeoutMs at 600s, limit title
to 80 chars and description to 256 chars. Prefix plugin approval
IDs with `plugin:` so /approve routing can distinguish them from
exec approvals deterministically instead of relying on fallback.

* fix: address remaining PR feedback (Phases 1-3 source changes)

* chore: regenerate baselines and protocol artifacts

* fix: exclude requesting connection from approval-client availability check

hasExecApprovalClients() counted the backend connection that issued
the plugin.approval.request RPC as an approval client, preventing
the no-approval-route fast path from firing in headless setups and
causing 120s stalls. Pass the caller's connId so it is skipped.
Applied to both plugin and exec approval handlers.

* Approvals: complete Discord parity and compatibility fallback

* Hooks: make plugin approval onResolution non-blocking

* Hooks: freeze params after approval owner is selected

* Gateway: harden plugin approval request/decision flow

* Discord/Telegram: fix plugin approval delivery parity

* Approvals: fix Telegram plugin approval edge cases

* Auto-reply: enforce Telegram plugin approval approvers

* Approvals: harden Telegram and plugin resolve policies

* Agents: static-import gateway approval call and fix e2e mock loading

* Auto-reply: restore /approve Telegram import boundary

* Approvals: fail closed on no-route and neutralize Discord mentions

* docs: refresh generated config and plugin API baselines

---------

Co-authored-by: Václav Belák <vaclav.belak@gendigital.com>
2026-03-27 09:06:40 -07:00
clay-datacurve
7b61ca1b06 Session management improvements and dashboard API (#50101)
* fix: make cleanup "keep" persist subagent sessions indefinitely

* feat: expose subagent session metadata in sessions list

* fix: include status and timing in sessions_list tool

* fix: hide injected timestamp prefixes in chat ui

* feat: push session list updates over websocket

* feat: expose child subagent sessions in subagents list

* feat: add admin http endpoint to kill sessions

* Emit session.message websocket events for transcript updates

* Estimate session costs in sessions list

* Add direct session history HTTP and SSE endpoints

* Harden dashboard session events and history APIs

* Add session lifecycle gateway methods

* Add dashboard session API improvements

* Add dashboard session model and parent linkage support

* fix: tighten dashboard session API metadata

* Fix dashboard session cost metadata

* Persist accumulated session cost

* fix: stop followup queue drain cfg crash

* Fix dashboard session create and model metadata

* fix: stop guessing session model costs

* Gateway: cache OpenRouter pricing for configured models

* Gateway: add timeout session status

* Fix subagent spawn test config loading

* Gateway: preserve operator scopes without device identity

* Emit user message transcript events and deduplicate plugin warnings

* feat: emit sessions.changed lifecycle event on subagent spawn

Adds a session-lifecycle-events module (similar to transcript-events)
that emits create events when subagents are spawned. The gateway
server.impl.ts listens for these events and broadcasts sessions.changed
with reason=create to SSE subscribers, so dashboards can pick up new
subagent sessions without polling.

* Gateway: allow persistent dashboard orchestrator sessions

* fix: preserve operator scopes for token-authenticated backend clients

Backend clients (like agent-dashboard) that authenticate with a valid gateway
token but don't present a device identity were getting their scopes stripped.
The scope-clearing logic ran before checking the device identity decision,
so even when evaluateMissingDeviceIdentity returned 'allow' (because
roleCanSkipDeviceIdentity passed for token-authed operators), scopes were
already cleared.

Fix: also check decision.kind before clearing scopes, so token-authenticated
operators keep their requested scopes.

* Gateway: allow operator-token session kills

* Fix stale active subagent status after follow-up runs

* Fix dashboard image attachments in sessions send

* Fix completed session follow-up status updates

* feat: stream session tool events to operator UIs

* Add sessions.steer gateway coverage

* Persist subagent timing in session store

* Fix subagent session transcript event keys

* Fix active subagent session status in gateway

* bump session label max to 512

* Fix gateway send session reactivation

* fix: publish terminal session lifecycle state

* feat: change default session reset to effectively never

- Change DEFAULT_RESET_MODE from "daily" to "idle"
- Change DEFAULT_IDLE_MINUTES from 60 to 0 (0 = disabled/never)
- Allow idleMinutes=0 through normalization (don't clamp to 1)
- Treat idleMinutes=0 as "no idle expiry" in evaluateSessionFreshness
- Default behavior: mode "idle" + idleMinutes 0 = sessions never auto-reset
- Update test assertion for new default mode

* fix: prep session management followups (#50101) (thanks @clay-datacurve)

---------

Co-authored-by: Tyler Yust <TYTYYUST@YAHOO.COM>
2026-03-19 12:12:30 +09:00
Peter Steinberger
57204b4fa9 fix(gateway): surface env override keys in exec approvals 2026-03-16 23:24:32 -07:00
Peter Steinberger
91f1894372 test: tighten server method helper coverage 2026-03-13 17:57:05 +00:00
Vincent Koc
2504cb6a1e Security: escape invisible exec approval format chars (#43687)
* Infra: escape invisible exec approval chars

* Gateway: sanitize exec approval display text

* Tests: cover sanitized exec approval payloads

* Tests: cover sanitized exec approval forwarding

* Changelog: note exec approval prompt hardening
2026-03-12 01:20:04 -04:00
Peter Steinberger
68c674d37c refactor(security): simplify system.run approval model 2026-03-11 01:43:06 +00:00
Peter Steinberger
7289c19f1a fix(security): bind system.run approvals to exact argv text 2026-03-11 01:25:31 +00:00
Harold Hunt
de49a8b72c Telegram: exec approvals for OpenCode/Codex (#37233)
Merged via squash.

Prepared head SHA: f243379094
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Reviewed-by: @huntharo
2026-03-09 23:04:35 -04:00
Bob
61f7cea48b fix: kill stuck ACP child processes on startup and harden sessions in discord threads (#33699)
* Gateway: resolve agent.wait for chat.send runs

* Discord: harden ACP thread binding + listener timeout

* ACPX: handle already-exited child wait

* Gateway/Discord: address PR review findings

* Discord: keep ACP error-state thread bindings on startup

* gateway: make agent.wait dedupe bridge event-driven

* discord: harden ACP probe classification and cap startup fan-out

* discord: add cooperative timeout cancellation

* discord: fix startup probe concurrency helper typing

* plugin-sdk: avoid Windows root-alias shard timeout

* plugin-sdk: keep root alias reflection path non-blocking

* discord+gateway: resolve remaining PR review findings

* gateway+discord: fix codex review regressions

* Discord/Gateway: address Codex review findings

* Gateway: keep agent.wait lifecycle active with shared run IDs

* Discord: clean up status reactions on aborted runs

* fix: add changelog note for ACP/Discord startup hardening (#33699) (thanks @dutifulbob)

---------

Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>
2026-03-04 10:52:28 +01:00
Peter Steinberger
b9e820b7ed test(perf): cut exec approval metadata test timeout 2026-03-02 17:33:06 +00:00
Peter Steinberger
d3e0c0b29c test(gateway): dedupe gateway and infra test scaffolds 2026-03-02 07:13:10 +00:00
Peter Steinberger
155118751f refactor!: remove versioned system-run approval contract 2026-03-02 01:12:53 +00:00
Peter Steinberger
78a7ff2d50 fix(security): harden node exec approvals against symlink rebind 2026-02-26 21:47:45 +01:00
Peter Steinberger
10481097f8 refactor(security): enforce v1 node exec approval binding 2026-02-26 18:09:01 +01:00
Peter Steinberger
4894d907fa refactor(exec-approvals): unify system.run binding and generate host env policy 2026-02-26 16:58:01 +01:00
Peter Steinberger
9a4b2266cc fix(security): bind node system.run approvals to env 2026-02-26 16:38:07 +01:00
Peter Steinberger
da0ba1b73a fix(security): harden channel auth path checks and exec approval routing 2026-02-26 12:46:05 +01:00
Peter Steinberger
4a3f8438e5 fix(gateway): bind node exec approvals to nodeId 2026-02-24 03:05:58 +00:00
Peter Steinberger
d24f5c1e3a fix(gateway): fail fast exec approvals when no approvers are reachable
Co-authored-by: fanxian831-netizen <262880470+fanxian831-netizen@users.noreply.github.com>
2026-02-22 22:24:27 +01:00
Peter Steinberger
142c0a7f7d refactor: extract gateway transcript append helper 2026-02-22 14:44:19 +00:00
Peter Steinberger
a1cb700a05 test: dedupe and optimize test suites 2026-02-19 15:19:38 +00:00
Peter Steinberger
00c2308085 test(gateway): dedupe health status scope test setup 2026-02-18 12:48:10 +00:00
Peter Steinberger
31f9be126c style: run oxfmt and fix gate failures 2026-02-18 01:29:02 +00:00
Peter Steinberger
01672a8f25 Revert "Add mesh auto-planning with chat command UX and hardened auth/session behavior"
This reverts commit 16e59b26a6.

# Conflicts:
#	src/auto-reply/reply/commands-mesh.ts
#	src/gateway/server-methods/mesh.ts
#	src/gateway/server-methods/server-methods.test.ts
2026-02-18 02:18:02 +01:00
Tyler Yust
087dca8fa9 fix(subagent): harden read-tool overflow guards and sticky reply threading (#19508)
* fix(gateway): avoid premature agent.wait completion on transient errors

* fix(agent): preemptively guard tool results against context overflow

* fix: harden tool-result context guard and add message_id metadata

* fix: use importOriginal in session-key mock to include DEFAULT_ACCOUNT_ID

The run.skill-filter test was mocking ../../routing/session-key.js with only
buildAgentMainSessionKey and normalizeAgentId, but the module also exports
DEFAULT_ACCOUNT_ID which is required transitively by src/web/auth-store.ts.

Switch to importOriginal pattern so all real exports are preserved alongside
the mocked functions.

* pi-runner: guard accumulated tool-result overflow in transformContext

* PI runner: compact overflowing tool-result context

* Subagent: harden tool-result context recovery

* Enhance tool-result context handling by adding support for legacy tool outputs and improving character estimation for message truncation. This includes a new function to create legacy tool results and updates to existing functions to better manage context overflow scenarios.

* Enhance iMessage handling by adding reply tag support in send functions and tests. This includes modifications to prepend or rewrite reply tags based on provided replyToId, ensuring proper message formatting for replies.

* Enhance message delivery across multiple channels by implementing sticky reply context for chunked messages. This includes preserving reply references in Discord, Telegram, and iMessage, ensuring that follow-up messages maintain their intended reply targets. Additionally, improve handling of reply tags in system prompts and tests to support consistent reply behavior.

* Enhance read tool functionality by implementing auto-paging across chunks when no explicit limit is provided, scaling output budget based on model context window. Additionally, add tests for adaptive reading behavior and capped continuation guidance for large outputs. Update related functions to support these features.

* Refine tool-result context management by stripping oversized read-tool details payloads during compaction, ensuring repeated read calls do not bypass context limits. Introduce new utility functions for handling truncation content and enhance character estimation for tool results. Add tests to validate the removal of excessive details in context overflow scenarios.

* Refine message delivery logic in Matrix and Telegram by introducing a flag to track if a text chunk was sent. This ensures that replies are only marked as delivered when a text chunk has been successfully sent, improving the accuracy of reply handling in both channels.

* fix: tighten reply threading coverage and prep fixes (#19508) (thanks @tyler6204)
2026-02-17 15:32:52 -08:00
cpojer
8d6e345338 chore: Fix types in tests 22/N. 2026-02-17 12:23:12 +09:00
Peter Steinberger
eaa2f7a7bf fix(ci): restore main lint/typecheck after direct merges 2026-02-16 23:26:11 +00:00
ranausmanai
16e59b26a6 Add mesh auto-planning with chat command UX and hardened auth/session behavior 2026-02-16 23:58:23 +01:00
Peter Steinberger
93ca0ed54f refactor(channels): dedupe transport and gateway test scaffolds 2026-02-16 14:59:31 +00:00
Peter Steinberger
3f44ea244f perf(test): fold health + signal mention tests 2026-02-16 02:45:00 +00:00
Peter Steinberger
36b5f0c9a8 perf(test): consolidate gateway server-methods suites 2026-02-15 23:14:42 +00:00