mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-06 19:38:36 +08:00
eb6ea284a8a0de20317f812f13c2ee17841b39f2
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2f99d52fb5 |
fix(ci): re-enable Go tests and fix compilation errors after ListModels signature change (#15862)
## Summary
This PR re-enables the Go test steps in CI that were previously
commented out, and fixes all compilation errors that have accumulated in
`internal/entity/models/` since the `ListModels` return type was changed
from `[]string` to `[]ListModelResponse`.
## Changes
### CI (`.github/workflows/tests.yml`)
- Re-enable **Prepare test resources** step (clones resource repo with
WordNet data)
- Re-enable **Test Go packages** step (runs `go test ./internal/...`)
- Fix resource path race condition by using
`/tmp/resource-${GITHUB_RUN_ID}` instead of `/tmp/resource`
- Exclude `/cli` package from Go tests (contains `main` redeclarations)
### Test fixes (16 model provider test files)
All errors were caused by the upstream change from `[]string` to
`[]ListModelResponse` in the `ListModels` interface:
- Add `joinModelNames` test helper to extract `.Name` from
`[]ListModelResponse` slices
- `strings.Join(models, ",")` → `joinModelNames(models, ",")` (11 files)
- `ids[i] != "..."` → `ids[i].Name != "..."` (cometapi, mistral)
- `got[i] != want[i]` → `got[i].Name != want[i]` (bedrock)
- `[]string` return types → `[]ListModelResponse` (google)
### Pre-existing bugs in model_test.go
Bugs introduced by the upstream `entity/` → `entity/models/` directory
rename:
- Add missing `pm := GetProviderManager()` calls in 3 test functions
- Fix `InitProviderManager` signature (`_, err :=` → `err :=`)
- Fix `MaxTokens` `*int` dereference (6 comparisons)
- Fix `readProviderConfig` relative path (3 levels up instead of 2)
### model.go
- Add `findRepoRoot()` to make `conf/all_models.json` resolution work
from any CWD, fixing `TestSiliconFlowProviderConfigLoadsLatestProModels`
### Test validation
```bash
go build ./internal/... # ✅
go test ./internal/entity/models/... -count=1 # ✅ all pass
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
04aa8d04e8 |
fix(go-models): raise SSE scanner buffer so large stream chunks are not dropped (#15382)
### Summary Closes #15381 Every provider in `internal/entity/models/` reads its streaming response with `bufio.NewScanner(resp.Body)` and iterates over `scanner.Scan()`. The default `bufio.Scanner` maximum token size is 64KB, so when an upstream sends a single SSE `data:` line larger than 64KB (long content deltas, large tool or function call argument blobs, bundled `reasoning_content`, or providers that emit a whole message in one event) `scanner.Scan()` returns `false` and `scanner.Err()` returns `bufio.ErrTooLong`. Streaming chat then ends with an error partway through the response. This change adds `scanner.Buffer(make([]byte, 64*1024), 1024*1024)` immediately after every SSE scanner that was still bare, raising the cap to 1MB. 1MB is the value already used for streaming chat in `openai.go`, `modelscope.go`, `groq.go`, `mistral.go`, `xai.go` and the other already patched providers (the 8MB cap in the repo is reserved for TTS and embedding paths), so this simply converges the remaining providers onto the established pattern. Nothing else changes: line parsing, `data:` prefix handling, `[DONE]` detection, JSON unmarshalling, error handling, and the existing `scanner.Err()` checks all stay the same. Providers covered (23 scanners across 22 files): 302ai, aliyun, baichuan, baidu, cohere, deepinfra, deepseek, gitee, huggingface, lmstudio, minimax (the chat scanner, whose TTS scanner was already bumped), moonshot, nvidia, ollama, openrouter, orcarouter, paddleocr, siliconflow, tokenhub, vllm, volcengine, xunfei, zhipu-ai. `jiekouai.go` is excluded because it is covered by the in flight #15337. A table driven regression test (`sse_scanner_buffer_test.go`) streams a single 128KB `data:` content delta followed by `data: [DONE]` through an `httptest` server and asserts that `ChatStreamlyWithSender` delivers the full content with no error across a representative subset of providers. Without the buffer fix the test fails with `bufio.Scanner: token too long`. This PR also removes three duplicate declarations of the package level `roundTripperFunc` test helper that several recently merged provider PRs each added independently, which had left the `internal/entity/models` test package unable to compile. The helper now lives in a single place and is shared. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) |
||
|
|
ff9aa4e2c7 |
fix(go-models): harden LongCat default transport handling (#15340)
## Summary - Harden `NewLongCatModel` to avoid panics when `http.DefaultTransport` is a custom non-`*http.Transport` RoundTripper. - Fallback to a safe transport (`ProxyFromEnvironment`) while preserving existing pooling/timeout settings. - Add `TestLongCatNewModelWithCustomDefaultTransport` regression coverage. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
22a3b8cdf9 |
feat(go-models): list LongCat models (#15241)
## Summary - Add LongCat model-list support through the documented OpenAI-compatible models endpoint. ## What changed - Add the LongCat `models` URL suffix for `/openai/v1/models`. - Implement `ListModels` for the LongCat Go driver. - Delegate `CheckConnection` to the lightweight model-list request. - Add focused regression coverage for successful, malformed, oversized, and missing-key responses. ## Why LongCat documents a models endpoint under the OpenAI-compatible API surface, but the Go driver still returned `no such method` for model listing and connection checks. ## Validation - `go test ./internal/entity/models -run TestLongCat -count=1` - `go test -race ./internal/entity/models -run TestLongCat -count=1` - `go test ./internal/entity -count=1` - `git diff --check` ## Notes - Related to the broader Go model provider tracking in #14736, but this PR only handles LongCat model listing. - `go test ./internal/entity/models -count=1` is currently blocked by an unrelated Astraflow test panic outside this LongCat change. --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com> |
||
|
|
cb01529d8b |
Go: implement provider: Voyage AI (#14811)
### What problem does this PR solve? Add a Go driver for Voyage AI (https://voyageai.com), one of the unchecked providers on the umbrella tracking issue #14736. Voyage AI is **embed + rerank only** — no chat, no streaming, no `/v1/models` endpoint. It's the first provider in the Go layer of this shape. Until this PR, a tenant who configured `voyage` as a model provider in the Go layer fell through to the default branch of `internal/entity/models/factory.go` and got the dummy driver. ### What this PR includes - New `internal/entity/models/voyage.go` with a `VoyageModel` implementing the `ModelDriver` interface. - New `conf/models/voyage.json` with 6 embedding models (`voyage-3.5`, `voyage-3.5-lite`, `voyage-3-large`, `voyage-code-3`, `voyage-law-2`, `voyage-finance-2`) and 2 rerank models (`rerank-2`, `rerank-2-lite`). - `factory.go`: route `"voyage"` to `NewVoyageModel`. - `internal/entity/models/voyage_test.go`: 19 unit tests. ### How the driver works - **Embed**: `POST /v1/embeddings`. Response is OpenAI-shaped (`{data: [{embedding, index, object, text}], model, usage}`). Driver reorders by `index`, rejects duplicate / out-of-range / missing slots, and short-circuits empty input without an HTTP call. - **Rerank**: `POST /v1/rerank`. Voyage uses **`top_k`** as the request param name (not `top_n` like Aliyun/SiliconFlow); the driver translates `RerankConfig.TopN` → `top_k`. Response is Cohere-shaped (`{data: [{relevance_score, index}], model}`), so the existing `RerankResponse{Data: []RerankResult{Index, RelevanceScore}}` shape fits cleanly. - **`ListModels`**: returns a hardcoded list of `voyageKnownModels`. Voyage does **not** expose `/v1/models` (probed live, returns 404), so the driver synthesizes the list from the same set the config ships. New upstream models are added by extending one slice. - **`CheckConnection`**: pings a 1-input embed call against `voyage-3.5`. Without `/v1/models`, this is the cheapest way to verify the API key + network path before a tenant tries a real workload. - **`ChatWithMessages` / `ChatStreamlyWithSender` / `Balance` / `TranscribeAudio` / `AudioSpeech` / `OCRFile`**: all return `"no such method"`. Voyage does not host any of these surfaces. No interface change. No new dependencies. ### How was this tested? **19 unit tests** in `internal/entity/models/voyage_test.go` — all pass on go 1.25: ``` $ go test -vet=off -run TestVoyage -count=1 ./internal/entity/models/... ok ragflow/internal/entity/models 0.036s ``` Coverage: Name; Embed (happy path, reorder, empty-input, missing key/model, duplicate index, out-of-range index, missing slot); Rerank (happy path with `top_k` assertion, default-to-len-documents, empty documents, out-of-range index); ListModels (static list, missing key); CheckConnection (happy, 401); chat methods sentinels; Balance sentinel; audio/OCR sentinels. `go build ./internal/entity/models/...` exits 0. **Live integration test** against `api.voyageai.com`: ``` === RUN TestVoyageLiveSmoke [OK] Name() = "voyage" [OK] ListModels (static): 8 models -> [voyage-3.5 voyage-3.5-lite voyage-3-large voyage-code-3 voyage-law-2 voyage-finance-2 rerank-2 rerank-2-lite] [OK] CheckConnection [OK] Embed vectors=3 dim=1024 indices=[0 1 2] [OK] Embed(empty) -> 0 vectors [OK] Rerank results=3 scores=[0.8125 0.59765625 0.39453125] [OK] ChatWithMessages returns voyage, no such method [OK] Balance returns voyage, no such method VOYAGE LIVE SMOKE PASSED --- PASS: TestVoyageLiveSmoke (0.81s) ``` What the live run proves on the wire: - Auth (`Bearer <key>`) accepted by `api.voyageai.com`. - Embed `voyage-3.5` on 3 inputs returns 3 vectors at dim 1024 with `index` field preserved as `[0, 1, 2]` — the reorder-by-index code is exercised on real data. - Empty input short-circuits without an HTTP call (mock server would have been hit if it did). - Rerank `rerank-2` on 3 docs returns 3 real `relevance_score` floats `[0.8125, 0.598, 0.395]`. The `top_k` translation works on the live wire. - All sentinel methods return the documented `"no such method"` strings. ### Note on PR history This branch was previously named for LocalAI Embed work which is now consolidated into PR #14813. The branch was reset to `upstream/main` and rebuilt for Voyage. Diff against `main` is a clean +838 lines across 4 files. ### Type of change - [x] New Feature (non-breaking change which adds functionality) Tracking: #14736 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com> |
||
|
|
8b53960819 |
Go: implement provider: LongCat (#14809)
### What problem does this PR solve? Add a Go driver for LongCat (Meituan, https://longcat.chat), one of the unchecked providers on the umbrella tracking issue #14736. LongCat exposes an OpenAI-compatible REST API at `https://api.longcat.chat/openai/v1` with three public chat models including `LongCat-Flash-Thinking`, a reasoning model that returns chain-of-thought in `reasoning_content` (OpenAI o-series shape). Until this PR, a tenant who configured `longcat` as a model provider in the Go layer fell through to the default branch of `internal/entity/models/factory.go` and got the dummy driver. ### What this PR includes - New `internal/entity/models/longcat.go` with a `LongCatModel` implementing the `ModelDriver` interface. - New `conf/models/longcat.json` with the 3 public chat models (Flash-Chat, Flash-Lite, Flash-Thinking) and `url_suffix` for `chat` and `models`. - `factory.go`: route `"longcat"` to `NewLongCatModel`. Method coverage: - `ChatWithMessages`: `POST /openai/v1/chat/completions`, non-streaming - `ChatStreamlyWithSender`: SSE stream against the same endpoint - `ListModels` / `CheckConnection`: `GET /openai/v1/models` - **Reasoning extraction**: `message.reasoning_content` (non-stream) and `delta.reasoning_content` (stream) flow into `ChatResponse.ReasonContent` / the sender's second arg. Matches the OpenAI o-series convention also used by kimi-k2.6 and DeepSeek-R1. - **`reasoning_effort` propagation**: `ChatConfig.Effort` → request body `reasoning_effort` (LongCat-Flash-Thinking honors it; non-reasoning models ignore it). - `Embed` / `Rerank` / `Balance` / `TranscribeAudio` / `AudioSpeech` / `OCRFile` return `"no such method"` (LongCat does not expose any of these surfaces). No interface change. No new dependencies. ### How was this tested? **21 unit tests** in `internal/entity/models/longcat_test.go` — all pass: ``` $ go test -vet=off -run TestLongCat -count=1 -v ./internal/entity/models/... === RUN TestLongCatName --- PASS: TestLongCatName (0.00s) === RUN TestLongCatChatHappyPath --- PASS: TestLongCatChatHappyPath (0.00s) === RUN TestLongCatChatExtractsReasoningContent --- PASS: TestLongCatChatExtractsReasoningContent (0.00s) === RUN TestLongCatChatPropagatesReasoningEffort --- PASS: TestLongCatChatPropagatesReasoningEffort (0.00s) === RUN TestLongCatChatOmitsReasoningEffortWhenUnset --- PASS: TestLongCatChatOmitsReasoningEffortWhenUnset (0.00s) === RUN TestLongCatChatRequiresAPIKey --- PASS: TestLongCatChatRequiresAPIKey (0.00s) === RUN TestLongCatChatRequiresMessages --- PASS: TestLongCatChatRequiresMessages (0.00s) === RUN TestLongCatChatRejectsHTTPError --- PASS: TestLongCatChatRejectsHTTPError (0.00s) === RUN TestLongCatStreamHappyPath --- PASS: TestLongCatStreamHappyPath (0.00s) === RUN TestLongCatStreamExtractsReasoningContent --- PASS: TestLongCatStreamExtractsReasoningContent (0.00s) === RUN TestLongCatStreamRejectsExplicitFalse --- PASS: TestLongCatStreamRejectsExplicitFalse (0.00s) === RUN TestLongCatStreamRequiresSender --- PASS: TestLongCatStreamRequiresSender (0.00s) === RUN TestLongCatStreamFailsWithoutTerminal --- PASS: TestLongCatStreamFailsWithoutTerminal (0.00s) === RUN TestLongCatListModelsHappyPath --- PASS: TestLongCatListModelsHappyPath (0.00s) === RUN TestLongCatListModelsRequiresAPIKey --- PASS: TestLongCatListModelsRequiresAPIKey (0.00s) === RUN TestLongCatCheckConnectionDelegatesToListModels --- PASS: TestLongCatCheckConnectionDelegatesToListModels (0.00s) === RUN TestLongCatEmbedReturnsNoSuchMethod --- PASS: TestLongCatEmbedReturnsNoSuchMethod (0.00s) === RUN TestLongCatRerankReturnsNoSuchMethod --- PASS: TestLongCatRerankReturnsNoSuchMethod (0.00s) === RUN TestLongCatBalanceReturnsNoSuchMethod --- PASS: TestLongCatBalanceReturnsNoSuchMethod (0.00s) === RUN TestLongCatAudioOCRReturnNoSuchMethod --- PASS: TestLongCatAudioOCRReturnNoSuchMethod (0.00s) PASS ok ragflow/internal/entity/models 0.020s ``` `go build ./internal/entity/models/...` exits 0 on go 1.25. **Live integration test** against `api.longcat.chat`: ``` === RUN TestLongCatLiveSmoke [OK] Name() = "longcat" [OK] CheckConnection [OK] ListModels: 5 models -> [LongCat-Flash-Lite LongCat-Flash-Chat LongCat-Flash-Thinking-2601 LongCat-Flash-Omni-2603 LongCat-2.0-Preview] [OK] Chat (Flash-Chat) answer="Got it! Let me know if you" reason="" [OK] Chat (Flash-Thinking) answer len=443 head="To find 15 % of 80, follow these steps:\n\n1. **Convert the percentage to a frac..." ReasonContent len=557 head="The user asks: \"15% of 80?\" They want step by step reasoning and final answer in \\boxed{}. So we need to compute 15% of ..." [OK] Stream content: 78 chunks, 351 chars [OK] Stream reasoning: 107 chunks, 537 chars [OK] Balance returns longcat, no such method [OK] Embed returns longcat, no such method [OK] Rerank returns longcat, no such method LONGCAT LIVE SMOKE PASSED --- PASS: TestLongCatLiveSmoke (31.01s) ``` What the live run proves on the wire: - Auth header (`Bearer <key>`) is accepted by `api.longcat.chat`. - `/openai/v1/models` parser handles the real 5-model response (note: live API returns versioned aliases `LongCat-Flash-Thinking-2601`, `LongCat-Flash-Omni-2603`, `LongCat-2.0-Preview` plus the un-versioned `LongCat-Flash-Chat` and `LongCat-Flash-Lite`). - Non-stream chat against `LongCat-Flash-Chat`: visible answer parses correctly, `ReasonContent` correctly empty. - Non-stream chat against `LongCat-Flash-Thinking`: 443-char answer flows into `Answer`, 557-char chain-of-thought flows into `ReasonContent` via the new `message.reasoning_content` extraction. - Streaming chat against `LongCat-Flash-Thinking`: 107 reasoning chunks (537 chars) reach the sender's second arg via `delta.reasoning_content`; 78 content chunks (351 chars) reach the first arg. Before this code, the reasoning chunks would have been silently dropped. - All sentinel methods (Balance, Embed, Rerank, audio/OCR) return the documented `"no such method"` strings. ### Note on PR history This branch was previously named for LocalAI work which is now consolidated into PR #14813. The branch was reset to `upstream/main` and rebuilt for LongCat. The diff against `main` is a clean +969 lines across 4 files. ### Type of change - [x] New Feature (non-breaking change which adds functionality) Tracking: #14736 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com> |