v2026.06.10#409
Merged
Merged
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
fix(log): restructure log directory retention
Persist and resolve TDP service origins without /config/api or /api/v1 segments. Add handler and secrets normalization with tests, fix TDP plugin test paths, and remove obsolete docs.
* feat(workspace): treat jsonl as text and stabilize Files tab loading Add .jsonl to workspace text extensions with API/UI coverage, and fix racey directory loads plus unstable toast deps that re-triggered list fetches. * fix(workspace): cap text preview size and disable edit when truncated Limit workspace/memory file reads via FLOCKS_WORKSPACE_MAX_READ_BYTES (default 2MB), return truncation metadata, and show a read-only preview banner in the WebUI.
* fix(session): recover orphaned running tools after server restart Mark persisted running tool parts as interrupted after unexpected server exits so session history no longer shows stale in-progress tools. Add startup, session-read, and session-loop recovery coverage with regression tests for idle and busy sessions. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(session): avoid duplicate orphan tool scans in message listing Reuse preloaded message parts during orphan tool recovery so GET /message no longer performs a redundant scan before returning results.
Extract shared graph layout for branch/loop routing, add edge property panel and join conflict settings, and refresh node/edge styling in the editor.
* feat(workflow): unify trigger integrations and simplify setup Make workflow.json the source of truth for trigger definitions and consolidate the workflow integration UI around API publishing plus four trigger entrypoints. This removes legacy trigger resurrection and streamlines the trigger configuration experience. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(workflow): route ingest triggers through unified dispatcher Wire Kafka and Syslog managers through EventDispatcher so filter, mapping, and trigger IDs match unified definitions. Add webhook HMAC verification, singleton trigger validation, public webhook auth bypass, and runtime adapter reload when custom trigger config changes. Co-authored-by: Cursor <cursoragent@cursor.com> * chore: move contributing guide to root and ignore docs/ Add docs/ to gitignore, stop tracking local documentation, and point README links at CONTRIBUTING.md. Simplify workflow trigger editor UI by removing preview/test mapping panels and unused adapter controls.
- Enable MULTI_GROUP_ENABLED by default in backend (env var to opt out) - Refactor DeviceIntegration page with left sidebar for room navigation - GroupSidebar with inline create / rename / delete for rooms - "All Rooms" aggregate view with collapsible per-room sections - Collapse-all / expand-all toggle when multiple rooms are present - Fix sidebar height: route /devices as fullscreen to bypass min-h-full wrapper that breaks flex height propagation chain - Room assignment in DeviceConfigPanel: dropdown (editable) when viewing "All Rooms", read-only field when viewing a specific room or editing - Add i18n (zh-CN / en-US) for all hardcoded strings in device page; register "device" namespace in i18n.ts - Align page header icon with other pages (ServerCog w-8 h-8) - Update index.test.tsx mocks to cover createGroup / deleteGroup / listDeviceTools / updateDeviceTool Co-authored-by: Cursor <cursoragent@cursor.com>
feat(device): add multi-room support and i18n for device integration
When opening a tool's test panel from within a specific device's configuration panel, the device UUID (generated at onboarding time) is now pre-filled as `device_id` in the test parameters JSON. This resolves the error "当前存在多台同类型设备,调用前必须显式传入 `device_id`" that appeared whenever multiple instances of the same device type were registered, because the registry's `_resolve_device_target` could not auto-select a target without an explicit `device_id`. Changes: - ToolDetailModal: add optional `deviceId` prop; inject it as the first key in the template produced by `buildParamsTemplate`, skipping any duplicate `device_id` param entry from the tool's parameter list only when the prop is already provided (avoids regression for tools whose YAML explicitly declares a required `device_id` parameter) - ToolDetailModal: show a contextual hint below the params label when `deviceId` is pre-filled, so the user knows where the value came from - DeviceConfigPanel: pass `device?.id` as `deviceId` when opening ToolDetailModal from the per-device tools tab - buildParamsTemplate: fix number/boolean default values to emit actual `0` / `false` instead of the string literals `"0"` / `"false"` Co-authored-by: Cursor <cursoragent@cursor.com>
…evice-id feat(device): auto-inject device_id into tool test params
Clicking a fixture called setTestParams with the fixture's raw params, silently overwriting the pre-filled device_id injected by the deviceId prop. Merge device_id as the first key so it is never lost regardless of which fixture the user selects. Co-authored-by: Cursor <cursoragent@cursor.com>
setToolModal(tool) passed the raw tool object whose enabled field
reflects the initial load, ignoring any per-device toggle the user
applied in the same session. Replace with { ...tool, enabled: isOn }
so the modal always receives the current effective enabled state.
Co-authored-by: Cursor <cursoragent@cursor.com>
…l reveal (#349) * feat(webui): add custom device access wizard (API/WebCLI/Syslog) Extend Device Integration with custom device onboarding for API, WebCLI, and syslog modes, including types, panel UI, and tests. Document a third web2cli capture path when CLI requirements are already specified. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(webui,web2cli): align WebCLI custom device with device plugin flow Require skill integration first, then optional device plugin packaging for security devices. Add cli-in-device reference, tighten session prompts and provider description guidance, and update custom device access UI/tests. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(device,web2cli): reveal persisted secrets and streamline CLI docs Add an explicit credentials endpoint so the device UI can show full masked secrets on demand. Update web2cli to document cookie/auth-state defaults and replace the spec-generation step with cli-requirements. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(web2cli,webui): document optional auth recovery credentials Allow optional username/password for browser-based cookie recovery after auth-state expires, and align custom device session prompts with the updated cli-in-device guidance. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(device,webui): scope credential reveal and add audit trail Switch credentials reveal to POST with per-field requests, emit device.credentials_reveal audit events without logging secrets, and localize the custom device access UI.
…E_ID handlers _config_override_service was set to the bare service_id (e.g. "sangfor_af") derived by storage_key_to_service_id(), but several device handlers declare SERVICE_ID as the full versioned storage key (e.g. "sangfor_af_v8_0_48"). get_config_override() performed an exact match, so these handlers always got None and silently fell back to the global default config — using the plugin's hardcoded DEFAULT_BASE_URL (192.168.1.1) instead of the device's configured IP (e.g. 10.201.255.17). Fix: - _build_overrides() now returns a 4-tuple including storage_key - activate_device_credentials() stores storage_key in a new ContextVar _config_override_storage_key alongside the existing service_id var - get_config_override() accepts a match on either bare service_id OR full storage_key, so all handler SERVICE_ID conventions work correctly Affected handlers (non-exhaustive): sangfor_af_v8_0_48, sangfor_af_v8_0_85, sangfor_af_v8_0_106 Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(session): add write file links and concise workflow tool output Append clickable local-file Markdown links to write tool results in session output, omit verbose workflow execution history from default run_workflow text while keeping it in metadata, and strip reasoning block whitespace on both ends. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(session): drop runner-side write tool file link formatting Remove clickable Markdown link injection from session runner write output; workflow concise output and reasoning strip changes remain unchanged. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(workflow): show live stage in WebUI and forward session cancel Expose workflow_name and total_nodes in run_workflow metadata, forward the session abort flag to the workflow runtime, and render a compact running-stage summary in the session tool header. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(session): propagate abort to tools and guard late metadata updates Forward the session abort event into StreamProcessor tool execution, mark metadata callbacks finished in a finally block, ignore stale running updates after completion, and persist interrupted tool state on cancel. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(session): cancel inflight metadata tasks and localize workflow header Cancel pending running-metadata publish/persist tasks when a tool completes, and use i18n labels for run_workflow stage summaries in the WebUI header. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(workflow): make llm.ask cancellable and show cancelling UI state Propagate workflow cancel checks through LLM nodes, lazy llm helpers, and provider calls, then surface a cancelling phase in workflow detail run/history views with localized status messaging. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(workflow): add cancel_checker to sandbox python runtime Declare cancel_checker on SandboxPythonExecRuntime and update sandbox tests to match the keyword-aware get_lazy_llm factory.
B1 (ToolDetailModal): { device_id: deviceId, ...fx.params } had the spread
order backwards — a fixture that already carries a device_id key would
overwrite the prop-injected value, exactly undoing the fix. Swap to
{ ...fx.params, device_id: deviceId } so the parent-supplied deviceId
always takes precedence regardless of fixture contents.
S1 (credential_context): 'and' binds tighter than 'or', so the guard
if secret_ovr is None and config_ovr is None or service_id is None
was already evaluated correctly, but was easy to misread as
if secret_ovr is None and (config_ovr is None or service_id is None).
Add explicit parentheses to match the intended semantics at a glance.
Co-authored-by: Cursor <cursoragent@cursor.com>
S2 — Add unit tests for get_config_override dual-key matching New test file tests/tool/test_credential_context_config_override.py covers 7 scenarios without touching the DB or ToolRegistry: · bare service_id match (existing behaviour) · versioned storage_key match (new behaviour, regression target) · unrelated service_id → None · no active override → None · storage_key=None does not match empty string (falsy trap) · service_id=None does not match empty string (falsy trap) · identical service_id and storage_key (no version suffix) S3 — Improve readability of the dual-key match in get_config_override Replace 'service_id in (expected_service, expected_storage)' with explicit named booleans (matches_service / matches_storage) and an expanded docstring that explains the two naming conventions handlers use, so future readers do not mistake either branch as redundant. S4 — _build_overrides return type → _DeviceOverrides NamedTuple Positional 4-tuples are fragile: a caller adding or reordering fields silently shifts every unpack site. Introducing _DeviceOverrides makes field access self-documenting (.service_id, .storage_key, …) and lets type-checkers catch missing fields at import time. Co-authored-by: Cursor <cursoragent@cursor.com>
- Add autouse fixture _reset_context_vars that clears the three ContextVars before and after every test; without it a test that sets a var leaks state into the next test in the same thread - Remove bare 'import pytest' that was unused before the fixture was added (would have triggered a lint warning) Co-authored-by: Cursor <cursoragent@cursor.com>
…-drops-device-id fix/device tool test fixture drops device
…ingtalk, telegram Apply PR #190 (wecom inbound + outbound file attachments) and extend the same pattern to dingtalk and telegram. Refactor the inbound dispatcher into a per-channel hook registry so new channels no longer need to modify dispatcher.py. Inbound (download to local FilePart): - wecom: AES-256-CBC decrypt via wecom_aibot_sdk, 30MB cap, nested mixed-message aeskey, Content-Disposition filename extraction - dingtalk: exchange download_code via OAPI /v1.0/robot/messageFiles/download, 20MB cap, separate exchange/download error classification - telegram: resolve telegram://<kind>/<file_id> via getFile + https://api.telegram.org/file/bot<token>/<file_path> download Outbound (send_media per channel): - wecom: SDK upload_media → send_media_message / reply_media; companion text sent as a follow-up markdown message - dingtalk: OAPI multipart upload → msgKey=file (downloadCode+fileName) for any type; msgKey=image (photoURL) for remote image URLs - telegram: route to sendPhoto / sendDocument / sendVideo / sendAudio / sendVoice / sendAnimation based on inferred kind; agent can force document via telegram:document:<url> prefix Dispatcher: - register_inbound_media_downloader() + _DOWNLOADERS table - dynamic per-channel lookup so test monkeypatches on the channel's inbound_media module still apply - SSE message.part.updated events for both FilePart and the rewritten text part; placeholder text replaced with 'Attached files: <path>' Tests: - wecom: +14 (send_media, inbound_media, content-disposition, mixed file) - dingtalk: +9 (download_code exchange, oversized guard, send_media routing, text-after-file, image URL inline) - telegram: +15 (file_id resolution, kind inference for image/pdf/gif/ogg, endpoint routing, kind override prefix, error path) - dispatcher: +9 (per-channel routing, placeholder detection, end-to-end per-channel pipeline) - test_e2e_file_roundtrip.py: 7 new tests covering real PNG byte round-trips for all five channels with in-process fake servers All 354 channel tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Documents the bidirectional file/image contract for all built-in channels, the dispatcher refactor, the per-channel downloader hook pattern, and the channel-specific outbound quirks reviewers need to know before approving changes to the media path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…escription) The channel file/image review notes are better kept in the PR description itself (where reviewers see them first) than in a root-level doc that the gitignore policy excludes from the docs/ folder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ge points, impact scope, and review focus Rewrite the "Pull Request Guidelines" section in CONTRIBUTING.md so the required PR description structure is explicit: - Key Changes (改动点) — concrete deltas grouped by area. - Impact Scope (影响范围) — user-visible behavior, compatibility, configuration, dependencies, performance, security. - Business Logic to Focus On During Review (需重点 Review 的业务逻辑) — the parts of the change that deserve extra reviewer attention. The previous section listed five reviewer-facing questions but did not constrain the order or depth of the description, which led to PRs that mentioned the impact but omitted the logic that needed a careful read. Also update the PR description template to match the new structure and add a Why-This-Approach section plus an explicit Compatibility, Migration & Rollback section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR #380 added flex flex-col to the shared content wrapper for the /devices page height chain, which unintentionally changed home and other standard page layout. Keep /devices on the fullscreen route and restore the v2026.6.4 wrapper for all other pages.
Add admin-managed user-defined pages with backend build/watch/runtime support and a WebUI host for published pages.
* refactor: unify subagent delegation under delegate_task Consolidate task scheduling into delegate_task (task becomes a compat alias), remove plan mode and standalone background tools, and run independent foreground subagents in parallel. Update WebUI cards, skill installer, and agent configs. Co-authored-by: Cursor <cursoragent@cursor.com> * fix/skill remove * fix/skill install skill.sh * fix(webui): render parallel delegate tasks as separate cards Remove buildParallelDelegateGroupParts which merged multiple sibling delegate_task tool parts into a single 'Parallel Agents' card. Each parallel subagent now renders as its own DelegateTaskCard with its real subagent_type name, matching the user-facing expectation of 'one tool card per agent'. * refactor(delegate_task): remove legacy tasks=[...] batch shape The unified delegate_task tool only needs the single-subagent shape now that parallel work is expressed as multiple sibling tool calls in one assistant turn. Drop the batch path from delegate_task, the task compat alias, the stream-processor branch that aggregated it into one card, and the matching batch compat tests; replace the latter with a small tolerance test for the slimmer schema and adjust model-pinning tests accordingly. Also remove the now-redundant fallback to the load_skills-aware description in the webui DelegateTaskCard since the card already renders the explicit description when provided. * Fix legacy todo permission migration
…w-usability # Conflicts: # webui/src/components/common/SessionChat.tsx
Fix channel image preview rendering
feat/Input selector visual tuning
Revert PR #398 changes that touched workflow pages and workflow-local config support. This removes the workflow detail UI tuning, edit markdown/config APIs, generated config templates, and matching test/mock updates while keeping later dev commits intact.
revert(workflow): restore pre-pr398 workflow experience
* feat(device): unify device plugin intake * refactor(device): streamline custom intake chat * refine device intake layout and webcli guidance
* feat: improve device integration auto-sync * fix: harden device refresh auto-provisioning
duguwanglong
approved these changes
Jun 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.