Skip to content

[Feature & Refactor] LeapFlow Gateway & App Connector Robustness Enhancements#16

Merged
wangxingjun778 merged 14 commits into
mainfrom
feat/core_loop
Jul 14, 2026
Merged

[Feature & Refactor] LeapFlow Gateway & App Connector Robustness Enhancements#16
wangxingjun778 merged 14 commits into
mainfrom
feat/core_loop

Conversation

@wangxingjun778

@wangxingjun778 wangxingjun778 commented Jul 14, 2026

Copy link
Copy Markdown
Member

PR: LeapFlow Gateway & App Connector Robustness Enhancements

This pull request strengthens LeapFlow's App Connector and gateway infrastructure by introducing platform-neutral capability health tracking, strict resource provenance, and progressive context discovery, alongside key stability and performance fixes.


Key Enhancements

  • Capability Health Ledger: Introduced a platform-neutral ledger to systematically track authorization failures and monitor integration health.
  • Resource Provenance Verification: Implemented a ResourceProvenancePool to prevent resource ID hallucination during execution.
  • Progressive Discovery: Added a capability_expand tool to enable Tier 1 model-initiated, on-demand discovery.

Bug Fixes & Stability Improvements

  • Defensive Session Handling: Added safety checks for ctx.session in teaching commands to prevent AttributeError.

  • Leak Prevention:

  • Configured CompositeEventSource to cancel background tasks upon cancellation.

  • Ensured leaked subprocesses in LarkCliEventSource are explicitly terminated on timeout.

  • Guaranteed State Saving: Wrapped checkpoint and deduplication state saves in a finally block to protect against middle-of-run failures.

  • Robust Data Handling:

  • Updated send_reply to handle empty chunks gracefully and avoid returning None.

  • Resolved string formatting bugs in the hub command handler.

Performance & Compatibility Optimizations

  • Backward Compatibility: Added fallback try-except blocks to ensure older, custom file gates continue to function seamlessly.
  • Database & Engine Caching:
  • Cached capability manifests in engine.py to reduce redundant processing overhead.
  • Batched database writes in checkpoint_store.py for high-throughput insert optimization.

wangxingjun778 and others added 13 commits July 14, 2026 11:16
…kpoint, session persistence, callbacks, normalizers, unified inbound

Close all design gaps for the IM bidirectional message processing architecture:

- Add 4 Feishu message reading actions (im.list_messages, im.get_messages,
  im.search_messages, im.list_thread_messages) to feishu.yaml action pack
- Implement EventDeduplicator (LRU-based) in consumer loop for idempotency
- Add DuckDB-backed GatewayCheckpointStore for event source resume on restart
- Wire ConversationStore into GatewayRouter for persistent session history
- Parse card.action.trigger into InboundCallback with full field extraction
- Add callback handler pipeline (GatewayServer → GatewayRouter.handle_callback)
- Create CompositeEventSource for multi-event-key subscription merging
- Update LarkCliEventSource to default-subscribe both im.message.receive_v1
  and card.action.trigger via CompositeEventSource
- Implement GatewayEventBridge to publish IM signals to EventBus for the
  learning pipeline (PatternMiner, Copilot)
- Add TelegramEventNormalizer and DingTalkEventNormalizer with auto-registration
- Create TelegramPollingEventSource and DingTalkWebhookEventSource as
  BackendEventSource implementations
- Unify inbound architecture: remove adapter.on_message direct callback,
  route all platforms through normalizer → trigger policy consumer loop

Co-authored-by: Cursor <cursoragent@cursor.com>
P0 — @ALL mention detection:
  - Normalizers (Feishu/Telegram/DingTalk) now detect @all/@所有人
    and treat it as bot_mentioned for trigger policy routing.

P0 — Processing indicators:
  - GatewayRouter signals start/done/error phases via IndicatorFn.
  - Context wires it to platform reactions (OnIt emoji).
  - Fire-and-forget with 5s timeout — never blocks message processing.

P0 — Streaming reply:
  - GatewayRouter supports progressive message editing via StreamSendFn.
  - Sends initial message, then updates in-place as LLM chunks arrive.
  - Throttled updates (1.5s interval, 40-char minimum delta).
  - Falls back to non-streaming when tools are active.

