Conversation
基于 aisoc_mini 的告警去重算法(URI 归一化 + 5-gram Shingling + Jaccard 相似度)移植为 flocks 工作流,包含 5 个线性节点:接收解析 → URI 归一化 → 去重键计算 → 分组去重 → 报告生成。支持严格字段精确匹配与 LSH 字段近似 匹配,输出唯一告警、重复告警及 Markdown 分析报告。 Co-authored-by: Cursor <cursoragent@cursor.com>
…stages) 重写工作流以完整对齐 aisoc_mini 的 LogProcessPipeline 四阶段主流程: - normalize_logs: TDP/Skyeye 字段映射 + 嵌套结构扁平化 - filter_logs: jsonLogic 规则过滤(扫描类/出站/非HTTP告警剔除) - dedup_logs: URI 归一化 + 5-gram Jaccard 相似度去重,生成 dedup_key - analyze_unique: 仅对唯一 dedup_key 调用 LLM is_attack 研判并回填重复告警 - generate_report: 输出四阶段统计 Markdown 报告及 JSONL 数据文件 Co-authored-by: Cursor <cursoragent@cursor.com>
…rallelize LLM analysis
修复审阅中发现的功能性偏差:
1. filter_logs: 完整对齐 LogFilter._get_tdp_process_type() 9 种 process_type 分类
- 修正:HTTP 非扫描告警无论方向(in/out/lateral)都需研判(之前错误地只保留
direction=in/none,会丢失大量本应分析的出站/横向 HTTP 告警)
- HTTP 协议判断兼容 application_layer_protocol/net_type/net_app_proto 多字段
- threat_type 取值与原版一致:tdp 取 threat_name,skyeye 取 threat_type
- 新增 _process_type、_need_analysis_attack_status 字段
- 统计中加入 filter_process_type_counts
2. analyze_unique: ThreadPoolExecutor 并行调用 LLM(与 LogAnalysis.process_parallel
一致,可通过 analyze_max_workers 配置),单条失败不影响其他
3. dedup_logs: 移除函数体内重复的 import hashlib as _hl
4. 各节点新增轻量 print 进度日志,便于大批量调试
5. workflow.md 同步修正过滤逻辑描述
Co-authored-by: Cursor <cursoragent@cursor.com>
…result routing
用显式 branch 节点替换代码内部的 if-else 路由,拓扑结构变为:
receive_alerts
→ branch_log_type (select_key: source_log_type)
label:"tdp" → normalize_tdp → filter_logs
label:"skyeye" → normalize_skyeye → filter_logs
→ branch_has_alerts (select_key: _has_alerts)
label:"true" → dedup_logs → analyze_unique → generate_report
label:"false" → generate_empty_report(无 LLM 调用的快速终点)
修复:
- branch_log_type 两条边均使用显式 label ("tdp"/"skyeye"),
使 lint 正确识别为互斥路径,消除 multi_incoming_no_join 报错
- false 分支独立终结于 generate_empty_report,
避免 generate_report 多入边 lint 错误
- 测试验证:TDP/Skyeye 字段映射、has_alerts true/false 四条路径均正确路由
Co-authored-by: Cursor <cursoragent@cursor.com>
…y to dedup-only
- 目录重命名 alert_dedup → network_alert_dedup
- workflow.json / meta.json name & id 改为 network_alert_dedup
- 移除 analyze_unique / generate_report / generate_empty_report / branch_has_alerts 四个节点
- 移除 LLM 研判相关参数(analyze_enabled / analyze_max_workers)
- dedup_logs 成为终点节点,直接输出 dict:
deduped_alerts(全量含 dedup_key)/ unique_alerts(唯一簇)/ stats / dedup_summary
- filter_logs 清理预填空结果逻辑,精简 outputs 传递
- workflow.md 更新为三阶段流程说明(归一化→过滤→去重)
- lint 无警告,模型验证通过
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ert_dedup - filter_logs 新增 _has_alerts 输出 - 插入 branch_has_alerts 分支节点(select_key: _has_alerts) - true 路径 → dedup_logs(执行去重,终点) - false 路径 → dedup_empty(无告警,直接返回空 dict,终点) - 更新 workflow.md 流程图及节点说明 - lint 无警告,模型验证通过(8 节点 / 8 边) Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…p_alert_dedup filter_logs 直接连接 dedup_logs,dedup_logs 自然处理空列表输入 Co-authored-by: Cursor <cursoragent@cursor.com>
…_logs 使用 datasketch MinHash + MinHashLSH 替换原有 O(n²) 暴力 Jaccard: - NUM_PERM=128, MINHASH_SEED=2024(对齐 lsh_processor.py) - 共享 permutations,对齐 LSHProcessor 初始化方式 - query_most_similar:LSH 快速候选 → 精确 Jaccard 取最相似(对齐原版逻辑) - normalize_uri 对齐 utils.py(DATETIME/UUID/TRAVERSAL/NULL_REPLACED/HEXADECIMAL) - dedup_key = MD5(strict_text + '. ' + lsh_key),对齐 LogDedup._generate_dedup_key_text - 实测 453 条 TDP 过滤后告警 → 360 个唯一簇,压缩率 20.5% Co-authored-by: Cursor <cursoragent@cursor.com>
…dup_logs - All Chinese comments replaced with English - cluster_id (int) written to alert['_lsh_cluster_id'] so callers can inspect LSH cluster membership - lsh_cache now stores MinHash directly (not wrapped in dict) for cleaner re-ranking - summary string switched to English Co-authored-by: Cursor <cursoragent@cursor.com>
LSH state (lsh_index + lsh_cache) is now saved to and loaded from: ~/.flocks/data/workflows/http_alert_dedup/lsh_state_np128_th<threshold>.pkl - get_lsh_state_path(): builds path via Config().get_data_path() - load_lsh_state(): loads pickle, validates num_perm/threshold params match - dump_lsh_state(): saves after each run; mirrors LogDedup.dump() - Filename encodes NUM_PERM and threshold so param changes auto-reset state - stats gains lsh_total_clusters and lsh_state_path fields - Verified: run2 correctly loads run1 clusters and accumulates new ones Co-authored-by: Cursor <cursoragent@cursor.com>
Four correctness fixes plus the datasketch dependency:
1. Persist dedup_key_cache (the set of MD5 keys ever seen) into the same pkl
so that 'dedup_key_already_exists' is correct across restarts and batches.
Previously it was a per-run local set, breaking cross-batch dedup detection.
2. Atomic write: pickle to <state>.tmp, fsync, then os.replace() over the
target. A crash mid-write no longer corrupts the persisted state.
3. fcntl.flock(LOCK_EX) on a sibling .lock file serializes load+modify+dump
across concurrent workflow runs, eliminating the read-modify-write race
that previously caused lost updates.
4. dedup_enabled=False branch now sets _lsh_cluster_id=None so that downstream
consumers see a consistent schema regardless of dedup mode. In-batch
duplicate detection still works in this branch.
Also: warn when persisted cluster count exceeds 100k so operators can rotate
state. New stat: lsh_total_dedup_keys.
Verified end-to-end:
- cross-batch: same alert in run2 reports already_exists=True
- corruption: garbage pkl is auto-discarded, no crash
- concurrent: 5 parallel processes writing 10 alerts each end up with
50 persisted clusters (not lost to read-modify-write)
- disabled: _lsh_cluster_id=None, in-batch duplicate detected
Co-authored-by: Cursor <cursoragent@cursor.com>
Cross-platform support: - Replace bare 'import fcntl' with platform detection. - POSIX path keeps fcntl.flock(LOCK_EX). - Windows path uses msvcrt.locking(LK_LOCK, 1) on a single byte of the lock file, looping on OSError to wait beyond LK_LOCK's built-in 10-second cap. - Both branches release the lock symmetrically in release_lock(). Review fixes: - 'lsh_state_path', 'lsh_total_clusters', 'lsh_total_dedup_keys' are no longer written to stats when dedup_enabled=False (was misleading; no file is touched in that mode). Added 'dedup_state_persisted' bool for callers to branch on. - Cluster-overflow warning now also checks dedup_key_cache, since pkl size is dominated by per-key entries, not per-cluster. - normalize_uri's UUID regex now uses re.IGNORECASE so uppercase UUIDs map to the same 'UUID' placeholder (and thus the same LSH cluster) as lowercase ones. - Disabled-mode summary clearly states 'no state persisted, in-batch only'. Verified: cross-batch, disabled-mode stats, uppercase UUID dedup, concurrent writers. Co-authored-by: Cursor <cursoragent@cursor.com>
…; add alert_file support run_workflow.py: - When workflow is a JSON-decoded non-dict (e.g. the AI wraps the path in extra quotes producing '\"..path..\"'), treat the decoded string as a file path instead of crashing with 'str object has no attribute name'. - Add upfront dict sanity-check: if the dict has no 'start' key it's almost certainly the inputs dict passed to the wrong parameter; return a clear error instead of a Pydantic validation traceback. - Add a comment clarifying that the else-branch delivers a Path, not a str. workflow.py: - Add sync_workflows_from_filesystem() which app.py imports at startup. Triggers the one-time storage→filesystem migration then returns the count of discovered workflows so the startup log entry is informative. http_alert_dedup/workflow.json: - receive_alerts now accepts alert_file (absolute or ~-prefixed path to a JSON file) as an alternative to inlining the alerts list directly in inputs. This removes the need to manually load large log files via bash before running the workflow (the main friction observed in session 询问可用工作流). - sampleInputs annotated with a _comment_alert_file hint. Co-authored-by: Cursor <cursoragent@cursor.com>
…type errors Previous fix used 'parsed if isinstance(parsed, str) else raw' which silently passed list/int/bool results to Path(), giving a misleading 'file not found' error. Now three explicit branches: - parsed is str → double-encoded path; use decoded value as file path - parsed is None → JSONDecodeError; use raw string as file path (original behaviour) - parsed is other → clear error stating the unexpected JSON type Co-authored-by: Cursor <cursoragent@cursor.com>
…ID lookup Resolve the merge conflict in the `workflow` string parsing block by combining both sides: - HEAD: explicit type dispatch on json.loads() result (dict / str / None / other) with clear per-type error messages. - Upstream (d8b44e5): on JSONDecodeError, try read_workflow_from_fs() first so callers can pass a plain workflow ID instead of a full JSON string. Merged result: keep the type-dispatch structure from HEAD; in the `parsed is None` (JSONDecodeError) branch, attempt workflow-ID resolution via read_workflow_from_fs() before falling back to a file path. Co-authored-by: Cursor <cursoragent@cursor.com>
The get_state_paths() change to ~/.flocks/workspace/workflows/ was lost when merging dev into feat/alert-dedup-workflow (da58f7b). Re-apply: - Remove top-level `from flocks.config import Config` import - Replace Config().get_data_path() with Config().get_global().data_dir.parent / 'workspace' / 'workflows' - Update node description accordingly Also sync the running release snapshot and restart the service process so the /invoke API immediately uses the new path. Co-authored-by: Cursor <cursoragent@cursor.com>
…calls
workflow_center_invoke (POST /workflow-center/{id}/invoke) now records
execution stats via create_execution_record + _update_workflow_stats +
_record_execution_result, so that UI callCount / successCount / errorCount
counters are updated for every /workflow-center call — not only for
agent-driven /workflow/{id}/run calls.
Co-authored-by: Cursor <cursoragent@cursor.com>
New workflow: - Add alert_dedup_triage workflow: chains http_alert_dedup → tdp_alert_triage in a single pipeline; per-alert dedup via MinHash LSH, then LLM triage for first-seen unique alerts; duplicate alerts are annotated with cached triage results from a persisted triage_cache.pkl (FIFO LRU, max_dedup_keys cap). http_alert_dedup improvements: - Upgrade dedup_key_cache from set to ordered dict for FIFO LRU eviction. - Add max_dedup_keys input param (default 100 000); oldest entries are evicted before each persist so the state file stays bounded. - Use a monotonic cluster_id counter (_cid_box) instead of len(lsh_cache) so IDs never collide after eviction; remove evicted cluster_ids from the MinHashLSH index to prevent stale query results. - Expose lsh_max_dedup_keys / lsh_evicted_keys / lsh_evicted_clusters in stats. - Forward max_dedup_keys through normalize_* and filter_logs nodes. tdp_alert_triage: - Remove web-log detection branch; workflow now accepts HTTP alerts directly. - Add _strip_think() to all LLM nodes to strip <think>…</think> blocks. - Update workflow.md to reflect simplified node structure. Test tools (moved from scripts/ → tests/integration/): - test_http_alert_dedup_stream.py: streaming simulation for http_alert_dedup. - test_alert_dedup_triage_stream.py: end-to-end dedup → triage pipeline test. Co-authored-by: Cursor <cursoragent@cursor.com>
- Add flocks/syslog package (constants, parser, listener, manager) to
receive UDP/TCP syslog messages and trigger workflow execution via the
Channel-GatewayManager pattern
- Expose POST/GET /workflow/{id}/syslog-config API endpoints; start/stop
all enabled listeners in the FastAPI lifespan
- Add SyslogConfig TS interface and saveSyslogConfig/getSyslogConfig API
methods to the frontend workflow client
- Extract PublishSection, KafkaSection, SyslogSection from RunTab into a
new IntegrationTab component; wire it as a fourth "Integration" tab in
RightPanel so the Run tab only shows test-run and execution history
- Add tabIntegration i18n keys (zh-CN / en-US) and syslogActive badge
shown when listener is enabled and collapsed
Co-authored-by: Cursor <cursoragent@cursor.com>
Group data-ingestion triggers under a shared flocks/ingest/ namespace so that future connectors (kafka, webhook, …) live alongside syslog as sibling sub-packages rather than top-level packages. - Move flocks/syslog/* → flocks/ingest/syslog/* - Add flocks/ingest/__init__.py (empty package marker) - Update all internal imports (flocks.syslog → flocks.ingest.syslog) in listener.py, manager.py, __init__.py, server/app.py and server/routes/workflow.py Co-authored-by: Cursor <cursoragent@cursor.com>
receive_alerts node now handles three input sources in priority order:
1. syslog_message (injected by flocks syslog listener, RFC3164/5424)
- TDP alert JSON parsed from syslog_message.message
- Syslog metadata (hostname, severity, timestamp…) attached to alert
under _syslog_meta for traceability; does not affect dedup/triage logic
2. alerts (batch list, existing)
3. alert_file (local JSON path, existing)
Also adds syslog-config API documentation and example to workflow.md and
syslog_message sample to metadata.sampleInputs.
Co-authored-by: Cursor <cursoragent@cursor.com>
…move HTTP service dependency Replace direct HTTP POST calls to published service ports (19000/19001) with in-process embedded invocations using flocks.workflow.runner.run_workflow and flocks.workflow.fs_store.workflow_scan_dirs. - _invoke_workflow(): locates sub-workflow.json via workflow_scan_dirs(), then calls run_workflow() directly in the same process - Removes urllib/HTTP helpers, dedup_service_url, triage_service_url inputs - Adds dedup_workflow_id / triage_workflow_id inputs (default: http_alert_dedup, tdp_alert_triage) so callers can override the sub-workflow IDs if needed - http_alert_dedup and tdp_alert_triage no longer need to be published as running services for alert_dedup_triage to function Co-authored-by: Cursor <cursoragent@cursor.com>
…nglish - Node description fields: translated to English - generate_summary: verdict_label / stage_label dicts and summary_md template converted from Chinese to English - Code comments in receive_alerts and dedup_and_triage were already English - description_cn field and LLM prompt content in tdp_alert_triage left as-is (intentionally Chinese for LLM interaction) Co-authored-by: Cursor <cursoragent@cursor.com>
…able Co-authored-by: Cursor <cursoragent@cursor.com>
…report in batch mode Add branch_output_mode node after dedup_and_triage: - input_mode == 'syslog' -> direct_output: returns single-alert triage result directly (one-liner summary_report, no table, no file write) - input_mode == 'alerts' | 'alert_file' -> generate_summary: full statistics table + top-risk report written to pipeline_summary.md Both paths emit identical output field names for downstream compatibility. Co-authored-by: Cursor <cursoragent@cursor.com>
…iggered runs Syslog-triggered workflow runs were invisible in the WebUI history panel and not counted in the workflow stats card because `_trigger_workflow` called the runner directly, bypassing both the execution record write and the call counter update. Run records were never written, and `callCount` only ever reflected HTTP-triggered runs. This change makes the syslog path go through the same persistence helpers as the HTTP API path so all trigger sources are uniformly visible in the UI: - syslog/manager: wrap each run with create_execution_record / record_execution_result; write the same fields the WebUI consumes (`outputResults`, `errorMessage`, `duration`, `executionLog`, `currentNodeId`, `currentPhase`, `currentStepIndex`); tag input params with `_trigger=syslog` for source identification. - workflow/execution_store: move the workflow stats counter update into `record_execution_result` so every persisted result automatically increments callCount/successCount/errorCount/totalRuntime/avgRuntime, regardless of trigger source. - server/routes/workflow: remove the now-redundant `_update_workflow_stats` calls from the HTTP run/invoke paths and drop the orphaned helper to avoid double counting. Co-authored-by: Cursor <cursoragent@cursor.com>
… triage http_alert_dedup: - Replace branch_log_type + normalize_tdp + normalize_skyeye nodes with a single unified normalize node; each alert is individually classified via field signatures (nested net dict / behave_uuid for TDP; uri / vuln_name / attack_result for Skyeye) before field mapping, enabling mixed-type batches in a single invocation. - Update filter_logs to read per-alert _source_type set by normalize instead of the batch-level source_log_type, ensuring correct threat/process type classification in mixed batches. - source_log_type is retained as an optional batch-level fallback hint when per-alert detection is inconclusive. alert_dedup_triage: - Implement 4-priority source_log_type resolution in receive_alerts: (1) explicit input param, (2) syslog app_name/hostname hint, (3) JSON field auto-detection on first alert, (4) default 'tdp'. - Emit source_log_type_reason for traceability. tdp_alert_triage: - Extend receive_alert pick() lookups to cover flat TDP field names (net_real_src_ip, net_dest_ip, net_http_url, net_http_reqs_body, net_http_resp_body, net_http_status, etc.) alongside nested TDP and normalized schema, fixing empty-payload LLM analysis for pre-flattened TDP alerts arriving via alert_dedup_triage. Co-authored-by: Cursor <cursoragent@cursor.com>
…lert_dedup Root causes identified: 1. Large alert lists (enriched_alerts, unique_alerts, …) were written verbatim into every workflow_execution SQLite row — both in outputResults and in each executionLog snapshot emitted by _on_step_complete — duplicating megabytes of data that is already persisted to JSONL on disk. 2. The problem affected both the syslog trigger path (manager.py) and the HTTP background execution path (routes/workflow.py), but only the former had a local fix applied; the HTTP path was left unprotected. Changes: - execution_store.py: add compact_outputs_for_storage() and compact_history_for_storage() as the canonical compact API. Lists whose key belongs to DEFAULT_LARGE_LIST_KEYS and whose length exceeds DEFAULT_COMPACT_SIZE_THRESHOLD (100) are replaced with a lightweight _<key>_count integer; small lists and unknown keys pass through unchanged, so ordinary metadata arrays are never silently dropped. - syslog/manager.py: remove the local _compact_outputs/_compact_history implementation and import the shared helpers from execution_store. - routes/workflow.py: apply compact_outputs_for_storage to outputResults and compact_history_for_storage to executionLog in both the background execution path and the workflow-center invoke path. Also compact each step dict inside _on_step_complete before appending to step_history so that every intermediate _write_progress snapshot stays bounded. - tests/workflow/test_execution_store_compact.py: 14 new unit tests covering the size-threshold guard, non-mutation contract, defensive pass-through for non-dict inputs, and the end-to-end size reduction (>1 000x on a 10K-alert payload). Co-authored-by: Cursor <cursoragent@cursor.com>
inputParams was written verbatim into every workflow_execution SQLite row.
For HTTP /run batch calls that pass a large alert list as an input
parameter (e.g. {"raw_alerts": [...10k items...]}) this inflates each row
by the same order of magnitude as the uncompacted outputResults bug fixed
in the previous commit.
Changes:
- execution_store.py: create_execution_record() now passes input_params
through compact_outputs_for_storage() before building the record, so
known large-list keys (raw_alerts, enriched_alerts, etc.) are replaced
with lightweight _<key>_count integers. Scalar fields and unknown keys
are preserved unchanged, so audit / replay use-cases are not affected.
- tests/workflow/test_execution_store_compact.py: two new tests pin the
expected behaviour — "alerts" (not in DEFAULT_LARGE_LIST_KEYS) passes
through unchanged, while "raw_alerts" (in the default set) is compacted.
Co-authored-by: Cursor <cursoragent@cursor.com>
…274) When nvm activates a supported Node version but `node` on PATH remains older, pin NODE_CMD/NPM_CMD/NPX_CMD to NVM_BIN for the rest of the installer run. Adds a Linux integration test for the stale-resolution scenario.
Five issues raised in code review, all fixed in this commit:
1. Docstring/behaviour mismatch — alerts key
create_execution_record()'s docstring previously used {"alerts":[…10k]}
as the example of what gets compacted. "alerts" is NOT in
DEFAULT_LARGE_LIST_KEYS, so the row would silently stay large. The
docstring now cites "raw_alerts" (which IS in the set) and adds an
explicit note that keys outside the default set are stored verbatim.
compact_outputs_for_storage() gains the same clarification so callers
can easily see the full list of compacted keys.
2. workflow_center_invoke — executionLog path
The invoke path proxies to an external service and never populates
executionLog locally, so no data was at risk. Added an explanatory
comment and an explicit compact_history_for_storage() call on the
executionLog field as a forward-compatible guard against future code
that might populate it before the final write.
3. tuple sequences not compacted
compact_outputs_for_storage() checked isinstance(v, list), missing
tuple values that some serialisation paths may produce. Changed to
isinstance(v, (list, tuple)). New test test_compact_outputs_compacts_
tuple_sequences() pins this behaviour.
4. Unused import pytest
Removed the bare "import pytest" from test_execution_store_compact.py;
no pytest.raises / @pytest.mark usages exist in the file.
5. Observability note
compact_outputs_for_storage() docstring now explicitly states that
compacted keys are replaced with _<key>_count and that callers who
need the full list contents must read from the JSONL files written by
the workflow.
Co-authored-by: Cursor <cursoragent@cursor.com>
…y-leak fix/stream alert dedup memory leak
Follow-up to PR #267: the syslog config form already validated host but accepted any integer for port, allowing values such as 0, 22, or 99999 to be saved and only blow up at bind time with a confusing OS error (e.g. "[Errno 49] can't assign requested address"). - Backend SyslogConfigRequest.port now enforces ge=1, le=65535 via Pydantic so out-of-range ports are rejected with HTTP 422 before the config is persisted or the listener is restarted. - IntegrationTab.tsx adds an inline validator that strictly matches a numeric string (rejecting "5140abc", "3.14", "-1", etc.) and the 1..65535 range; the input shows a red border with a localized hint and the save button is disabled while the value is invalid. - extractErrorMessage now flattens Pydantic 422 detail arrays ([{loc, msg, type}, ...]) into a readable "; "-joined string so scripted callers (or any caller that bypasses the UI validator) see the actual validation message instead of "[object Object]". - Adds zh-CN/en-US copy for detail.run.syslogPortError. Co-authored-by: Cursor <cursoragent@cursor.com>
…tion fix(syslog): validate listener port range on save
Move sangfor-edr-use and sangfor-xdr-use from docs/ into the standard skills directory (.flocks/plugins/skills/). Changes made during review: - edr: remove incorrect API mode section; EDR has no open API, all operations must go through browser/CDP - xdr: fix wrong script name in pitfalls table (cdp_fetch.py -> fetch_xdr_system_state.py) - xdr: fix API vs CDP comparison table — system state row had CDP script listed under API column, now shows ❌ - xdr: fix ambiguous "request confirmation" wording; now clearly states API is default and fallback to browser only on failure - both: replace hardcoded Windows absolute paths in execution examples with cross-platform placeholders (<FLOCKS_VENV> / <FLOCKS_PLUGINS>), and add macOS/Linux parallel examples - both: use tempfile.gettempdir() for daemon port file path instead of hardcoded C:/Users/Administrator/AppData/Local/Temp - both: add macOS/Linux Chrome/Edge remote debugging start commands - xdr: rename dict key data接入 -> data_ingestion to avoid mixed Chinese/English key names - both: move inline `import re` to module top level Co-authored-by: Cursor <cursoragent@cursor.com>
feat(skills): add sangfor-edr-use and sangfor-xdr-use skills
…275) * feat(task): enforce five-field cron and format times in schedule TZ Reject unsupported six-field Quartz expressions with a clear hint; show CLI and task center datetimes in the scheduler timezone for readability. * fix(task): skip plugin task specs with invalid cron fields Validate cron during plugin upsert; log and skip bad specs so six-field Quartz expressions cannot create or overwrite schedulers. * fix(task): validate cron with croniter and avoid trigger mutation Deep-copy triggers on scheduler create; keep existing cron when switching to run-once without a new cron. Reject invalid five-field expressions via croniter; clarify unknown timezone labels in task datetime formatting; mark plugin spec upserts as fully skipped on bad cron.
* refactor(session): modular system prompts and runner wiring - Extend prompt composition (provider blocks, guidance, caching) and consolidate defaults; trim redundant static template bodies. - Update prompt_strings, Rex/Hephaestus builders, prompt_utils, and memory bootstrap for the new prompt pipeline. - Adjust session runner for Anthropic-style system blocks and related message handling. - Refresh session/agent/memory/integration tests; add Anthropic system blocks unit coverage. * refactor(rex): streamline prompt builder; ship flocks_mcp in core - Relocate flocks_mcp from ~/.flocks plugin path to flocks/tool/system. - Rex prompt_builder and agent.yaml/toolset updates; agent_factory hooks. - Session prompt/runner and prompt_strings tweaks; registry and skill wiring. - Refresh AGENTS.md; extend tests for factory, runner, toolset, builtins. * fix(session): reorder system prompt blocks; keep lsp tool non-native - Move agent_identity and tool_catalog layers for clearer guidance order. - Exclude lsp from bulk native=True classification in ToolRegistry. - Minor lsp_tool tweak; extend runner and builtin management tests. * refactor(session): trim prompt strings; tighten bash tool copy - Remove redundant prompt.py / prompt_strings content where duplicated. - Refine bash tool description (dedicated-tool bullets and usage notes). - Align prompt_tokens, runner_step, and bash registry tests. * refactor: remove file search, list, codesearch, and omo tools - Remove Python/TUI tool implementations and registry/catalog wiring - Update agent YAMLs, skills docs, and validator for tool-builder - Adjust session runner, prompts, and OpenAI responses tool prep - Add TUI question-state module with tests; update DelegateTaskCard * refactor: unify general session prompt, remove batch tool - Add general.txt prompt and get_prompt_general; drop Python qwen.txt - Remove batch tool from Python/TUI registries and delegate_task paths - Update Rex/hephaestus prompt builders, prompt_utils, and session assembly - Refresh anthropic prompts; add TUI prompt-source and system test * refactor(plan): remove plan agent yaml; simplify plan_exit - Drop bundled plan agent definition; keep plan_enter/plan_exit tools - Exit plan mode without confirmation; pass call_id for question context - Align TUI plan tool copy; extend test_tools coverage * refactor(session): hook payloads, task scheduling, and file tools Rework runner/hooks pipeline for LLM hook payloads, replace legacy task_center with schedule_task_center, remove multiedit end-to-end, add path_utils and a minimax prompt fragment, and align file tools, TUI, and tests. * refactor(session): message parts, todo flow, and runner loop Extend assistant message handling, rework todo tool/session/TUI wiring with runner and session_loop, adjust compaction policy and provider SDK hooks, and add regression tests (including DeepSeek provider). * refactor(tool): split bash descriptions and require PowerShell on Windows Unix and Windows now get tailored bash-tool copy; Windows drops cmd fallback, surfaces missing PowerShell clearly, and documents PS 5.1 quirks only when using powershell.exe. * fix(tool): escape Windows path examples in bash tool description Use doubled backslashes in the PowerShell description so the rendered guidance shows valid Windows-style paths. * feat(session): require replies in the user's language Add a consistent language-matching rule to Rex prompt XML and the general, Anthropic, and MiniMax session prompt templates.
Prefer single-line semicolon-separated -c snippets on Windows PowerShell to avoid quoting/newline pitfalls; document in browser-use, cdp-direct, and web2cli.
…280) Prevent nested workflow tools from overwriting run_workflow metadata, report completed status for successful task/delegate results, reject stale running updates over terminal tool parts, and tighten delegate card rendering so run_workflow is not misclassified.
…ifespan (#279) * fix(mcp): thread-safe commands across event loops for workflow runtime Route MCP client commands through the owner loop, initialize MCP in the workflow service lifespan, and add regression tests for cross-loop usage and route/service behavior. * fix(mcp,workflow): harden disconnect during connect and surface MCP readiness Only enqueue disconnect when connected; expose mcp_ready in workflow service health and return 503 when MCP init fails; add regression tests. * feat(api): reconnect MCP after update when server was connected Return reconnected/reconnect_error in the update response; bound reconnect with timeout derived from server config; extend route tests.
Merge the open detail snapshot into the visible list, poll execution by id while the drawer is open, and enable SessionChat live streaming whenever a session id exists so completed/running transitions stay accurate.
…#283) Replace per-message message_shapes with aggregate message_summary for each chat/stream request, and move plugin, tool, session, and compaction noise from INFO to DEBUG so long runs stay readable.
…metadata (#284) Pass only a registered clear callback into slash commands so /clear still emits the fallback message on WebUI. Document the resolved memory root and arbitrary daily note paths; surface model/provider in runtime metadata; align tool copy and tests.
Load Storage-backed custom agents during registry initialization so agents created through /api/agent survive service restarts.
* fix(feishu): init legacy WS client on worker loop and improve shutdown Defer lark_oapi Client construction to the background thread's event loop to avoid "attached to a different loop" errors. Track ping/receive tasks and reset state on stop so restart is reliable. * fix(feishu): handle stop during legacy WS client initialization Wait for worker-thread client init before stop proceeds; skip start when stop is requested early. Guard coroutine scheduling when loop is not running.
…hema (#287) * refactor(command): unify slash direct handlers and agent-safe tool schema Extract shared direct command execution and help formatting so the UI handler, run_slash_command tool, and Rex guidance stay consistent. Limit the agent tool to read-only direct commands and improve /help formatting. * feat(command,webui): add /agents command and refresh catalogs on focus Expose /agents as a shared direct slash command for UI and agent tools. WebUI agents/tools/skills/workflows pages refresh when the tab regains focus; Session restores the last selected chat from localStorage. Add skill-builder skill and route SkillSheet creation through it.
Prevent bash commands and large tool inputs from expanding the tool card summary; cap input JSON preview height and keep full values on hover.
…o-v2026.5.19 chore: update version to v2026.5.19 in pyproject.toml and uv.lock
Use _provider.yaml location to distinguish project vs user plugins for delete protection, avoiding false positives from stale native flags. Co-authored-by: Cursor <cursoragent@cursor.com>
…escriptor-path fix(provider): classify API builtin status from descriptor path
xiami762
approved these changes
May 19, 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.