@zvec/zvec-grep 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -236
- package/README_CN.md +142 -233
- package/dist/authorization/index.d.ts +7 -0
- package/dist/authorization/index.js +7 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/authorization/manager.d.ts +8 -0
- package/dist/authorization/manager.js +19 -0
- package/dist/authorization/manager.js.map +1 -0
- package/dist/authorization/operation.d.ts +7 -0
- package/dist/authorization/operation.js +50 -0
- package/dist/authorization/operation.js.map +1 -0
- package/dist/authorization/planner.d.ts +21 -0
- package/dist/authorization/planner.js +97 -0
- package/dist/authorization/planner.js.map +1 -0
- package/dist/authorization/prompt.d.ts +11 -0
- package/dist/authorization/prompt.js +62 -0
- package/dist/authorization/prompt.js.map +1 -0
- package/dist/authorization/store.d.ts +20 -0
- package/dist/authorization/store.js +251 -0
- package/dist/authorization/store.js.map +1 -0
- package/dist/authorization/target.d.ts +15 -0
- package/dist/authorization/target.js +49 -0
- package/dist/authorization/target.js.map +1 -0
- package/dist/authorization/types.d.ts +61 -0
- package/dist/authorization/types.js +2 -0
- package/dist/authorization/types.js.map +1 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.js +338 -55
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth.d.ts +21 -0
- package/dist/cli/auth.js +209 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/commands.js +469 -625
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/errors.js +2 -2
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/format/context.d.ts +4 -0
- package/dist/cli/format/context.js +311 -44
- package/dist/cli/format/context.js.map +1 -1
- package/dist/cli/format/debug.js +12 -6
- package/dist/cli/format/debug.js.map +1 -1
- package/dist/cli/format/progress.d.ts +4 -0
- package/dist/cli/format/progress.js +219 -46
- package/dist/cli/format/progress.js.map +1 -1
- package/dist/cli/format/status.d.ts +79 -6
- package/dist/cli/format/status.js +341 -111
- package/dist/cli/format/status.js.map +1 -1
- package/dist/cli/help.js +395 -63
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/install.d.ts +4 -0
- package/dist/cli/install.js +963 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/managed-rg.d.ts +10 -0
- package/dist/cli/managed-rg.js +329 -0
- package/dist/cli/managed-rg.js.map +1 -0
- package/dist/cli/server-search.d.ts +3 -0
- package/dist/cli/server-search.js +12 -0
- package/dist/cli/server-search.js.map +1 -0
- package/dist/cli/types.d.ts +23 -6
- package/dist/cli/types.js.map +1 -1
- package/dist/client/daemon-client.d.ts +31 -0
- package/dist/client/daemon-client.js +203 -0
- package/dist/client/daemon-client.js.map +1 -0
- package/dist/client/mode-router.d.ts +9 -0
- package/dist/client/mode-router.js +28 -0
- package/dist/client/mode-router.js.map +1 -0
- package/dist/client/search-policy.d.ts +11 -0
- package/dist/client/search-policy.js +15 -0
- package/dist/client/search-policy.js.map +1 -0
- package/dist/daemon/backend.d.ts +77 -0
- package/dist/daemon/backend.js +1087 -0
- package/dist/daemon/backend.js.map +1 -0
- package/dist/daemon/change-set.d.ts +25 -0
- package/dist/daemon/change-set.js +101 -0
- package/dist/daemon/change-set.js.map +1 -0
- package/dist/daemon/config.d.ts +24 -0
- package/dist/daemon/config.js +88 -0
- package/dist/daemon/config.js.map +1 -0
- package/dist/daemon/errors.d.ts +5 -0
- package/dist/daemon/errors.js +11 -0
- package/dist/daemon/errors.js.map +1 -0
- package/dist/daemon/http-server.d.ts +30 -0
- package/dist/daemon/http-server.js +288 -0
- package/dist/daemon/http-server.js.map +1 -0
- package/dist/daemon/index-coordinator.d.ts +24 -0
- package/dist/daemon/index-coordinator.js +68 -0
- package/dist/daemon/index-coordinator.js.map +1 -0
- package/dist/daemon/job-scheduler.d.ts +70 -0
- package/dist/daemon/job-scheduler.js +366 -0
- package/dist/daemon/job-scheduler.js.map +1 -0
- package/dist/daemon/logger.d.ts +9 -0
- package/dist/daemon/logger.js +53 -0
- package/dist/daemon/logger.js.map +1 -0
- package/dist/daemon/model-pool.d.ts +45 -0
- package/dist/daemon/model-pool.js +187 -0
- package/dist/daemon/model-pool.js.map +1 -0
- package/dist/daemon/root-lease.d.ts +14 -0
- package/dist/daemon/root-lease.js +188 -0
- package/dist/daemon/root-lease.js.map +1 -0
- package/dist/daemon/root-runtime.d.ts +78 -0
- package/dist/daemon/root-runtime.js +333 -0
- package/dist/daemon/root-runtime.js.map +1 -0
- package/dist/daemon/runtime-manager.d.ts +46 -0
- package/dist/daemon/runtime-manager.js +246 -0
- package/dist/daemon/runtime-manager.js.map +1 -0
- package/dist/daemon/runtime.d.ts +12 -0
- package/dist/daemon/runtime.js +102 -0
- package/dist/daemon/runtime.js.map +1 -0
- package/dist/daemon/server-controller.d.ts +39 -0
- package/dist/daemon/server-controller.js +254 -0
- package/dist/daemon/server-controller.js.map +1 -0
- package/dist/daemon/watch-manager.d.ts +50 -0
- package/dist/daemon/watch-manager.js +293 -0
- package/dist/daemon/watch-manager.js.map +1 -0
- package/dist/daemon/workspace-read-session-cache.d.ts +31 -0
- package/dist/daemon/workspace-read-session-cache.js +115 -0
- package/dist/daemon/workspace-read-session-cache.js.map +1 -0
- package/dist/engine/code-formats.d.ts +3 -0
- package/dist/engine/code-formats.js +14 -0
- package/dist/engine/code-formats.js.map +1 -0
- package/dist/engine/config.d.ts +30 -8
- package/dist/engine/config.js +171 -45
- package/dist/engine/config.js.map +1 -1
- package/dist/engine/{errors/index.d.ts → errors.d.ts} +6 -1
- package/dist/engine/{errors/details.js → errors.js} +17 -4
- package/dist/engine/errors.js.map +1 -0
- package/dist/engine/extraction/code/adapter.d.ts +1 -1
- package/dist/engine/extraction/code/adapter.js +1 -1
- package/dist/engine/extraction/code/adapter.js.map +1 -1
- package/dist/engine/extraction/code/extractor.d.ts +5 -11
- package/dist/engine/extraction/code/extractor.js +116 -48
- package/dist/engine/extraction/code/extractor.js.map +1 -1
- package/dist/engine/extraction/code/families/c-family.js +1 -1
- package/dist/engine/extraction/code/families/c-family.js.map +1 -1
- package/dist/engine/extraction/code/families/js-ts.d.ts +1 -1
- package/dist/engine/extraction/code/families/metadata.d.ts +1 -1
- package/dist/engine/extraction/code/tree-sitter/grammar.js.map +1 -0
- package/dist/engine/extraction/code/tree-sitter/nodes.js.map +1 -0
- package/dist/engine/extraction/code/tree-sitter/parser.js.map +1 -0
- package/dist/engine/extraction/image/extractor.d.ts +5 -0
- package/dist/engine/extraction/image/extractor.js +35 -0
- package/dist/engine/extraction/image/extractor.js.map +1 -0
- package/dist/engine/extraction/index.d.ts +4 -44
- package/dist/engine/extraction/index.js +2 -280
- package/dist/engine/extraction/index.js.map +1 -1
- package/dist/engine/extraction/markdown/extractor.d.ts +5 -11
- package/dist/engine/extraction/markdown/extractor.js +38 -17
- package/dist/engine/extraction/markdown/extractor.js.map +1 -1
- package/dist/engine/extraction/runtime.d.ts +4 -0
- package/dist/engine/extraction/runtime.js +26 -0
- package/dist/engine/extraction/runtime.js.map +1 -0
- package/dist/engine/extraction/source.d.ts +18 -0
- package/dist/engine/extraction/source.js +22 -0
- package/dist/engine/extraction/source.js.map +1 -0
- package/dist/engine/extraction/text/extractor.d.ts +7 -0
- package/dist/engine/extraction/text/extractor.js +168 -0
- package/dist/engine/extraction/text/extractor.js.map +1 -0
- package/dist/engine/extraction/types.d.ts +4 -0
- package/dist/engine/{models → extraction}/types.js.map +1 -1
- package/dist/engine/extraction/vector-content.d.ts +5 -0
- package/dist/engine/extraction/vector-content.js +95 -0
- package/dist/engine/extraction/vector-content.js.map +1 -0
- package/dist/engine/file-size-policy.d.ts +6 -0
- package/dist/engine/file-size-policy.js +20 -0
- package/dist/engine/file-size-policy.js.map +1 -0
- package/dist/engine/file-type.d.ts +15 -0
- package/dist/engine/file-type.js +152 -0
- package/dist/engine/file-type.js.map +1 -0
- package/dist/engine/index-status.d.ts +9 -0
- package/dist/engine/index-status.js +38 -0
- package/dist/engine/index-status.js.map +1 -0
- package/dist/engine/manifest.d.ts +13 -0
- package/dist/engine/manifest.js +124 -0
- package/dist/engine/manifest.js.map +1 -0
- package/dist/engine/models/{providers/llama-cpp/embedding.d.ts → backends/llama-cpp.d.ts} +25 -20
- package/dist/engine/models/{providers/llama-cpp/embedding.js → backends/llama-cpp.js} +127 -106
- package/dist/engine/models/backends/llama-cpp.js.map +1 -0
- package/dist/engine/models/backends/model2vec-runtime.d.ts +63 -0
- package/dist/engine/models/backends/model2vec-runtime.js +112 -0
- package/dist/engine/models/backends/model2vec-runtime.js.map +1 -0
- package/dist/engine/models/backends/model2vec-tokenizer.d.ts +2 -0
- package/dist/engine/models/backends/model2vec-tokenizer.js +42 -0
- package/dist/engine/models/backends/model2vec-tokenizer.js.map +1 -0
- package/dist/engine/models/backends/model2vec-worker-pool.d.ts +25 -0
- package/dist/engine/models/backends/model2vec-worker-pool.js +264 -0
- package/dist/engine/models/backends/model2vec-worker-pool.js.map +1 -0
- package/dist/engine/models/backends/model2vec-worker.d.ts +1 -0
- package/dist/engine/models/backends/model2vec-worker.js +41 -0
- package/dist/engine/models/backends/model2vec-worker.js.map +1 -0
- package/dist/engine/models/backends/model2vec.d.ts +40 -0
- package/dist/engine/models/backends/model2vec.js +311 -0
- package/dist/engine/models/backends/model2vec.js.map +1 -0
- package/dist/engine/models/backends/qwen.d.ts +44 -0
- package/dist/engine/models/{providers/qwen/embedding.js → backends/qwen.js} +155 -94
- package/dist/engine/models/backends/qwen.js.map +1 -0
- package/dist/engine/models/backends/transformers-js.d.ts +87 -0
- package/dist/engine/models/backends/transformers-js.js +316 -0
- package/dist/engine/models/backends/transformers-js.js.map +1 -0
- package/dist/engine/models/catalog.d.ts +207 -23
- package/dist/engine/models/catalog.js +191 -25
- package/dist/engine/models/catalog.js.map +1 -1
- package/dist/engine/models/download-progress.d.ts +15 -0
- package/dist/engine/models/download-progress.js +48 -0
- package/dist/engine/models/download-progress.js.map +1 -0
- package/dist/engine/models/embeddings.d.ts +59 -18
- package/dist/engine/models/embeddings.js +52 -28
- package/dist/engine/models/embeddings.js.map +1 -1
- package/dist/engine/models/factory.d.ts +2 -5
- package/dist/engine/models/factory.js +41 -56
- package/dist/engine/models/factory.js.map +1 -1
- package/dist/engine/models/index.d.ts +4 -6
- package/dist/engine/models/index.js +4 -4
- package/dist/engine/models/index.js.map +1 -1
- package/dist/engine/models/ranking.d.ts +7 -3
- package/dist/engine/models/resolution.d.ts +8 -0
- package/dist/engine/models/resolution.js +22 -0
- package/dist/engine/models/resolution.js.map +1 -0
- package/dist/engine/pipeline/indexing/index.d.ts +9 -7
- package/dist/engine/pipeline/indexing/index.js +409 -165
- package/dist/engine/pipeline/indexing/index.js.map +1 -1
- package/dist/engine/pipeline/indexing/input-budget.d.ts +2 -0
- package/dist/engine/pipeline/indexing/input-budget.js +51 -0
- package/dist/engine/pipeline/indexing/input-budget.js.map +1 -0
- package/dist/engine/pipeline/indexing/root-paths.js +6 -6
- package/dist/engine/pipeline/indexing/root-paths.js.map +1 -1
- package/dist/engine/pipeline/indexing/scanner/index.d.ts +9 -2
- package/dist/engine/pipeline/indexing/scanner/index.js +291 -35
- package/dist/engine/pipeline/indexing/scanner/index.js.map +1 -1
- package/dist/engine/pipeline/search/index.d.ts +6 -6
- package/dist/engine/pipeline/search/index.js +8 -10
- package/dist/engine/pipeline/search/index.js.map +1 -1
- package/dist/engine/service/index.d.ts +3 -2
- package/dist/engine/service/index.js +1 -1
- package/dist/engine/service/index.js.map +1 -1
- package/dist/engine/service/root.d.ts +10 -12
- package/dist/engine/service/root.js +29 -25
- package/dist/engine/service/root.js.map +1 -1
- package/dist/engine/service/structure-enrichment.d.ts +1 -1
- package/dist/engine/service/structure-enrichment.js +20 -22
- package/dist/engine/service/structure-enrichment.js.map +1 -1
- package/dist/engine/service/types.d.ts +40 -38
- package/dist/engine/service/workspace-index.d.ts +26 -0
- package/dist/engine/service/workspace-index.js +157 -0
- package/dist/engine/service/workspace-index.js.map +1 -0
- package/dist/engine/service/zvec-grep.d.ts +12 -1
- package/dist/engine/service/zvec-grep.js +698 -489
- package/dist/engine/service/zvec-grep.js.map +1 -1
- package/dist/engine/storage/index.d.ts +30 -20
- package/dist/engine/storage/index.js +2 -1
- package/dist/engine/storage/index.js.map +1 -1
- package/dist/engine/storage/layout.d.ts +10 -0
- package/dist/engine/storage/layout.js +29 -0
- package/dist/engine/storage/layout.js.map +1 -0
- package/dist/engine/storage/zvec.d.ts +4 -67
- package/dist/engine/storage/zvec.js +115 -85
- package/dist/engine/storage/zvec.js.map +1 -1
- package/dist/engine/types.d.ts +29 -23
- package/dist/engine/types.js +1 -1
- package/dist/engine/types.js.map +1 -1
- package/dist/engine/utils/daemon-lease.d.ts +17 -0
- package/dist/engine/utils/daemon-lease.js +175 -0
- package/dist/engine/utils/daemon-lease.js.map +1 -0
- package/dist/engine/utils/file-selection.js +38 -1
- package/dist/engine/utils/file-selection.js.map +1 -1
- package/dist/engine/utils/lock.js +1 -1
- package/dist/engine/utils/lock.js.map +1 -1
- package/dist/index-progress.d.ts +10 -0
- package/dist/index-progress.js +159 -0
- package/dist/index-progress.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/http-transport.d.ts +27 -0
- package/dist/mcp/http-transport.js +182 -0
- package/dist/mcp/http-transport.js.map +1 -0
- package/dist/mcp/input-normalization.d.ts +38 -0
- package/dist/mcp/input-normalization.js +104 -0
- package/dist/mcp/input-normalization.js.map +1 -0
- package/dist/mcp/progress-heartbeat.d.ts +17 -0
- package/dist/mcp/progress-heartbeat.js +46 -0
- package/dist/mcp/progress-heartbeat.js.map +1 -0
- package/dist/mcp/request-metadata.d.ts +2 -0
- package/dist/mcp/request-metadata.js +11 -0
- package/dist/mcp/request-metadata.js.map +1 -0
- package/dist/mcp/request-state.d.ts +40 -0
- package/dist/mcp/request-state.js +210 -0
- package/dist/mcp/request-state.js.map +1 -0
- package/dist/mcp/result-format.d.ts +13 -0
- package/dist/mcp/result-format.js +75 -0
- package/dist/mcp/result-format.js.map +1 -0
- package/dist/mcp/schemas.d.ts +672 -0
- package/dist/mcp/schemas.js +506 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/stdio-bridge.d.ts +9 -0
- package/dist/mcp/stdio-bridge.js +131 -0
- package/dist/mcp/stdio-bridge.js.map +1 -0
- package/dist/mcp/tools.d.ts +153 -0
- package/dist/mcp/tools.js +482 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/toolset.d.ts +5 -0
- package/dist/mcp/toolset.js +12 -0
- package/dist/mcp/toolset.js.map +1 -0
- package/dist/observability/trace-context.d.ts +11 -0
- package/dist/observability/trace-context.js +138 -0
- package/dist/observability/trace-context.js.map +1 -0
- package/dist/prompts/zvec-grep-guidance.d.ts +2 -0
- package/dist/prompts/zvec-grep-guidance.js +9 -0
- package/dist/prompts/zvec-grep-guidance.js.map +1 -0
- package/docs/01-agents.md +132 -0
- package/docs/02-cli.md +239 -0
- package/docs/03-mcp.md +185 -0
- package/docs/04-pipeline.md +226 -0
- package/docs/05-architecture.md +86 -0
- package/docs/06-server.md +215 -0
- package/docs/07-embedding.md +182 -0
- package/docs/08-roadmap.md +85 -0
- package/docs/README.md +53 -0
- package/package.json +20 -11
- package/dist/cli/mcp.d.ts +0 -2
- package/dist/cli/mcp.js +0 -354
- package/dist/cli/mcp.js.map +0 -1
- package/dist/engine/collection/index.d.ts +0 -55
- package/dist/engine/collection/index.js +0 -710
- package/dist/engine/collection/index.js.map +0 -1
- package/dist/engine/errors/details.d.ts +0 -6
- package/dist/engine/errors/details.js.map +0 -1
- package/dist/engine/errors/index.js +0 -16
- package/dist/engine/errors/index.js.map +0 -1
- package/dist/engine/extraction/tree-sitter/grammar.js.map +0 -1
- package/dist/engine/extraction/tree-sitter/nodes.js.map +0 -1
- package/dist/engine/extraction/tree-sitter/parser.js.map +0 -1
- package/dist/engine/files/file-type.d.ts +0 -5
- package/dist/engine/files/file-type.js +0 -119
- package/dist/engine/files/file-type.js.map +0 -1
- package/dist/engine/models/providers/index.d.ts +0 -2
- package/dist/engine/models/providers/index.js +0 -3
- package/dist/engine/models/providers/index.js.map +0 -1
- package/dist/engine/models/providers/llama-cpp/embedding.js.map +0 -1
- package/dist/engine/models/providers/llama-cpp/index.d.ts +0 -1
- package/dist/engine/models/providers/llama-cpp/index.js +0 -2
- package/dist/engine/models/providers/llama-cpp/index.js.map +0 -1
- package/dist/engine/models/providers/qwen/embedding.d.ts +0 -42
- package/dist/engine/models/providers/qwen/embedding.js.map +0 -1
- package/dist/engine/models/providers/qwen/index.d.ts +0 -1
- package/dist/engine/models/providers/qwen/index.js +0 -2
- package/dist/engine/models/providers/qwen/index.js.map +0 -1
- package/dist/engine/models/types.d.ts +0 -30
- package/skills/zvec-grep/SKILL.md +0 -151
- package/skills/zvec-grep/agents/openai.yaml +0 -4
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.d.ts +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.js +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.d.ts +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.js +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.d.ts +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.js +0 -0
- /package/dist/engine/{models → extraction}/types.js +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
1
|
+
import { lstat, readFile } from "node:fs/promises";
|
|
2
|
+
import { workspaceIndexDetail, detail, EngineError, errorDetails, isEngineError, } from "../../errors.js";
|
|
3
3
|
import { sha256Bytes } from "../../utils/hash.js";
|
|
4
|
+
import { normalizePath } from "../../utils/path.js";
|
|
4
5
|
import { ConcurrentTiming, TimingCollector } from "../../utils/timing.js";
|
|
5
|
-
import {
|
|
6
|
-
import { scanRootPaths } from "./scanner/index.js";
|
|
7
|
-
|
|
8
|
-
const DEFAULT_EMBEDDING_MIN_CONCURRENCY = 4;
|
|
9
|
-
const DEFAULT_EMBEDDING_MAX_CONCURRENCY = 12;
|
|
6
|
+
import { extract, vectorContentForFragment, } from "../../extraction/index.js";
|
|
7
|
+
import { scanDirectoryPath, scanFilePath, scanRootPaths, } from "./scanner/index.js";
|
|
8
|
+
import { indexChunkOptions } from "./input-budget.js";
|
|
10
9
|
const EMBEDDING_TRANSIENT_MAX_RETRIES = 3;
|
|
11
10
|
const EMBEDDING_RATE_LIMIT_MAX_RETRIES = 6;
|
|
12
11
|
const EMBEDDING_TRANSIENT_RETRY_BASE_DELAY_MS = 500;
|
|
@@ -15,33 +14,44 @@ const EMBEDDING_TRANSIENT_RETRY_MAX_DELAY_MS = 8000;
|
|
|
15
14
|
const EMBEDDING_RATE_LIMIT_RETRY_MAX_DELAY_MS = 30000;
|
|
16
15
|
const EMBEDDING_RETRY_JITTER_MS = 500;
|
|
17
16
|
const EMBEDDING_SUCCESS_STREAK_MIN = 4;
|
|
18
|
-
export async function
|
|
17
|
+
export async function indexWorkspace(ctx) {
|
|
19
18
|
try {
|
|
20
|
-
return await
|
|
19
|
+
return await indexWorkspaceUnchecked(ctx);
|
|
21
20
|
}
|
|
22
21
|
catch (error) {
|
|
23
|
-
throw toEngineError(error, "Indexing
|
|
24
|
-
code: "ZVEC_GREP.ENGINE.INDEXING.
|
|
25
|
-
context:
|
|
22
|
+
throw toEngineError(error, "Indexing workspace failed", {
|
|
23
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.WORKSPACE_FAILED",
|
|
24
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
26
25
|
});
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
|
-
export async function
|
|
28
|
+
export async function indexWorkspacePaths(ctx, changedPaths) {
|
|
30
29
|
try {
|
|
31
|
-
|
|
30
|
+
return await indexWorkspacePathsUnchecked(ctx, changedPaths);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw toEngineError(error, "Indexing changed paths failed", {
|
|
34
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.WORKSPACE_FAILED",
|
|
35
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export async function getWorkspaceIndexStatus(workspaceIndex, storedFiles) {
|
|
40
|
+
try {
|
|
41
|
+
const scan = await scanRootPaths(workspaceIndex.id, workspaceIndex.rootPaths);
|
|
32
42
|
const diff = await computeDiffFromFiles(scan.files, storedFiles);
|
|
33
43
|
const pendingFiles = storedFiles.filter((file) => file.indexStatus?.indexedTime === null);
|
|
34
44
|
const failedFiles = pendingFiles.filter((file) => file.indexStatus?.error !== undefined);
|
|
35
45
|
const indexedFiles = storedFiles.filter((file) => file.indexStatus?.indexedTime !== undefined &&
|
|
36
46
|
file.indexStatus.indexedTime !== null);
|
|
37
47
|
const entitiesIndexed = indexedFiles.reduce((count, file) => count + (file.indexStatus?.entityCount ?? 0), 0);
|
|
48
|
+
const fragmentsTruncated = indexedFiles.reduce((count, file) => count + (file.indexStatus?.truncatedFragmentCount ?? 0), 0);
|
|
38
49
|
return {
|
|
39
|
-
collectionId: collection.id,
|
|
40
|
-
collectionName: collection.name,
|
|
41
50
|
filesScanned: scan.files.length,
|
|
42
51
|
filesStored: storedFiles.length,
|
|
43
52
|
filesIndexed: indexedFiles.length,
|
|
44
53
|
entitiesIndexed,
|
|
54
|
+
fragmentsTruncated,
|
|
45
55
|
filesPending: pendingFiles.length,
|
|
46
56
|
filesFailed: failedFiles.length,
|
|
47
57
|
filesAdded: diff.added.length,
|
|
@@ -56,36 +66,42 @@ export async function getCollectionIndexStatus(collection, storedFiles) {
|
|
|
56
66
|
};
|
|
57
67
|
}
|
|
58
68
|
catch (error) {
|
|
59
|
-
throw toEngineError(error, "Inspecting
|
|
69
|
+
throw toEngineError(error, "Inspecting workspace index status failed", {
|
|
60
70
|
code: "ZVEC_GREP.ENGINE.INDEXING.STATUS_FAILED",
|
|
61
|
-
context:
|
|
71
|
+
context: workspaceIndexContext(workspaceIndex),
|
|
62
72
|
});
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
|
-
async function
|
|
75
|
+
async function indexWorkspaceUnchecked(ctx) {
|
|
66
76
|
const start = Date.now();
|
|
67
77
|
const report = ctx.onProgress ?? (() => undefined);
|
|
68
78
|
const timings = new TimingCollector();
|
|
79
|
+
throwIfIndexCancelled(ctx);
|
|
69
80
|
const firstPass = await runIndexPass(ctx, report, "Scanning files...", timings);
|
|
70
81
|
const passes = [firstPass];
|
|
82
|
+
let progressBase;
|
|
71
83
|
if (firstPass.stats.filesFailed > 0) {
|
|
72
84
|
const failed = firstPass.stats.filesFailed;
|
|
85
|
+
progressBase = retryProgressBase(firstPass);
|
|
73
86
|
report({
|
|
74
87
|
phase: "scanning",
|
|
88
|
+
filesTotal: progressBase.filesTotal,
|
|
89
|
+
filesIndexed: progressBase.filesSucceeded,
|
|
75
90
|
detail: `Retrying ${failed} failed ${failed === 1 ? "file" : "files"}...`,
|
|
76
91
|
});
|
|
77
|
-
passes.push(await runIndexPass(ctx, report, "Scanning retry candidates...", timings));
|
|
92
|
+
passes.push(await runIndexPass(ctx, report, "Scanning retry candidates...", timings, progressBase));
|
|
78
93
|
}
|
|
79
94
|
const finalPass = passes[passes.length - 1];
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
throwIfIndexCancelled(ctx);
|
|
96
|
+
reportIndexFinalizing(ctx, report, finalPass, progressBase);
|
|
97
|
+
await timings.time("index_optimize", () => optimizeStorage(ctx));
|
|
82
98
|
const result = buildIndexResult(ctx, passes, Date.now() - start, timings);
|
|
83
99
|
if (result.filesFailed > 0) {
|
|
84
100
|
report({ phase: "done", detail: "Indexing completed with failed files" });
|
|
85
101
|
throw new EngineError(`Indexing completed with ${result.filesFailed} failed ${result.filesFailed === 1 ? "file" : "files"}`, {
|
|
86
102
|
code: "ZVEC_GREP.ENGINE.INDEXING.FILES_FAILED",
|
|
87
103
|
context: errorDetails([
|
|
88
|
-
|
|
104
|
+
workspaceIndexDetail(ctx.workspaceIndex.name),
|
|
89
105
|
detail("filesFailed", result.filesFailed),
|
|
90
106
|
detail("filesScanned", result.filesScanned),
|
|
91
107
|
detail("failedFiles", summarizeFailedFiles(finalPass.stats.failedFiles)),
|
|
@@ -99,18 +115,83 @@ async function indexCollectionUnchecked(ctx) {
|
|
|
99
115
|
report({ phase: "done", detail: "Indexing complete" });
|
|
100
116
|
return result;
|
|
101
117
|
}
|
|
102
|
-
async function
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
const
|
|
118
|
+
async function indexWorkspacePathsUnchecked(ctx, changedPaths) {
|
|
119
|
+
const start = Date.now();
|
|
120
|
+
const report = ctx.onProgress ?? (() => undefined);
|
|
121
|
+
const timings = new TimingCollector();
|
|
122
|
+
const normalizedPaths = [...new Set(changedPaths.map(normalizePath))];
|
|
123
|
+
throwIfIndexCancelled(ctx);
|
|
124
|
+
const firstPass = await runPathIndexPass(ctx, report, normalizedPaths, timings);
|
|
125
|
+
const passes = [firstPass];
|
|
126
|
+
let progressBase;
|
|
127
|
+
if (firstPass.stats.filesFailed > 0) {
|
|
128
|
+
progressBase = retryProgressBase(firstPass);
|
|
129
|
+
passes.push(await runPathIndexPass(ctx, report, normalizedPaths, timings, progressBase));
|
|
130
|
+
}
|
|
131
|
+
const finalPass = passes[passes.length - 1];
|
|
132
|
+
throwIfIndexCancelled(ctx);
|
|
133
|
+
reportIndexFinalizing(ctx, report, finalPass, progressBase);
|
|
134
|
+
await timings.time("index_optimize", () => optimizeStorage(ctx));
|
|
135
|
+
const result = buildIndexResult(ctx, passes, Date.now() - start, timings);
|
|
136
|
+
if (result.filesFailed > 0) {
|
|
137
|
+
throw new EngineError(`Indexing completed with ${result.filesFailed} failed files`, {
|
|
138
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.FILES_FAILED",
|
|
139
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
report({ phase: "done", detail: "Indexing complete" });
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
async function runPathIndexPass(ctx, report, changedPaths, timings, progressBase) {
|
|
146
|
+
reportScanning(report, "Scanning changed paths...", progressBase);
|
|
147
|
+
const scanned = await timings.time("index_scan_paths", async () => {
|
|
148
|
+
const files = [];
|
|
149
|
+
const diagnostics = emptyScanDiagnostics();
|
|
150
|
+
for (const path of changedPaths) {
|
|
151
|
+
throwIfIndexCancelled(ctx);
|
|
152
|
+
const info = await lstat(path).catch(() => null);
|
|
153
|
+
const scan = info?.isDirectory()
|
|
154
|
+
? await scanDirectoryPath(ctx.workspaceIndex.id, ctx.workspaceIndex.rootPaths, path, { signal: ctx.signal })
|
|
155
|
+
: await scanFilePath(ctx.workspaceIndex.id, ctx.workspaceIndex.rootPaths, path, {
|
|
156
|
+
signal: ctx.signal,
|
|
157
|
+
});
|
|
158
|
+
files.push(...scan.files);
|
|
159
|
+
mergeScanDiagnostics(diagnostics, scan.diagnostics);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
files: [...new Map(files.map((file) => [file.id, file])).values()],
|
|
163
|
+
diagnostics,
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
throwIfIndexCancelled(ctx);
|
|
167
|
+
const existing = [
|
|
168
|
+
...new Map(changedPaths
|
|
169
|
+
.flatMap((path) => ctx.storage.listFilesByPathPrefix(path))
|
|
170
|
+
.map((file) => [file.id, file])).values(),
|
|
171
|
+
];
|
|
172
|
+
return runDiffPass(ctx, report, scanned.files, existing, timings, progressBase, scanned.diagnostics);
|
|
173
|
+
}
|
|
174
|
+
async function runIndexPass(ctx, report, scanningDetail, timings, progressBase) {
|
|
175
|
+
reportScanning(report, scanningDetail, progressBase);
|
|
176
|
+
const scan = await timings.time("index_scan", () => scanRootPaths(ctx.workspaceIndex.id, ctx.workspaceIndex.rootPaths, {
|
|
177
|
+
signal: ctx.signal,
|
|
178
|
+
}));
|
|
179
|
+
throwIfIndexCancelled(ctx);
|
|
180
|
+
return runDiffPass(ctx, report, scan.files, ctx.storage.listFiles(), timings, progressBase, scan.diagnostics);
|
|
181
|
+
}
|
|
182
|
+
async function runDiffPass(ctx, report, scannedFiles, existingFiles, timings, progressBase, scanDiagnostics = emptyScanDiagnostics()) {
|
|
183
|
+
const diff = await timings.time("index_diff", () => computeDiffFromFiles(scannedFiles, existingFiles));
|
|
184
|
+
throwIfIndexCancelled(ctx);
|
|
106
185
|
const pending = [...diff.added, ...diff.modified, ...diff.pending];
|
|
107
186
|
report({
|
|
108
187
|
phase: "scanning",
|
|
109
|
-
filesTotal:
|
|
188
|
+
filesTotal: progressBase?.filesTotal ?? scannedFiles.length,
|
|
189
|
+
filesIndexed: progressBase?.filesSucceeded ?? 0,
|
|
110
190
|
detail: `${diff.added.length} added, ${diff.modified.length} modified, ${diff.pending.length} pending, ${diff.deleted.length} deleted, ${diff.unchanged.length} unchanged`,
|
|
111
191
|
});
|
|
112
192
|
timings.timeSync("index_delete_stale", () => {
|
|
113
193
|
for (const file of diff.deleted) {
|
|
194
|
+
throwIfIndexCancelled(ctx);
|
|
114
195
|
try {
|
|
115
196
|
ctx.storage.deleteFile(file.id);
|
|
116
197
|
}
|
|
@@ -125,8 +206,10 @@ async function runIndexPass(ctx, report, scanningDetail, timings) {
|
|
|
125
206
|
const reportIndexing = (currentStats, detail, embedding) => {
|
|
126
207
|
report({
|
|
127
208
|
phase: "indexing",
|
|
128
|
-
filesTotal: pending.length,
|
|
129
|
-
filesIndexed:
|
|
209
|
+
filesTotal: progressBase?.filesTotal ?? pending.length,
|
|
210
|
+
filesIndexed: (progressBase?.filesSucceeded ?? 0) +
|
|
211
|
+
currentStats.filesIndexed +
|
|
212
|
+
currentStats.filesFailed,
|
|
130
213
|
filesFailed: currentStats.filesFailed,
|
|
131
214
|
detail,
|
|
132
215
|
embedding,
|
|
@@ -140,21 +223,46 @@ async function runIndexPass(ctx, report, scanningDetail, timings) {
|
|
|
140
223
|
entitiesCreated: 0,
|
|
141
224
|
});
|
|
142
225
|
const stats = await indexFiles(pending, ctx, reportIndexing, timings);
|
|
226
|
+
throwIfIndexCancelled(ctx);
|
|
143
227
|
return {
|
|
144
|
-
filesScanned:
|
|
228
|
+
filesScanned: scannedFiles.length,
|
|
229
|
+
scanDiagnostics,
|
|
145
230
|
diff,
|
|
146
231
|
stats,
|
|
147
232
|
};
|
|
148
233
|
}
|
|
149
|
-
function reportIndexFinalizing(ctx, report, pass) {
|
|
234
|
+
function reportIndexFinalizing(ctx, report, pass, progressBase) {
|
|
150
235
|
report({
|
|
151
236
|
phase: "indexing",
|
|
237
|
+
filesTotal: progressBase?.filesTotal ??
|
|
238
|
+
pass.diff.added.length +
|
|
239
|
+
pass.diff.modified.length +
|
|
240
|
+
pass.diff.pending.length,
|
|
241
|
+
filesIndexed: (progressBase?.filesSucceeded ?? 0) +
|
|
242
|
+
pass.stats.filesIndexed +
|
|
243
|
+
pass.stats.filesFailed,
|
|
244
|
+
filesFailed: pass.stats.filesFailed,
|
|
245
|
+
detail: "finalizing index",
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
function retryProgressBase(pass) {
|
|
249
|
+
return {
|
|
250
|
+
filesSucceeded: pass.stats.filesIndexed,
|
|
152
251
|
filesTotal: pass.diff.added.length +
|
|
153
252
|
pass.diff.modified.length +
|
|
154
253
|
pass.diff.pending.length,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function reportScanning(report, detail, progressBase) {
|
|
257
|
+
report({
|
|
258
|
+
phase: "scanning",
|
|
259
|
+
...(progressBase
|
|
260
|
+
? {
|
|
261
|
+
filesTotal: progressBase.filesTotal,
|
|
262
|
+
filesIndexed: progressBase.filesSucceeded,
|
|
263
|
+
}
|
|
264
|
+
: {}),
|
|
265
|
+
detail,
|
|
158
266
|
});
|
|
159
267
|
}
|
|
160
268
|
function buildIndexResult(ctx, passes, durationMs, timings) {
|
|
@@ -162,8 +270,6 @@ function buildIndexResult(ctx, passes, durationMs, timings) {
|
|
|
162
270
|
const retryPasses = passes.slice(1);
|
|
163
271
|
const finalPass = passes[passes.length - 1];
|
|
164
272
|
return {
|
|
165
|
-
collectionId: ctx.collection.id,
|
|
166
|
-
collectionName: ctx.collection.name,
|
|
167
273
|
filesScanned: finalPass.filesScanned,
|
|
168
274
|
filesAdded: firstPass.diff.added.length +
|
|
169
275
|
retryPasses.reduce((count, pass) => count + pass.diff.added.length, 0),
|
|
@@ -178,22 +284,50 @@ function buildIndexResult(ctx, passes, durationMs, timings) {
|
|
|
178
284
|
entitiesCreated: passes.reduce((count, pass) => count + pass.stats.entitiesCreated, 0),
|
|
179
285
|
durationMs,
|
|
180
286
|
timings: timings.entries(),
|
|
287
|
+
...(finalPass.scanDiagnostics.skippedFiles > 0
|
|
288
|
+
? { scanDiagnostics: finalPass.scanDiagnostics }
|
|
289
|
+
: {}),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const MAX_SKIPPED_FILE_SAMPLES = 20;
|
|
293
|
+
function emptyScanDiagnostics() {
|
|
294
|
+
return {
|
|
295
|
+
skippedFiles: 0,
|
|
296
|
+
skippedByReason: {
|
|
297
|
+
empty: 0,
|
|
298
|
+
too_large: 0,
|
|
299
|
+
unsupported: 0,
|
|
300
|
+
binary: 0,
|
|
301
|
+
},
|
|
302
|
+
skippedSamples: [],
|
|
181
303
|
};
|
|
182
304
|
}
|
|
183
|
-
function
|
|
305
|
+
function mergeScanDiagnostics(target, source) {
|
|
306
|
+
target.skippedFiles += source.skippedFiles;
|
|
307
|
+
for (const reason of [
|
|
308
|
+
"empty",
|
|
309
|
+
"too_large",
|
|
310
|
+
"unsupported",
|
|
311
|
+
"binary",
|
|
312
|
+
]) {
|
|
313
|
+
target.skippedByReason[reason] += source.skippedByReason[reason];
|
|
314
|
+
}
|
|
315
|
+
const remaining = MAX_SKIPPED_FILE_SAMPLES - target.skippedSamples.length;
|
|
316
|
+
if (remaining > 0) {
|
|
317
|
+
target.skippedSamples.push(...source.skippedSamples.slice(0, remaining));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function optimizeStorage(ctx) {
|
|
184
321
|
try {
|
|
185
|
-
ctx.storage.
|
|
322
|
+
await ctx.storage.finalizeWrites();
|
|
186
323
|
}
|
|
187
324
|
catch (error) {
|
|
188
325
|
throw toEngineError(error, "Indexing failed to finalize storage", {
|
|
189
326
|
code: "ZVEC_GREP.ENGINE.INDEXING.OPTIMIZE_FAILED",
|
|
190
|
-
context:
|
|
327
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
191
328
|
});
|
|
192
329
|
}
|
|
193
330
|
}
|
|
194
|
-
async function computeDiff(scannedFiles, storage) {
|
|
195
|
-
return computeDiffFromFiles(scannedFiles, storage.listFiles());
|
|
196
|
-
}
|
|
197
331
|
async function computeDiffFromFiles(scannedFiles, existingFiles) {
|
|
198
332
|
const existingById = new Map(existingFiles.map((file) => [file.id, file]));
|
|
199
333
|
const seen = new Set();
|
|
@@ -246,6 +380,7 @@ async function indexFiles(files, ctx, onProgress, timings) {
|
|
|
246
380
|
onProgress(currentStats, detail, embeddingScheduler.snapshot());
|
|
247
381
|
};
|
|
248
382
|
const flushBatch = async () => {
|
|
383
|
+
throwIfIndexCancelled(ctx);
|
|
249
384
|
if (batchFiles.length === 0) {
|
|
250
385
|
return;
|
|
251
386
|
}
|
|
@@ -254,6 +389,7 @@ async function indexFiles(files, ctx, onProgress, timings) {
|
|
|
254
389
|
await scheduleEmbeddingTask(() => embedAndCommitBatch(filesToEmbed, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming));
|
|
255
390
|
};
|
|
256
391
|
const scheduleEmbeddingTask = async (task) => {
|
|
392
|
+
throwIfIndexCancelled(ctx);
|
|
257
393
|
const promise = task().finally(() => {
|
|
258
394
|
runningEmbeddings.delete(promise);
|
|
259
395
|
});
|
|
@@ -262,50 +398,66 @@ async function indexFiles(files, ctx, onProgress, timings) {
|
|
|
262
398
|
await Promise.race(runningEmbeddings);
|
|
263
399
|
}
|
|
264
400
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
await
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
401
|
+
try {
|
|
402
|
+
for (const file of files) {
|
|
403
|
+
throwIfIndexCancelled(ctx);
|
|
404
|
+
onProgress(stats, `reading ${file.relativePath}`);
|
|
405
|
+
const prepared = await timings.time("index_prepare", () => prepareFile(file, ctx));
|
|
406
|
+
throwIfIndexCancelled(ctx);
|
|
407
|
+
if ("failedReason" in prepared) {
|
|
408
|
+
recordFileFailed(stats, file, prepared.failedReason);
|
|
409
|
+
onProgress(stats, `failed ${file.relativePath}`);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (prepared.fragments.length === 0) {
|
|
413
|
+
const committed = commitFile(prepared, [], ctx, stats);
|
|
414
|
+
onProgress(stats, finishedFileDetail(committed, file.relativePath));
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
if (prepared.fragments.length > ctx.embeddingModel.info.limits.maxBatchSize) {
|
|
418
|
+
await flushBatch();
|
|
419
|
+
await scheduleEmbeddingTask(async () => {
|
|
420
|
+
throwIfIndexCancelled(ctx);
|
|
421
|
+
reportEmbeddingProgress(stats, `embedding ${file.relativePath}`);
|
|
422
|
+
await embedAndCommitFile(prepared, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming);
|
|
423
|
+
});
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (batchFragmentCount > 0 &&
|
|
427
|
+
batchFragmentCount + prepared.fragments.length >
|
|
428
|
+
ctx.embeddingModel.info.limits.maxBatchSize) {
|
|
429
|
+
await flushBatch();
|
|
430
|
+
}
|
|
431
|
+
batchFiles.push(prepared);
|
|
432
|
+
batchFragmentCount += prepared.fragments.length;
|
|
433
|
+
if (batchFragmentCount === ctx.embeddingModel.info.limits.maxBatchSize) {
|
|
434
|
+
await flushBatch();
|
|
435
|
+
}
|
|
295
436
|
}
|
|
437
|
+
await flushBatch();
|
|
438
|
+
await Promise.all(runningEmbeddings);
|
|
296
439
|
}
|
|
297
|
-
|
|
298
|
-
|
|
440
|
+
catch (error) {
|
|
441
|
+
await Promise.allSettled(runningEmbeddings);
|
|
442
|
+
throw error;
|
|
443
|
+
}
|
|
444
|
+
throwIfIndexCancelled(ctx);
|
|
299
445
|
return stats;
|
|
300
446
|
}
|
|
301
447
|
async function prepareFile(file, ctx) {
|
|
302
448
|
try {
|
|
449
|
+
throwIfIndexCancelled(ctx);
|
|
303
450
|
const source = await readSource(file);
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
|
|
451
|
+
const chunkOptions = indexChunkOptions(ctx.embeddingModel.info.limits.maxInputTokens, source.kind === "text" ? source.text : undefined);
|
|
452
|
+
const extracted = await extract(source, chunkOptions);
|
|
453
|
+
throwIfIndexCancelled(ctx);
|
|
454
|
+
const fragments = extracted.filter((fragment) => ctx.embeddingModel.info.inputKinds.includes(fragment.content.kind));
|
|
455
|
+
return { file, fragments, maxChars: chunkOptions.maxChunkChars };
|
|
307
456
|
}
|
|
308
457
|
catch (error) {
|
|
458
|
+
if (indexIsCancelled(ctx)) {
|
|
459
|
+
throw indexCancellationError(ctx);
|
|
460
|
+
}
|
|
309
461
|
return {
|
|
310
462
|
file,
|
|
311
463
|
failedReason: markFileFailed(ctx, file, error, "prepare"),
|
|
@@ -313,20 +465,33 @@ async function prepareFile(file, ctx) {
|
|
|
313
465
|
}
|
|
314
466
|
}
|
|
315
467
|
async function embedAndCommitBatch(files, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming) {
|
|
316
|
-
const fragments = files.flatMap((file) => file.fragments);
|
|
317
468
|
try {
|
|
318
|
-
|
|
469
|
+
throwIfIndexCancelled(ctx);
|
|
470
|
+
const contents = files.flatMap((file) => file.fragments.map((fragment) => vectorContentForFragment(fragment, file.maxChars)));
|
|
319
471
|
onProgress(stats, `embedding ${describePreparedFiles(files)}`, embeddingScheduler.snapshot());
|
|
320
|
-
const
|
|
472
|
+
const embedding = await embeddingTiming.time(() => embedContentsWithRetry(contents, ctx.embeddingModel, embeddingScheduler, ctx.signal, (progress) => reportModelDownloadProgress(stats, progress, onProgress, embeddingScheduler)));
|
|
473
|
+
const truncatedInputIndexes = new Set(embedding.truncated);
|
|
474
|
+
throwIfIndexCancelled(ctx);
|
|
321
475
|
let offset = 0;
|
|
322
476
|
for (const file of files) {
|
|
323
|
-
|
|
477
|
+
throwIfIndexCancelled(ctx);
|
|
478
|
+
const end = offset + file.fragments.length;
|
|
479
|
+
const fileVectors = embedding.vectors.slice(offset, end);
|
|
480
|
+
let truncatedFragmentCount = 0;
|
|
481
|
+
for (let index = offset; index < end; index++) {
|
|
482
|
+
if (truncatedInputIndexes.has(index)) {
|
|
483
|
+
truncatedFragmentCount++;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
324
486
|
offset += file.fragments.length;
|
|
325
|
-
const committed = timings.timeSync("index_commit", () => commitFile(file, fileVectors, ctx, stats));
|
|
487
|
+
const committed = timings.timeSync("index_commit", () => commitFile(file, fileVectors, ctx, stats, truncatedFragmentCount));
|
|
326
488
|
onProgress(stats, finishedFileDetail(committed, file.file.relativePath));
|
|
327
489
|
}
|
|
328
490
|
}
|
|
329
491
|
catch (error) {
|
|
492
|
+
if (indexIsCancelled(ctx)) {
|
|
493
|
+
throw indexCancellationError(ctx);
|
|
494
|
+
}
|
|
330
495
|
if (isRetryableEmbeddingError(error)) {
|
|
331
496
|
for (const file of files) {
|
|
332
497
|
const reason = markFileFailed(ctx, file.file, error, "embed");
|
|
@@ -343,29 +508,66 @@ async function embedAndCommitBatch(files, ctx, stats, onProgress, embeddingSched
|
|
|
343
508
|
}
|
|
344
509
|
async function embedAndCommitFile(file, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming) {
|
|
345
510
|
try {
|
|
346
|
-
|
|
347
|
-
const
|
|
511
|
+
throwIfIndexCancelled(ctx);
|
|
512
|
+
const embedding = await embeddingTiming.time(() => embedFragments(file.fragments, ctx.embeddingModel, embeddingScheduler, file.maxChars, ctx.signal, (progress) => reportModelDownloadProgress(stats, progress, onProgress, embeddingScheduler)));
|
|
513
|
+
throwIfIndexCancelled(ctx);
|
|
514
|
+
const committed = timings.timeSync("index_commit", () => commitFile(file, embedding.vectors, ctx, stats, embedding.truncated.length));
|
|
348
515
|
onProgress(stats, finishedFileDetail(committed, file.file.relativePath));
|
|
349
516
|
}
|
|
350
517
|
catch (error) {
|
|
518
|
+
if (indexIsCancelled(ctx)) {
|
|
519
|
+
throw indexCancellationError(ctx);
|
|
520
|
+
}
|
|
351
521
|
const reason = markFileFailed(ctx, file.file, error, "embed");
|
|
352
522
|
recordFileFailed(stats, file.file, reason);
|
|
353
523
|
onProgress(stats, finishedFileDetail(false, file.file.relativePath));
|
|
354
524
|
}
|
|
355
525
|
}
|
|
356
|
-
function commitFile(file, vectors, ctx, stats) {
|
|
526
|
+
function commitFile(file, vectors, ctx, stats, truncatedFragmentCount = 0) {
|
|
357
527
|
try {
|
|
358
|
-
ctx
|
|
528
|
+
throwIfIndexCancelled(ctx);
|
|
529
|
+
if (file.fragments.length !== vectors.length) {
|
|
530
|
+
throw new EngineError("Embedding returned mismatched entity/vector counts", {
|
|
531
|
+
code: "ZVEC_GREP.ENGINE.STORAGE.ENTITY_VECTOR_COUNT_MISMATCH",
|
|
532
|
+
context: `fileId=${file.file.id} fragmentCount=${file.fragments.length} vectorCount=${vectors.length}`,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
ctx.storage.replaceFile(file.file, file.fragments.map((fragment, index) => ({
|
|
536
|
+
fragment,
|
|
537
|
+
vector: vectors[index],
|
|
538
|
+
})), {
|
|
539
|
+
truncatedFragmentCount,
|
|
540
|
+
});
|
|
359
541
|
stats.filesIndexed++;
|
|
360
542
|
stats.entitiesCreated += countPublicEntities(file.fragments);
|
|
361
543
|
return true;
|
|
362
544
|
}
|
|
363
545
|
catch (error) {
|
|
546
|
+
if (indexIsCancelled(ctx)) {
|
|
547
|
+
throw indexCancellationError(ctx);
|
|
548
|
+
}
|
|
364
549
|
const reason = markFileFailed(ctx, file.file, error, "commit");
|
|
365
550
|
recordFileFailed(stats, file.file, reason);
|
|
366
551
|
return false;
|
|
367
552
|
}
|
|
368
553
|
}
|
|
554
|
+
function throwIfIndexCancelled(ctx) {
|
|
555
|
+
if (!indexIsCancelled(ctx)) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
throw indexCancellationError(ctx);
|
|
559
|
+
}
|
|
560
|
+
function indexIsCancelled(ctx) {
|
|
561
|
+
return ctx.signal?.aborted === true;
|
|
562
|
+
}
|
|
563
|
+
function indexCancellationError(ctx) {
|
|
564
|
+
return ctx.signal?.reason instanceof Error
|
|
565
|
+
? ctx.signal.reason
|
|
566
|
+
: new EngineError("Indexing was cancelled.", {
|
|
567
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.CANCELLED",
|
|
568
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
569
|
+
});
|
|
570
|
+
}
|
|
369
571
|
function recordFileFailed(stats, file, reason) {
|
|
370
572
|
stats.filesFailed++;
|
|
371
573
|
stats.failedFiles.push(file.relativePath);
|
|
@@ -417,14 +619,15 @@ async function readSource(file) {
|
|
|
417
619
|
text: bytes.toString("utf8"),
|
|
418
620
|
};
|
|
419
621
|
}
|
|
420
|
-
async function embedFragments(fragments, model, embeddingScheduler) {
|
|
622
|
+
async function embedFragments(fragments, model, embeddingScheduler, maxChars, signal, onModelProgress) {
|
|
421
623
|
const batches = [];
|
|
422
|
-
for (let start = 0; start < fragments.length; start += model.limits.maxBatchSize) {
|
|
423
|
-
const batch = fragments.slice(start, start + model.limits.maxBatchSize);
|
|
624
|
+
for (let start = 0; start < fragments.length; start += model.info.limits.maxBatchSize) {
|
|
625
|
+
const batch = fragments.slice(start, start + model.info.limits.maxBatchSize);
|
|
424
626
|
batches.push({ start, fragments: batch });
|
|
425
627
|
}
|
|
426
628
|
const vectors = new Array(fragments.length);
|
|
427
|
-
const
|
|
629
|
+
const truncatedInputIndexes = [];
|
|
630
|
+
const results = await Promise.allSettled(batches.map((batch) => embedFragmentBatch(batch.fragments, model, batch.start, embeddingScheduler, maxChars, signal, onModelProgress)));
|
|
428
631
|
let firstError;
|
|
429
632
|
for (const [index, result] of results.entries()) {
|
|
430
633
|
if (result.status === "rejected") {
|
|
@@ -432,94 +635,74 @@ async function embedFragments(fragments, model, embeddingScheduler) {
|
|
|
432
635
|
continue;
|
|
433
636
|
}
|
|
434
637
|
const start = batches[index].start;
|
|
435
|
-
for (const [offset, vector] of result.value.entries()) {
|
|
638
|
+
for (const [offset, vector] of result.value.vectors.entries()) {
|
|
436
639
|
vectors[start + offset] = vector;
|
|
437
640
|
}
|
|
641
|
+
truncatedInputIndexes.push(...result.value.truncated.map((inputIndex) => start + inputIndex));
|
|
438
642
|
}
|
|
439
643
|
if (firstError) {
|
|
440
644
|
throw firstError;
|
|
441
645
|
}
|
|
442
|
-
return
|
|
646
|
+
return {
|
|
647
|
+
vectors,
|
|
648
|
+
truncated: truncatedInputIndexes,
|
|
649
|
+
};
|
|
443
650
|
}
|
|
444
|
-
async function embedFragmentBatch(fragments, model, startIndex, embeddingScheduler) {
|
|
445
|
-
const contents = fragments.map(vectorContentForFragment);
|
|
651
|
+
async function embedFragmentBatch(fragments, model, startIndex, embeddingScheduler, maxChars, signal, onModelProgress) {
|
|
652
|
+
const contents = fragments.map((fragment) => vectorContentForFragment(fragment, maxChars));
|
|
446
653
|
try {
|
|
447
|
-
return await embedContentsWithRetry(contents, model, embeddingScheduler);
|
|
654
|
+
return await embedContentsWithRetry(contents, model, embeddingScheduler, signal, onModelProgress);
|
|
448
655
|
}
|
|
449
656
|
catch (error) {
|
|
450
657
|
if (fragments.length === 1 || isRetryableEmbeddingError(error)) {
|
|
451
658
|
throw error;
|
|
452
659
|
}
|
|
453
|
-
return await embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler);
|
|
660
|
+
return await embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler, maxChars, signal, onModelProgress);
|
|
454
661
|
}
|
|
455
662
|
}
|
|
456
|
-
async function embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler) {
|
|
663
|
+
async function embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler, maxChars, signal, onModelProgress) {
|
|
457
664
|
const vectors = [];
|
|
665
|
+
const truncatedInputIndexes = [];
|
|
458
666
|
for (const [index, fragment] of fragments.entries()) {
|
|
459
667
|
try {
|
|
460
|
-
const
|
|
461
|
-
vectors.push(
|
|
668
|
+
const result = await embedContentsWithRetry([vectorContentForFragment(fragment, maxChars)], model, embeddingScheduler, signal, onModelProgress);
|
|
669
|
+
vectors.push(result.vectors[0]);
|
|
670
|
+
if (result.truncated.length > 0) {
|
|
671
|
+
truncatedInputIndexes.push(index);
|
|
672
|
+
}
|
|
462
673
|
}
|
|
463
674
|
catch (error) {
|
|
464
675
|
throw new EngineError("Embedding entity fragment failed after one-by-one fallback", {
|
|
465
676
|
code: "ZVEC_GREP.ENGINE.INDEXING.EMBEDDING_FRAGMENT_FAILED",
|
|
466
|
-
context:
|
|
677
|
+
context: errorDetails([
|
|
678
|
+
detail("model", model.info.reference),
|
|
679
|
+
detail("fragmentId", fragment.id),
|
|
680
|
+
detail("fragmentIndex", startIndex + index),
|
|
681
|
+
isEngineError(error) ? detail("causeCode", error.code) : null,
|
|
682
|
+
error instanceof Error ? detail("cause", error.message) : null,
|
|
683
|
+
isEngineError(error) ? error.context : null,
|
|
684
|
+
]),
|
|
467
685
|
cause: error,
|
|
468
686
|
});
|
|
469
687
|
}
|
|
470
688
|
}
|
|
471
|
-
return vectors;
|
|
472
|
-
}
|
|
473
|
-
function vectorContentForFragment(fragment) {
|
|
474
|
-
if (fragment.content.kind !== "text") {
|
|
475
|
-
return fragment.content;
|
|
476
|
-
}
|
|
477
|
-
const metadata = vectorMetadataText(fragment.metadata);
|
|
478
|
-
if (metadata.length === 0) {
|
|
479
|
-
return fragment.content;
|
|
480
|
-
}
|
|
481
689
|
return {
|
|
482
|
-
|
|
483
|
-
|
|
690
|
+
vectors,
|
|
691
|
+
truncated: truncatedInputIndexes,
|
|
484
692
|
};
|
|
485
693
|
}
|
|
486
|
-
function
|
|
487
|
-
if (!metadata) {
|
|
488
|
-
return "";
|
|
489
|
-
}
|
|
490
|
-
if (metadata.kind === "code") {
|
|
491
|
-
return compactMetadataLines([
|
|
492
|
-
metadata.symbolName
|
|
493
|
-
? `symbol: ${metadata.symbolType} ${metadata.symbolName}`
|
|
494
|
-
: `symbol: ${metadata.symbolType}`,
|
|
495
|
-
metadata.scope ? `scope: ${metadata.scope}` : null,
|
|
496
|
-
metadata.signature ? `signature: ${oneLine(metadata.signature)}` : null,
|
|
497
|
-
metadata.modifiers.length > 0
|
|
498
|
-
? `modifiers: ${metadata.modifiers.join(" ")}`
|
|
499
|
-
: null,
|
|
500
|
-
metadata.doc ? `doc: ${oneLine(metadata.doc)}` : null,
|
|
501
|
-
]);
|
|
502
|
-
}
|
|
503
|
-
return compactMetadataLines([
|
|
504
|
-
metadata.heading ? `heading: ${metadata.heading}` : null,
|
|
505
|
-
typeof metadata.level === "number"
|
|
506
|
-
? `heading_level: ${metadata.level}`
|
|
507
|
-
: null,
|
|
508
|
-
metadata.scope ? `scope: ${metadata.scope}` : null,
|
|
509
|
-
]);
|
|
510
|
-
}
|
|
511
|
-
function compactMetadataLines(lines) {
|
|
512
|
-
return lines
|
|
513
|
-
.filter((line) => line !== null && line.trim().length > 0)
|
|
514
|
-
.join("\n");
|
|
515
|
-
}
|
|
516
|
-
async function embedContentsWithRetry(contents, model, embeddingScheduler) {
|
|
694
|
+
async function embedContentsWithRetry(contents, model, embeddingScheduler, signal, onModelProgress) {
|
|
517
695
|
let attempt = 0;
|
|
518
696
|
while (true) {
|
|
519
697
|
let retry = nonRetryableEmbeddingError();
|
|
520
698
|
let delayMs = 0;
|
|
521
699
|
try {
|
|
522
|
-
|
|
700
|
+
throwIfAborted(signal);
|
|
701
|
+
const result = await embeddingScheduler.run(() => model.embed(contents, {
|
|
702
|
+
purpose: "document",
|
|
703
|
+
signal,
|
|
704
|
+
onProgress: onModelProgress,
|
|
705
|
+
}), signal, (error) => {
|
|
523
706
|
retry = classifyEmbeddingRetry(error);
|
|
524
707
|
delayMs = retryDelayMs(attempt, retry);
|
|
525
708
|
if (retry.retryable) {
|
|
@@ -530,9 +713,14 @@ async function embedContentsWithRetry(contents, model, embeddingScheduler) {
|
|
|
530
713
|
}
|
|
531
714
|
});
|
|
532
715
|
embeddingScheduler.recordSuccess();
|
|
533
|
-
return
|
|
716
|
+
return result;
|
|
534
717
|
}
|
|
535
718
|
catch (error) {
|
|
719
|
+
if (signal?.aborted) {
|
|
720
|
+
throw signal.reason instanceof Error
|
|
721
|
+
? signal.reason
|
|
722
|
+
: new Error("Embedding was cancelled.");
|
|
723
|
+
}
|
|
536
724
|
if (!retry.retryable) {
|
|
537
725
|
retry = classifyEmbeddingRetry(error);
|
|
538
726
|
delayMs = retryDelayMs(attempt, retry);
|
|
@@ -540,11 +728,17 @@ async function embedContentsWithRetry(contents, model, embeddingScheduler) {
|
|
|
540
728
|
if (attempt >= maxRetryAttempts(retry) || !retry.retryable) {
|
|
541
729
|
throw error;
|
|
542
730
|
}
|
|
543
|
-
await
|
|
731
|
+
await abortableDelay(delayMs, signal);
|
|
544
732
|
attempt++;
|
|
545
733
|
}
|
|
546
734
|
}
|
|
547
735
|
}
|
|
736
|
+
function reportModelDownloadProgress(stats, progress, onProgress, embeddingScheduler) {
|
|
737
|
+
onProgress(stats, `downloading ${progress.model}`, {
|
|
738
|
+
...embeddingScheduler.snapshot(),
|
|
739
|
+
...progress,
|
|
740
|
+
});
|
|
741
|
+
}
|
|
548
742
|
function createEmbeddingScheduler(requestedConcurrency, model) {
|
|
549
743
|
return new AdaptiveEmbeddingScheduler(resolveEmbeddingConcurrencyPolicy(requestedConcurrency, model));
|
|
550
744
|
}
|
|
@@ -559,10 +753,17 @@ function resolveEmbeddingConcurrencyPolicy(requestedConcurrency, model) {
|
|
|
559
753
|
adaptive: requestedConcurrency > 1,
|
|
560
754
|
};
|
|
561
755
|
}
|
|
562
|
-
const
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
const
|
|
756
|
+
const remote = model.info.provider === "qwen";
|
|
757
|
+
const multimodal = model.info.inputKinds.includes("image");
|
|
758
|
+
const configuredLocalDefault = model.info.defaultConcurrency;
|
|
759
|
+
const localDefault = configuredLocalDefault !== undefined &&
|
|
760
|
+
Number.isInteger(configuredLocalDefault) &&
|
|
761
|
+
configuredLocalDefault > 0
|
|
762
|
+
? configuredLocalDefault
|
|
763
|
+
: 1;
|
|
764
|
+
const initial = remote ? (multimodal ? 4 : 8) : localDefault;
|
|
765
|
+
const max = remote ? (multimodal ? 8 : 12) : localDefault;
|
|
766
|
+
const min = Math.min(initial, 4);
|
|
566
767
|
return {
|
|
567
768
|
initial,
|
|
568
769
|
min,
|
|
@@ -585,11 +786,13 @@ class AdaptiveEmbeddingScheduler {
|
|
|
585
786
|
get taskConcurrency() {
|
|
586
787
|
return this.policy.max;
|
|
587
788
|
}
|
|
588
|
-
async run(task, onError) {
|
|
589
|
-
|
|
590
|
-
await this.
|
|
789
|
+
async run(task, signal, onError) {
|
|
790
|
+
throwIfAborted(signal);
|
|
791
|
+
await this.waitForCooldown(signal);
|
|
792
|
+
await this.acquire(signal);
|
|
591
793
|
try {
|
|
592
|
-
await this.waitForCooldown();
|
|
794
|
+
await this.waitForCooldown(signal);
|
|
795
|
+
throwIfAborted(signal);
|
|
593
796
|
return await task();
|
|
594
797
|
}
|
|
595
798
|
catch (error) {
|
|
@@ -631,19 +834,36 @@ class AdaptiveEmbeddingScheduler {
|
|
|
631
834
|
retryableFailures: this.retryableFailures,
|
|
632
835
|
};
|
|
633
836
|
}
|
|
634
|
-
async waitForCooldown() {
|
|
837
|
+
async waitForCooldown(signal) {
|
|
635
838
|
const remaining = this.cooldownUntil - Date.now();
|
|
636
839
|
if (remaining > 0) {
|
|
637
|
-
await
|
|
840
|
+
await abortableDelay(remaining, signal);
|
|
638
841
|
}
|
|
639
842
|
}
|
|
640
|
-
async acquire() {
|
|
843
|
+
async acquire(signal) {
|
|
844
|
+
throwIfAborted(signal);
|
|
641
845
|
if (this.active < this.currentConcurrency) {
|
|
642
846
|
this.active++;
|
|
643
847
|
return;
|
|
644
848
|
}
|
|
645
|
-
await new Promise((resolve) => {
|
|
646
|
-
|
|
849
|
+
await new Promise((resolve, reject) => {
|
|
850
|
+
const queued = () => {
|
|
851
|
+
signal?.removeEventListener("abort", abort);
|
|
852
|
+
resolve();
|
|
853
|
+
};
|
|
854
|
+
const abort = () => {
|
|
855
|
+
const index = this.queue.indexOf(queued);
|
|
856
|
+
if (index >= 0) {
|
|
857
|
+
this.queue.splice(index, 1);
|
|
858
|
+
}
|
|
859
|
+
reject(abortError(signal));
|
|
860
|
+
};
|
|
861
|
+
if (signal?.aborted) {
|
|
862
|
+
reject(abortError(signal));
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
866
|
+
this.queue.push(queued);
|
|
647
867
|
});
|
|
648
868
|
}
|
|
649
869
|
release() {
|
|
@@ -724,8 +944,32 @@ function retryAfterMsFromText(text) {
|
|
|
724
944
|
}
|
|
725
945
|
return undefined;
|
|
726
946
|
}
|
|
727
|
-
function
|
|
728
|
-
|
|
947
|
+
function abortableDelay(ms, signal) {
|
|
948
|
+
if (ms <= 0) {
|
|
949
|
+
return Promise.resolve();
|
|
950
|
+
}
|
|
951
|
+
throwIfAborted(signal);
|
|
952
|
+
return new Promise((resolve, reject) => {
|
|
953
|
+
const timer = setTimeout(() => {
|
|
954
|
+
signal?.removeEventListener("abort", abort);
|
|
955
|
+
resolve();
|
|
956
|
+
}, ms);
|
|
957
|
+
const abort = () => {
|
|
958
|
+
clearTimeout(timer);
|
|
959
|
+
reject(abortError(signal));
|
|
960
|
+
};
|
|
961
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
function throwIfAborted(signal) {
|
|
965
|
+
if (signal?.aborted) {
|
|
966
|
+
throw abortError(signal);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function abortError(signal) {
|
|
970
|
+
return signal?.reason instanceof Error
|
|
971
|
+
? signal.reason
|
|
972
|
+
: new Error("Embedding was cancelled.");
|
|
729
973
|
}
|
|
730
974
|
function countPublicEntities(fragments) {
|
|
731
975
|
let count = 0;
|
|
@@ -777,10 +1021,10 @@ function toEngineError(error, message, options) {
|
|
|
777
1021
|
cause: error,
|
|
778
1022
|
});
|
|
779
1023
|
}
|
|
780
|
-
function
|
|
1024
|
+
function workspaceIndexContext(workspaceIndex) {
|
|
781
1025
|
return (errorDetails([
|
|
782
|
-
detail("
|
|
783
|
-
|
|
1026
|
+
detail("workspace_index_id", workspaceIndex.id),
|
|
1027
|
+
workspaceIndexDetail(workspaceIndex.name),
|
|
784
1028
|
]) ?? "");
|
|
785
1029
|
}
|
|
786
1030
|
function fileContext(file) {
|