P1 — Media inbound (image/file/audio):
  - Feishu normalizer extracts MediaAttachment with file_key for deferred
    download via im.download_resource action.
  - Telegram normalizer extracts photo/document/audio/video/voice/sticker.
  - Non-text messages produce synthetic [type] text + media tuple.

P1 — Extended event keys:
  - Default Feishu subscription now includes reaction, read receipt,
    and bot lifecycle events for richer signal observation.

P1 — New Feishu actions:
  - im.reply_message, im.update_message, im.add_reaction,
    im.remove_reaction, im.update_card, im.download_resource.
  - FeishuAdapter.send() uses im.reply_message when reply_to_id is set.

P2 — User authorization:
  - TriggerPolicy gains allowed_users field (frozenset whitelist).
  - Context wires allowed_users/blocked_users/keywords/rate limits
    from platform options (config-driven, no hardcoding).

P2 — Outbound text chunking:
  - GatewayServer.send_reply() auto-chunks text exceeding
    adapter.max_message_length at paragraph/sentence boundaries.

P2 — Persistent dedup:
  - DuckDBDeduplicationStore saves/loads event_ids across restarts.
  - EventDeduplicator gains load_from_store/save_to_store methods.
  - Consumer loop loads on start, saves on cancellation.
  - Auto-prunes entries older than 7 days.

P2 — Thread parent context:
  - Feishu normalizer extracts parent_id → reply_to_id.
  - GatewayRouter fetches parent text via ContextFetchFn and prepends
    "[Replying to: ...]" context for the LLM.

P2 — Markdown/rich format detection:
  - send_reply() detects markdown formatting (code blocks, headers,
    lists, bold, links) and sets format_hint metadata.
  - Adapters can use format_hint to select richer message types.

Tests: 467 passed (12 new tests for @ALL, media, reply_to_id,
       allowed_users, text chunking, and markdown detection).
Co-authored-by: Cursor <cursoragent@cursor.com>
…dempotency

Root-cause fix for two classes of platform_action failures:

1. Payload structural errors (fields at wrong level, missing required fields):
   - Add normalize_payload() that lifts misplaced business fields into payload
   - Enhance ValidationResult with failure_code, missing_fields, recovery_hint
   - Enhance Capability Index to show per-action payload signatures with required markers

2. Duplicate side-effect execution (LLM repeating send/write across turns):
   - Add task-scoped side-effect dedup in platform_action_handler (before approval)
   - Add completed:true + execution_note in successful send/write/execute results
   - Add "Side-effect action rule" to system prompt constraining LLM behavior
   - Add platform_action evidence builder with COMPLETED/ALREADY_EXECUTED markers
   - Add loop exit bias nudging LLM to stop after side-effect completion

Design: defense-in-depth with Prevention (prompt/result signals) + Protection
(deterministic dedup guard). Read actions are never subject to dedup.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add a human-curated alias table as a remedial resolution layer between
formatting normalization and "unknown" fallback. This transparently maps
common LLM naming drift (read_file → file_read, execute_command → shell_run,
etc.) to canonical tool names without requiring an LLM retry round-trip.

Design:
- Alias table declared in name_resolver.py as TOOL_NAME_ALIASES (Dict[str,str])
- Validated at registry construction: only entries targeting actual specs are kept
- Resolution priority: exact > normalized > bridge prefix > alias > unknown
- New ResolutionStatus "aliased" for auditability in logs and TUI
- auto_executable=True — aliases are proven 1:1 semantic equivalences
- Table is intentionally small; primary reliance is on LLM schema adherence

Extensibility:
- Adding a new alias = one line in TOOL_NAME_ALIASES
- Adding a new LLM or tool = no change to resolution logic
- Gateway router also uses the alias table for its scoped registry

Co-authored-by: Cursor <cursoragent@cursor.com>
…ti-hallucination

Defense-in-depth against LLM hallucinating resource IDs after authorization
failures. Addresses the critical flow: list_chats fails → model fabricates
chat_id → approval passes with insufficient info → send times out.

P0 — Platform-Level Degradation:
- CapabilityHealthLedger now tracks platform degradation: when a hard
  authorization failure (admin_required) is recorded, ALL side-effect
  actions on that platform are blocked by feasibility check, regardless
  of whether their specific capability has been tested.
