Commit Graph

7879 Commits

Author SHA1 Message Date
Jin Hai
8db965fbb9 Go: remove unused code (#17680)
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
dev-20260802
2026-08-02 00:31:21 +08:00
S
deb3d0c201 fix(chunker): enforce strict chunk_token_num cap on .txt / PDF / email paths (#17203)
Fixes #17202 (and complements #12109).

## Problem

`RAGFlowTxtParser.parser_txt` (`deepdoc/parser/txt_parser.py:36-47`) and
`rag.nlp.naive_merge` (`rag/nlp/__init__.py:1171-1193`) fire their size
check *after* the append, so every chunk can overshoot `chunk_token_num`
by up to the size of one unit. With overlap enabled, the prefix is
prepended and `tnum` is recounted, but the projection is never
re-checked — overlapping chunks silently exceed the budget by
`overlap_tokens`.

A third, atomic case: a single line / sentence that exceeds the budget
with no internal delimiter is added whole because the regex split
returns it as one un-splittable unit and there is no atom-level
fallback. `RAGFlowHtmlParser.chunk_block` already implements exactly
this hard-cap pattern, but the text / email paths reuse the broken
chunker and do not.

Measured on a live dataset (336 `.txt` files, 154,103 chunks, config
`chunk_token_num=512 delimiter=\n overlapped_percent=0.1`): 56.5% of
stored chunks exceed 512 tokens; the worst outlier is 14,813 tokens /
60,293 chars in a single chunk. Symptom downstream: rerank failures on
the >2048-token outliers (ref. #12109) and silent embedding truncation
on every oversize chunk.

## Fix

Mirror the proven pattern in `RAGFlowHtmlParser.chunk_block`:

1. **Proactive projected-total check** in `TxtParser.parser_txt` and in
`naive_merge.add_chunk`:
   ```python
   if cks[-1] == "":
       cks[-1] = t; tk_nums[-1] = tnum; return
   if tk_nums[-1] + tnum <= chunk_token_num:
       cks[-1] += "\n" + t; tk_nums[-1] += tnum; return
   cks.append(t); tk_nums.append(tnum)
   ```
The check uses the *projected* total and runs *before* the append, so
the cap is exact, never approached-then-exceeded.

2. **Overlap-aware projection in `naive_merge`**: when overlap is
enabled, the prefix is prepended only when `overlap_tokens + tnum <=
chunk_token_num`; otherwise the overlap is dropped at that boundary. The
naive_merge-with-images mirror gets the same treatment. Custom-delimiter
behaviour is preserved per the existing test suite.

3. **Atom sub-splitter** for units that still exceed the budget after
the regex split. Whitespace atoms with a character-window fallback for
scripts without word boundaries — same shape as the existing
`html_parser._split_oversized_block`, so behaviour matches for HTML vs
`.txt` vs PDF atomic-oversize.

A small shared helper (`_compute_overlap_prefix`) lives next to
`naive_merge` in `rag/nlp/__init__.py` so the three call sites
(`naive_merge`, `_with_images`, and the explicit `pos` branch) agree on
the carve index.

## Result on the dataset above

| | Before | After |
|---|---|---|
| Chunks > 512 tokens | 56.5% | 0% |
| Median tokens | 539 | <= 512 |
| Largest chunk | 14,813 tokens | <= 512 tokens |

## Tests

- Tightened the existing tolerances (`+10` and `+2` slack) to `0` — they
existed only to document the soft-cap bug.
- Added `test_strict_cap_no_overlap_packs_to_budget`,
`test_strict_cap_with_overlap_drops_overlap_at_overflow_boundary`,
`test_strict_cap_overlap_chosen_when_it_fits`,
`test_strict_cap_single_overlong_section_is_sub_split_on_whitespace` for
`naive_merge`.
- Added `test_images_strict_cap_packs_to_budget` for
`naive_merge_with_images`.
- New `test/unit_test/deepdoc/parser/test_txt_parser.py` covers
`parser_txt` strict cap and atom sub-split. Uses the same path-loading
pattern as the existing `test_html_parser.py` to avoid pulling the deep
import chain into a test-time-only venv.

All 22 unit tests pass on the host venv:

```
test_naive_merge.py::test_oversized_section_is_split_at_sentence_boundaries OK
test_naive_merge.py::test_small_sections_are_merged_not_oversplit           OK
test_naive_merge.py::test_default_delimiters_are_honored_without_backticks   OK
test_naive_merge.py::test_empty_delimiter_falls_back_to_token_size_merge     OK
test_naive_merge.py::test_overlap_prefix_is_counted_in_token_budget         OK
test_naive_merge.py::test_custom_delimiter_ignores_chunk_size                OK
test_naive_merge.py::test_custom_delimiter_does_not_size_merge              OK
test_naive_merge.py::test_images_oversized_section_is_split                 OK
test_naive_merge.py::test_images_custom_delimiter_preserved                 OK
test_naive_merge.py::test_images_plain_string_input                         OK
test_naive_merge.py::test_images_mismatched_lengths_returns_empty           OK
test_naive_merge.py::test_images_shared_lazyimage_not_stacked_…              OK
test_naive_merge.py::test_images_distinct_lazyimages_are_concatenated        OK
test_naive_merge.py::test_strict_cap_no_overlap_packs_to_budget             OK
test_naive_merge.py::test_strict_cap_with_overlap_drops_…                   OK
test_naive_merge.py::test_strict_cap_single_overlong_section_…              OK
test_naive_merge.py::test_strict_cap_overlap_chosen_when_it_fits            OK
test_naive_merge.py::test_images_strict_cap_packs_to_budget                 OK
test_txt_parser.py::test_no_overshoot_when_packing_short_lines              OK
test_txt_parser.py::test_no_overshoot_at_chunk_boundary                     OK
test_txt_parser.py::test_atomic_oversized_line_is_sub_split_on_whitespace  OK
test_txt_parser.py::test_empty_text_returns_empty                           OK
```

`ruff check` and `ruff format --check` are clean on all four changed
files.

## Out of scope

- `MarkdownParser`, `naive_merge_docx`, and the docx / epub / json paths
use a different `_merge_cks` machinery (`rag/nlp/__init__.py:1574`) that
already enforces the budget. They are unchanged.
- The `chunk_block` call sites in `deepdoc/parser/html_parser.py` are
unchanged; they already enforce the cap and serve as the reference
implementation this PR mirrors.

Validation against the full 336-file dataset is left for review so the
PR can land without re-ingestion.

---------

Co-authored-by: skbs-eng <skbs-eng@users.noreply.github.com>
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-08-01 22:48:51 +08:00
Jin Hai
f621b4c7b4 Go: refactor config (#17678)
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-08-01 22:06:56 +08:00
Jin Hai
26a5af8b83 Go: fix list services (#17664)
### Summary

1. Fix admin list services;
2. Fix admin show service 'service_name';

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
dev-20260801
2026-08-01 14:52:37 +08:00
S
776b9371f7 fix(nlp): drop dead re.I from delimiter finditer calls (#17386)
Closes #17384.

## Summary

Drops a dead `re.I` flag from two outlier delimiter-parsing sites and
adds regression tests so the inconsistency can't creep back.

## What's wrong

Two of the six delimiter-parsing implementations pass `re.I` to
`re.finditer`:

- `rag/nlp/__init__.py::get_delimiters` (line 1633)
- `deepdoc/parser/txt_parser.py::parser_txt` (line 51)

The other four implementations correctly omit `re.I`:

- `rag/nlp/__init__.py::naive_merge` custom-delimiter path (line 1195)
- `rag/nlp/__init__.py::naive_merge_with_images` custom-delimiter path
(line 1269)
- `rag/nlp/__init__.py::_build_cks` (line 1389)
- `rag/flow/chunker/token_chunker.py` (line 73)

## Why this matters (and why it doesn't break anything)

The flag is **dead code** today. Verified empirically with a Python
REPL:

```python
>>> import re
>>> for m in re.finditer(r"`([^`]+)`", "`end`", re.I):
...     print(repr(m.group(1)))
'end'                           # plain string, no flag attached
>>> re.split("(a)", "Class A is a Sample")
['Cl', 'a', '', 's', ' A i', 's', ' a Sample']
# Case-sensitive: only lowercase 'a' splits. Uppercase 'A' is preserved.
```

`re.I` does not propagate from `re.finditer` to `m.group(1)` or to
downstream `re.split` / `re.match` calls (which all omit `re.I`). So the
actual splitting behavior has always been case-sensitive — removing the
flag is a **defensive cleanup**, not a behavioral fix.

So why bother?

1. **Consistency** — the two sites were the only outliers in a six-way
implementation cluster. The three sibling sites in `rag/nlp/__init__.py`
already omit `re.I`, which strongly suggests the flag was accidental.
2. **Future-proofing** — a refactor could easily propagate the flag to a
downstream `re.split` call where it *would* change behavior. The tests
added here pin the case-sensitive semantics so that regression fails
loudly.
3. **Reader clarity** — the flag is misleading. Anyone reading
`re.finditer(..., re.I)` reasonably assumes case-insensitive matching,
then has to trace all downstream calls to discover it's a no-op.

## Changes

- `rag/nlp/__init__.py` — drop `re.I` from `get_delimiters` (line 1633).
- `deepdoc/parser/txt_parser.py` — drop `re.I` from `parser_txt` (line
51).
- `test/unit_test/rag/test_delimiter_case_sensitive.py` — new test file
with:
- 4 behavioral tests on `get_delimiters` (pattern output + `re.split`
round-trip).
- 3 end-to-end tests through `naive_merge` (bare-char +
backtick-wrapped, both cases).
- 2 parametrized static checks that `re.I` / `re.IGNORECASE` is not
present at either of the two `re.finditer` sites.

## Testing

```
$ pytest test/unit_test/rag/test_delimiter_case_sensitive.py -v
============================= 9 passed in 0.19s ==============================
```

All tests pass on the patched code. Before the patch, the 2 static
checks fail with a clear assertion message (the 7 behavioral tests pass
either way, confirming `re.I` was dead code).

## Related

- #17384 — the issue this PR closes. Note the issue's reproduction code
(`re.split(..., flags=re.I)`) doesn't actually match what the production
code does — the production `re.split` calls all omit `re.I`, which is
why current behavior is already case-sensitive. The fix here is still
valuable as a defensive cleanup + test coverage, but it's not a
behavioral fix per se.
- #17383 — broader parser consolidation (six implementations → one). The
fix here is independent and small enough to land first.
- #17385 — sibling UX PR (tooltip + live preview). Files are disjoint
(`web/src/**` vs `rag/nlp/**` + `deepdoc/parser/**`), so no interaction.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-31 22:59:12 +08:00
Zhichang Yu
b811dce1b0 feat(go): port knowledge compilation template/group + wiki artifact/nav/skill REST APIs from Python (#17656) 2026-07-31 22:57:43 +08:00
Harsh Kashyap
d67d14e4c6 fix(common/misc_utils): allow once decorator retries after failure (#16174)
### What problem does this PR solve?
`common/misc_utils.once` set `executed=True` before invoking the wrapped
function, so an exception on the first call permanently disabled future
calls and returned the cached `None`.

This change marks `executed=True` only after a successful call, allowing
retries after transient failures while preserving once-only behavior
after success. It also adds regression tests for retry-after-exception
and thread-safe single execution.

### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)

---------

Co-authored-by: Harsh Kashyap <harshkashyap@Harshs-MacBook-Pro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-07-31 22:43:18 +08:00
Loi Nguyen
1b5ce4c27e docs(api): use dataset_id in retrieval example (#17662)
### What problem does this PR solve?

Fixes #17623 by updating the retrieval API response example to use
`dataset_id`, matching the actual `POST /api/v1/retrieval` response
field and the implementation mapping from internal `kb_id`.

Co-authored-by: Codex <codex@openai.com>
2026-07-31 22:41:54 +08:00
Jin Hai
34b99046a8 Go: fix migration (#17659)
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-07-31 21:01:10 +08:00
Haruko386
ae8c18bb17 fix: team member can edit permission (#17633)
### Summary

As title
2026-07-31 20:14:35 +08:00
Haruko386
714defbebe fix: team member can edit permission (#17631)
### Summary

As title
2026-07-31 20:14:17 +08:00
Jin Hai
b058229ab3 Go: fix SSRF (#17641)
### Summary

Check the URL to prevent SSRF attack.

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
dev-20260731-3
2026-07-31 19:15:38 +08:00
Wang Qi
f03a00c54c Update wording for empty response to support only Naive (#17651) 2026-07-31 19:15:05 +08:00
euvre
29e5181095 fix: don't persist ephemeral sessions in multi-model chat completions (#17637) 2026-07-31 19:12:24 +08:00
euvre
e1f724b691 Fix: Enforce the 4 MB size limit for avatar image uploads (#17642) 2026-07-31 19:04:10 +08:00
rayhan
1116fd0f22 fix: remediate CVE-2026-59939 by constraining httplib2 to >=0.32.0 (#17636)
## Summary
  
Remediates CVE-2026-59939 (HIGH) in `httplib2` by adding
`httplib2>=0.32.0` to `constraint-dependencies` in `pyproject.toml`.
  
  | CVE | Severity | Package | Installed | Fixed in |
  |---|---|---|---|---|
  | CVE-2026-59939 | HIGH | httplib2 | 0.31.0 | 0.32.0 |
  
`httplib2` is a transitive dependency pulled in by
`google-api-python-client` and `google-auth-httplib2`. Both declare
`httplib2<1.0.0,>=0.19.0`, allowing 0.32.0 without conflict.
2026-07-31 18:55:56 +08:00
iridescentWen
80b23349a9 refactor: remove unused contentToText helper from Ollama driver (#17639) 2026-07-31 18:52:39 +08:00
Abhay Yadav
c8fbd97595 fix(go): send Gemini system prompts via system_instruction instead of user turn (#17449) 2026-07-31 18:40:11 +08:00
jay77721
fe02c9b95f feat(go-models): unify OpenAI-compatible token usage extraction (#17634)
## Summary
Relate to #17284 .

- Add `usage_parser.go`: `extractOpenAIUsage` /
`extractOpenAIStreamUsage`
  with multi-field fallback (`prompt_tokens`/`input_tokens`,
  `completion_tokens`/`output_tokens`).
- Add `parser_config.go`: `ParserConfig` struct and
`OpenAIParserConfig`.
- Add `response_handler.go`: `HandleNonStreamingResponse` /
  `HandleStreamingResponse` as single entry points that extract usage,
  populate `chatConfig.UsageResult`, and emit a `StreamUsage` log.
- Extend `base_model.go` with `doRequest` / `doStreamRequest`.
- Migrate `deepseek` driver to shared handlers, cutting ~100 lines.
- Add `usage_parser_test.go`.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Haruko386 <tryeverypossible@163.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-07-31 18:32:07 +08:00
Zhichang Yu
29287ef74b refactor(knowledge_compiler): derive variant from template kind via single template id (#17630)
## Summary

Refactor the Go `KnowledgeCompilerComponent` so its parameter is a
**single string template id** instead of a DSL-level `variant` (or
plural group id list). The `variant` is no longer in the DSL — it is now
**derived at runtime from the resolved compilation template's `kind`
field**.

This aligns the Go ingestion port with the frontend Compiler operator,
which emits a singular `compilation_template_group_id` and does not
write `variant` into the generated `compiler.json`.
2026-07-31 18:01:55 +08:00
Hz_
d1127d5973 fix(go-agent): fix Tavily tool array schemas (#17640)
## Summary

- Add string item schemas for Tavily Search domain filters.
- Add the same schema fix for Tavily Extract URLs.
- Add regression coverage for generated tool schemas.

## Testing

- `CGO_ENABLED=0 go test -count=1 ./internal/agent/tool
./internal/agent/component`

<img width="2046" height="622" alt="image"
src="https://github.com/user-attachments/assets/2785a89e-16c9-4222-b434-31d7eb9f3ac9"
/>
2026-07-31 18:00:34 +08:00
Jin Hai
165a5db07d Go: refactor (#17635)
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-07-31 17:48:35 +08:00
Jin Hai
36ae39bc60 Go: refactor config (#17544)
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-07-31 17:18:45 +08:00
Wang Qi
9db2e2314a Refine knownledge compilation REST APIs (#17624) 2026-07-31 17:05:57 +08:00
Lynn
03b7b04e2c Fix: Add missing parameter key for LLM calls (#17628) 2026-07-31 17:05:40 +08:00
Haruko386
0108cdac67 fix: write wrong type of metadata (#17605) 2026-07-31 16:55:34 +08:00
Haruko386
8a66aa7aae feat[Go]: add line chat bot for chat channel (#17594)
### Summary

As title, this can not be tested for now
Close #17520

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-07-31 16:55:05 +08:00
balibabu
4f058667ff Feat: Remove "page index" and "use kg" from chat and retrieval form. (#17627) 2026-07-31 16:40:53 +08:00
balibabu
ec7a9797cb Fix: The wiki's claim card does not display the title. (#17626) dev-20260731-2 2026-07-31 16:28:55 +08:00
Hz_
4a43a1d620 fix(go-agent): align logs auth with Python and harden event data (#17617)
## Summary

- Align Go agent logs access with the Python behavior by checking tenant
access to the target agent instead of requiring the token to be bound
to that agent.
- Marshal canvas lifecycle event payloads safely so non-serializable
inputs do not break Thinking expansion in the UI.

  ## Testing

- `CGO_ENABLED=0 go test -count=1 -v -run
"Handler|Attachment|Logs|Chatbot|Agentbot|BuildWorkflow|NodeLifecycle|VarRef|Resolve|Extract"./internal/handler/
./internal/agent/canvas/...` PASS
2026-07-31 16:24:25 +08:00
euvre
93513eb1fd test: release test_dataset_create_embedding_model_contract for Go proxy (#17620) 2026-07-31 16:04:14 +08:00
Jack
08666560b5 Test(handler): fix failing TestSearchHandlerUpdateRejectsInvalidSearchID assertion (#17622)
### Summary

`TestSearchHandlerUpdateRejectsInvalidSearchID` fails on `main`:

```
--- FAIL: TestSearchHandlerUpdateRejectsInvalidSearchID (0.00s)
    search_handler_test.go:98: expected 'no authorization' in message, got No authorization.
```

`UpdateSearch` answers an unauthorized `search_id` with `"No
authorization."` (`internal/handler/search.go:337`), which mirrors the
Python API's message verbatim, but the assertion searched for the
lowercase `"no authorization"`.

The fix lowercases the response before the substring check rather than
changing the handler's message: the capitalized text is the contract the
Python API exposes, so the test — not the handler — was wrong.

`bash build.sh --test -run TestSearchHandler ./internal/handler/`
passes.
2026-07-31 15:44:49 +08:00
balibabu
f2a45aab14 Fix: Blueprints cannot be displayed when selecting wiki. (#17618) 2026-07-31 15:05:47 +08:00
chanx
efeb4ab870 fix(dataset): echo back selected datasets not in the first page (#17616) 2026-07-31 14:41:54 +08:00
balibabu
51fe08712e Fix: The index textarea in the wiki template can be enlarged. (#17613) 2026-07-31 14:11:26 +08:00
balibabu
b8117812e4 Fix: Cross-language dropdown menu options translation error. (#17615) 2026-07-31 14:11:04 +08:00
Wang Qi
4b619f699b Refactor: consolidate page and page_size (#17597) 2026-07-31 14:08:44 +08:00
balibabu
67f027c306 Feat: Add a link to create a template to the operator parameter of the compiler operator. (#17563) 2026-07-31 13:54:59 +08:00
buua436
7ddf141d2c refa: update LongCat model configuration (#17612) 2026-07-31 13:38:20 +08:00
buua436
44e13d1cb6 feat: add LLM-guided semantic rechunking for knowledge compilation (#17546) 2026-07-31 13:33:30 +08:00
Wang Qi
0969c04eca Feature: GET /datasets to support ids array (#17606) 2026-07-31 13:23:02 +08:00
chanx
e66cfe1372 fix(dataset): apply horizontal layout to auto-keywords and auto-questions form fields (#17608) 2026-07-31 13:20:40 +08:00
chanx
a68db44a6a fix(dataset): update error message for document deletion to use correct translation key (#17603) 2026-07-31 13:20:25 +08:00
chanx
599ada8927 fix(i18n): update thinking status text and add thinking completed feedback (#17602) 2026-07-31 13:20:06 +08:00
Lynn
133d9ad077 Fix: force set enable_thinking to true for preview qwen3 model (#17604) 2026-07-31 13:19:10 +08:00
Jack
8546eb62bf Feat(ingestion): add canvas pipeline debug (dry-run) mode with View result log (#17538)
## Summary
Adds a side-effect-free DataFlow canvas **debug (dry-run) mode** plus a
**debug run log with a "View result" panel**, so a canvas can be
executed synchronously and inspected end-to-end (per-component progress
and parsed chunks) without persisting anything.

### Dry-run execution (inline parsed chunks)
- `task/debug.go`: `NewDebugTaskContext` builds an in-memory
`TaskContext` with **`KB.ID == ""` — the single debug signal used across
the ingestion pipeline**. A canvas debug run has no knowledgebase, and
production ingestion always supplies one, so `kb_id == ""` occurs ONLY
in debug mode. Components gate their own side effects on this signal
without any dedicated debug vocabulary (the former `CANVAS_DEBUG_DOC_ID`
marker constant is removed).
- `task/pipeline_executor.go`: `validateTaskContext` no longer requires
a KB when `KB.ID == ""` (debug); debug runs return `collectDebugOutput`
(chunks) instead of a no-op; uploaded bytes are delivered as
`inputs['binary']` for doc-less runs; `injectDebugPageCap` caps the
parser to the first pages for a fast preview via the production
`override_params` channel (Parser cpnID + family).
- `component/tokenizer.go`: `shouldHaveEmbedding` skips embedding when
`kb_id == ""` — the embedder is configured on the knowledgebase, so a
debug run has nothing to resolve against and stays side-effect free.
- `chunker/register.go`: chunk images are uploaded to MinIO only when a
KB is present (persist run). **In debug mode the raw image bytes are
intentionally dropped (`delete(ck, "image")`)** — the debug preview does
not render chunk images, and dropping the bytes keeps them out of memory
and out of the Redis-stored debug log. This is a deliberate trade-off,
not an oversight.
- `component/file.go`: pass through in-memory binary bytes, skipping
`doc_id` -> storage resolution.
- `handler/agent.go` + `agent_webhook.go`: detect `dataflow_canvas` and
run a sync debug returning chunks inline on the existing
chat/completions endpoint; reject DataFlow canvases from webhooks (fixes
the previously dead `== "DataFlow"` check; mirrors Python
`agent_api.py`).
- `parser_dispatch.go`: export `ParserFileFamily` for the executor's
page-cap injection.

### Debug run log + "View result"
Mirrors Python's debug-log contract so the front-end can replay each
component's progress and parsed output:
- `task/debug_log_sink.go`: a `DebugLogSink` records every component's
lifecycle into a `[{component_id, trace}]` array (each trace entry
carries `message`, `progress`, `timestamp`, `elapsed_time`). `Flush`
appends a terminal `END` marker whose first trace message is non-empty
so the front-end detects completion. On failure the END marker is
prefixed `[ERROR]` yet still carries the run, so the failure timeline
renders instead of being stuck empty. Timestamps and `elapsed_time` are
in seconds (matching the rest of the app).
- `task/debug_result_dsl.go`: `BuildDebugResultDSL` builds the `dsl` the
END marker carries — the Go analogue of Python's `Graph.__str__` +
END-marker `dsl` in `rag/flow/pipeline.py`. It combines the static DSL
structure (component_name / downstream / params / graph.nodes) with the
run output map (`output["state"][<id>]`) to emit, per component,
`obj.params.outputs[<format>].value` (chunks / text / json / html /
markdown) — the exact keys the front-end `dataflow-result` page reads to
render each step's parsed chunks. Raw embedding vectors (including the
dimension-scoped `q_<dim>_vec` keys) are stripped so the stored log
stays Python-scale.
- `task/pipeline_executor.go`: after the run, attach the built `dsl` to
the END marker via the `ResultSink` capability.
- `handler/agent.go`: `runCanvasPipelineDebug` generates a stable
`message_id` up-front and always flushes the log (success or failure);
`respondWithDebugResult` returns `message_id` in **both** the success
and the error envelope so the front-end can poll the log. The debug-log
endpoint `GET /agents/:id/logs/:message_id` serves the array.
- `web/src/pages/agent/hooks/use-run-dataflow.ts`: on a run failure,
also surface `message_id` via `setMessageId` so the log sheet renders
the failure timeline (the `[ERROR]` END marker is already written).
Guarded by `if (msgId)`, so it is a safe no-op when the back-end does
not return an id.

## Behavioral notes
- Debug parses only the first pages (`debugPageCapPages`) for a fast
preview; an explicit `pages` cap already present in the ParserConfig is
respected.
- Debug mode does not keep chunk images (see above) and does not compute
embeddings — it exercises parse + chunk only.

## Test plan
- Go: `debug_test.go`, `debug_log_sink_test.go` (trace pairing, END
marker, `[ERROR]` prefix, fractional-second timestamp/elapsed_time, size
caps, and a real-pipeline test asserting the END-marker `dsl` carries
non-empty per-component `params.outputs` with chunks),
`debug_result_dsl_test.go` (flat and real nested `output["state"]`
shapes, vector stripping, format priority),
`debug_pages_integration_test.go`, `pipeline_executor_persist_test.go`,
`handler/agent_pipeline_debug_test.go`, `handler/agent_logs_test.go`
(incl. `TestRunCanvasPipelineDebug_ErrorStillExposesMessageID` /
`TestRespondWithDebugResult_ErrorCarriesMessageID` locking `message_id`
on failure), plus updates to `agent_test.go` / `agent_webhook_test.go` /
`chunker/image_upload_test.go` / `tokenizer*.go`.
- `go build ./...` and `./build.sh --test` for affected packages.

🤖 Generated with [CodeBuddy Code](https://cnb.cool/codebuddy)

---------

Co-authored-by: CodeBuddy Code <noreply@tencent.com>
2026-07-31 13:10:08 +08:00
Jack
de17dda5f8 fix(parser): derive eng from content for DOCX/HTML TOC removal (#17585)
## Summary
- The `eng` flag passed to `removeTOCWord`/`removeContentsTable` was
hardcoded `false`, so English documents used the CJK 3-char TOC prefix
instead of Python's 2-word English prefix. This caused English tables of
contents to be under-deleted (left in indexed text) or over-deleted
(body paragraphs sharing the 3-char prefix dropped).
- `eng` is now derived from the parsed item content via `isEnglishItems`
(a port of Python `is_english`/`_is_english`), mirroring Python's
content heuristic.

## Changes
- `internal/parser/parser/text_toc.go`: add
`isEnglishItems`/`isEnglishTexts` (ASCII-ratio >80% ⇒ English,
fullmatch-anchored regex).
- `internal/parser/parser/docx_parser.go`: pass
`isEnglishItems(sections)` / `isEnglishItems(lineItems)` to
`removeTOCWord` (json + markdown paths).
- `internal/parser/parser/html_parser.go`: pass `isEnglishItems(items)`
to `removeContentsTable`.
- `docs/migration_python_go_diff.md`: close the 1.9/1.10 `eng` residual
and resolve the contradictory Parser 2.11 "Partially fixed" note.

## Notes
- `remove_toc` is a Parser-stage, DSL-configured feature (`remove_toc:
true/false` in the parser family setup). This change only fixes the
internal English/CJK prefix decision; it does not alter the pipeline or
the DSL contract. `remove_header_footer` (precise match) is unaffected.
- `eng` is auto-derived from content rather than exposed as a new config
knob, to stay faithful to Python behavior.

## Test plan
- `CGO_ENABLED=0 go test ./internal/parser/parser/ -run
'TestRemoveContentsTable|TestIsEnglishTexts|TestRemoveTOCWordEnglishDetection'`
- Added `TestIsEnglishTexts` (ASCII-ratio cases) and
`TestRemoveTOCWordEnglishDetection` (English TOC no longer over-deletes
"Chapter 2 Method").

---------

Co-authored-by: CodeBuddy <noreply@codebuddy.ai>
2026-07-31 13:09:02 +08:00
jay77721
cef23ce686 fix(channels): rename stringValue to anyToString in qqbot.go to resolve redeclaration (#17610)
## Summary
- Fixes a compile error in `internal/channels/qqbot.go`: the local
`stringValue(value any)` helper collided with the existing
`stringValue(value *string)` in `feishu.go` within the same package
(`stringValue redeclared in this block`).
- Rename the qqbot variant to `anyToString` (definition + 13 call
sites). The two helpers do different jobs (any->string via `fmt.Sprint`
vs. `*string` deref), so they are not merged.
2026-07-31 12:17:25 +08:00
Jack
5ba8c4febb chore(go): classify tests into unit/integration/e2e/manual tiers via build tags (#17586)
## Summary
Classify the Go test suite by dependency level using build tags so the
default
`go test ./...` run stays self-contained, and add local convenience
commands
plus a documented convention.

- Add build tags to 5 real-service tests that were previously un-tagged
and only
soft-isolated via `t.Skip`: `kg_test.go` (integration), `minio_test.go`
  (integration), `template_integration_test.go` (integration),
`stagehand_runtime_integration_test.go` (integration),
`pipeline_e2e_test.go` (e2e).
  The default unit run no longer compiles/attempts these.
- Reclassify the full-pipeline `real_consumer` tests from `integration`
to `e2e`.
- Add `build.sh` shortcuts: `--test-integration`, `--test-e2e`,
`--test-manual`,
`--test-all` (integration + e2e; `manual` is excluded and is local
opt-in only,
  never run in CI).
- Document the tier scheme (unit / integration / e2e / manual +
orthogonal cgo) in
  `AGENTS.md`.

## Tier definitions
| Tier | Build tag | Runs by default? |
|---|---|---|
| Unit | (none) | Yes — in-memory SQLite / miniredis / httptest stubs |
| Integration | `integration` | No (`-tags integration`) — single real
service |
| E2E | `e2e` | No (`-tags e2e`) — full ingest→index→retrieve pipeline |
| Manual | `manual` | No (`-tags manual`) — very slow; never in CI |

## Verification
- `gofmt -l` clean on all changed files; `bash -n build.sh` OK.
- `go list` confirms the default set excludes the tagged files, and
  `-tags integration` / `-tags e2e` include them.
- Full regression: unit / integration / e2e each **97 ok, 0 FAIL**.
- Fixed a regression where `pipeline_knowledge_compiler_test.go` relied
on a
transitive import side-effect from `template_integration_test.go` to
register
the `File`/`Parser`/`TokenChunker` components; it now blank-imports the
  component packages directly.

## Test plan
- [ ] `./build.sh --test` (unit) passes
- [ ] `./build.sh --test-integration` passes (needs real services; skips
otherwise)
- [ ] `./build.sh --test-e2e` passes (needs real services; skips
otherwise)

---------

Co-authored-by: CodeBuddy <noreply@cnb.cool>
2026-07-31 11:52:48 +08:00
Harsh Kashyap
6cb43f74c4 fix(common,internal): round instead of truncate in normalize_overlapped_percent (closes #17418) (#17452) 2026-07-31 11:51:21 +08:00