- Adds llm_instruction field to blocked responses, explicitly instructing
  the model to stop and report the failure rather than guessing.
- Transient failures (timeout, rate-limit) do NOT trigger degradation.
- clear(platform) removes degradation when permissions are fixed.

P1 — Resource Provenance Tracking:
- New ResourceProvenancePool (session-scoped) registers resource IDs
  (chat_id, message_id, etc.) observed from successful API responses.
- Before side-effect actions, resource fields in the payload are checked
  against the pool: VERIFIED (seen from API), UNVERIFIED (pool populated
  but ID not found → likely hallucinated), UNKNOWN (pool empty).
- UNVERIFIED triggers provenance warnings shown in approval detail and
  elevates risk_hint to 0.9 for the approval gate.
- Pool populated automatically from execute_platform_action results by
  scanning for fields matching declared resource_fields across specs.

P0 — Anti-Hallucination Context Signals:
- System prompt: "Resource identifier provenance rule" — explicitly
  forbids fabricating IDs when read actions have failed.
- ToolEvidenceBuilder: propagates llm_instruction and platform_degraded
  fields to LLM context for auth failure results.
- Feasibility responses include stop-signal for LLM consumption.

All layers are platform-neutral and auto-extend to new platforms/actions.

Co-authored-by: Cursor <cursoragent@cursor.com>
…l-closed defaults

Core PCD redesign (context_disclosure.py):
- Replace natural-language tool-name guessing with a manifest-driven planner:
  disclosure decisions now derive only from structural facts (capability
  manifests, slash commands, context posture, recent failures, prior-turn
  tool-category continuity).
- Three stable levels: CORE (always-on Tier 0 index + Tier 0.5 read-only
  whitelist), EXPANDED (+ Tier 1 categories opened by structural gates),
  FULL (safety/compat fallback for high-stakes turns).
- CapabilityManifest.is_core is a static, auditable property
  (read_only risk + non-high schema cost), never a per-turn guess.
- Fail-closed unclassified fallback: tools that declare no explicit
  x_leapflow metadata and match no recognized safe keyword now default to
  "unclassified"/medium risk (non-core) instead of silently trusting them
  as "general"/read_only. text_search is explicitly whitelisted to avoid
  a regression from this tightened default.
- CORE-level reasoning stays OFF unless a Tier 1 category is open, to
  preserve the low-latency pure-chat path.

Security-relevant tool classification fixes:
- hub_tool.py / gateway_tool.py: add explicit x_leapflow metadata to all
  hub/platform/gateway tools. Their descriptions previously lacked
  distinguishing keywords, causing gateway_connect/platform_connect to be
  keyword-misclassified as "general"/read_only and silently promoted into
  the always-on core whitelist.

Tier 1 continuity fix (engine.py):
- _recent_tool_categories() previously tried to recover categories from a
  synthetic "[Called: ...]" text summary in working memory, which has no
  structured tool_calls field — Tier 1 continuity never actually fired.
  Replaced with a dedicated engine-instance state
  (_last_turn_tool_categories), reset per turn and populated from the
  turn's actual executed native tool_calls.
- _format_tool_catalog now annotates every non-core tool with its exact
  capability_expand category so the model never has to guess the string.

registry_bootstrap.py:
- capability_expand's description is now patched at import time with the
  live, computed set of non-core categories instead of a hardcoded example
  list that could drift from the real registry.

UX regression fixes:
- tui_app/stream.py: update the disclosure-tag suppression set from the
  retired "selected_tools" level to the current "core" default, so normal
  chat turns no longer show a noisy "disclosure=core" tag.

Tests:
- Rewrote test_context_disclosure.py against the new manifest/planner API,
  including a regression test pinning hub/gateway tools as explicitly
  non-core.
- Added an end-to-end regression test for Tier 1 continuity
  (test_progressive_disclosure_expands_write_category_after_prior_turn_tool_use).
- Updated stale assertions in test_agent_execution.py and
  test_tui_command_queue.py that referenced retired disclosure semantics.

514 tests pass; all modified modules compile and import standalone.
- Treat authorization blockers (access_denied, missing_scope, platform_degraded,
  blocks_approval, admin_required non-retryable failures) as hard-stop tool
  results across native/text and stream/non-stream engine paths.
- Stop remaining sequential native tool calls when a permission blocker is hit;
  classify platform/gateway/hub stateful tools as never-parallel.
- Add shared permission-failure predicates under security/permission_failures.py
  so engine and TUI use the same authority for permission recovery detection.
- Add TuiCommandStatus.BLOCKED and wire local + daemon interactive response
  labels to render permission-blocked turns as #N blocked instead of failed.
- Fix permission recovery card rendering so Rich never receives Panel(None).
- Add regression coverage for text/native hard-stop, blocked labels, command
  terminal state, and permission recovery card renderability.

Validation: py_compile modified files; 518 tests pass.
- Remove synchronous await_learning() from teach stop RPC handler to
  prevent 30s RPC timeout; distillation now runs as background task
- Sync app.prompt_mode with session state (learning/paused/idle) so
  TUI shows "● rec" recording indicator during active teach sessions
- Add learning-mode placeholder text with available teach commands
- Emit chat interaction events from engine during LEARNING mode for
  trajectory capture (user messages, tool calls, tool results, responses)
- Add CHAT_* ActionTypes to trajectory domain for recording chat demos
- Ensure RecordingProfile always activates InputTapObserver during teach
- Start ObservationDaemon on-demand when recording begins if not running
- Route daemon TUI input through both engine_chat and annotate in
  learning mode for chat-demonstration recording

Co-authored-by: Cursor <cursoragent@cursor.com>
Implement a push notification system for background task transparency:

- Add NotificationBus: lightweight async broadcast with per-subscriber
  queues, back-pressure handling, and graceful shutdown
- Add events.subscribe streaming RPC: long-lived NDJSON connection for
  daemon-to-TUI push notifications (generalizable to any background task)
- Wire session progress/completion callbacks to NotificationBus so
  distillation emits teach.progress and teach.complete events
- TUI background subscription task: renders progress in status bar
  (⚗ phase pct%) and shows completion inline notification with results
- Add /teach status command for on-demand distillation state query
- Fix _update_status() overriding prompt_mode during teach session
- Add teach.stopped notification for idle-watchdog auto-stop so TUI
  resets recording indicator when daemon times out the session
- Gate distillation on has_pending_distillation property to avoid
  misleading "started" messages when learnability check skips
- Add public SessionController properties: has_pending_distillation,
  is_distilling, recording_step_count, last_result
- Reset stale distill state on notification stream reconnection

Co-authored-by: Cursor <cursoragent@cursor.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant enhancements to LeapFlow's App Connector and gateway infrastructure, focusing on robust error handling, platform-neutral capability health tracking, resource provenance verification, and progressive context disclosure. Key additions include a new CapabilityHealthLedger to track authorization failures, a ResourceProvenancePool to prevent resource ID hallucination, and a capability_expand tool for Tier 1 model-initiated discovery. Feedback from the review highlights several critical bugs and improvement opportunities, including: preventing AttributeError by adding defensive checks for ctx.session in teaching commands; explicitly terminating leaked subprocesses on timeout in LarkCliEventSource; preventing task leaks in CompositeEventSource by cancelling background tasks on cancellation; ensuring checkpoint and deduplication states are saved in a finally block; handling empty chunks in send_reply to avoid returning None; fixing a string formatting bug in the hub command handler; ensuring backward compatibility for custom file gates by adding fallback try-except blocks; and optimizing performance by caching capability manifests in engine.py and batching database inserts in checkpoint_store.py.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/leapflow/cli/commands/slash_handlers.py Outdated
Comment thread src/leapflow/gateway/connectors/lark_event_source.py Outdated
Comment thread src/leapflow/gateway/connectors/composite_event_source.py
Comment thread src/leapflow/gateway/server.py
Comment thread src/leapflow/gateway/server.py
Comment thread src/leapflow/cli/commands/slash_handlers.py Outdated
Comment thread src/leapflow/tools/file_operations.py Outdated
Comment thread src/leapflow/tools/file_operations.py Outdated
Comment thread src/leapflow/engine/engine.py Outdated
Comment thread src/leapflow/gateway/checkpoint_store.py Outdated
@wangxingjun778 wangxingjun778 changed the title Feat/core loop [Feature & Refactor] LeapFlow Gateway & App Connector Robustness Enhancements Jul 14, 2026
@wangxingjun778 wangxingjun778 merged commit 2454da6 into main Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant