Skip to content

Make indexing and per-source chunk optional so minimal RAG configs validate (#88)#124

Merged
jpr5 merged 1 commit into
mainfrom
fix/issue-88-minimal-rag-config
Jun 25, 2026
Merged

Make indexing and per-source chunk optional so minimal RAG configs validate (#88)#124
jpr5 merged 1 commit into
mainfrom
fix/issue-88-minimal-rag-config

Conversation

@jpr5

@jpr5 jpr5 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Issue #88 reports three problems with the Zod config validator that prevent a docs-compliant minimal RAG config (using local embeddings) from booting. This PR addresses all three, minimally and without regressing any existing valid config.

Claim Diagnosis Fix
1. "Local embeddings rejected" NOT a schema bug. LocalEmbeddingConfigSchema is already in the EmbeddingConfigSchema discriminated union. The real cause: the prod Docker image is built with npm ci --omit=dev, which omits the optional @xenova/transformers peer dependency (left commented-out in the Dockerfile). The server boots and validates fine, then throws a clear Install @xenova/transformers… error at runtime (src/indexing/embeddings.ts) when local embeddings first run; pathfinder validate warns. Deps/docs fix, not schema. Clarified the Dockerfile comment around the optional peer-dep lines (kept commented — still optional, NOT a hard dependency) and added a deploy-docs callout explaining the prod image omits optional peer deps and how to bake them in.
2. Indexing params mandatory IndexingConfigSchema required auto_reindex / reindex_hour_utc / stale_threshold_hours with no defaults, and ServerConfigSchema.superRefine hard-required an indexing block whenever search/knowledge tools were present. Gave the three fields sensible .default()s (false / 3 / 24) and made the top-level indexing block .default({}). Removed the now-dead hasRag && !cfg.indexing superRefine check (the block is always present). The embedding presence check is unchanged.
3. chunk mandatory per source BaseSourceFields.chunk had no .optional(), even though every inner field of ChunkConfigSchema is already optional. Made chunk default to {} so a source can omit it and fall back to the chunker's per-source-type defaults.

Behavior safety

  • Defaults only fill omitted fields; explicit values pass through unchanged.
  • src/indexing/orchestrator.ts already read serverCfg.indexing?.… with a ?? 24 fallback, so promoting indexing from optional-to-defaulted is behavior-preserving (a config previously lacking indexing had auto-reindex effectively off; now it's an explicit auto_reindex: false).
  • @xenova/transformers remains an optional peer dependency — not promoted to a hard dependency.

Red-Green Proof

Exercised the real parse surface: ServerConfigSchema (the schema config.ts/validate.ts run YAML through), with the docs-compliant minimal config from the issue (local provider, a source with no chunk, a search tool, no indexing block). New test: src/__tests__/minimal-rag-config.test.ts.

RED (before the schema fix — current strict schema)

stderr | minimal RAG config (issue #88) > accepts a local-embedding config with no chunk and no indexing block
[
  { "path": ["sources", 0, "chunk"],            "message": "Required" },
  { "path": ["indexing", "auto_reindex"],        "message": "Required" },
  { "path": ["indexing", "reindex_hour_utc"],    "message": "Required" },
  { "path": ["indexing", "stale_threshold_hours"], "message": "Required" }
]

 ❯ src/__tests__/minimal-rag-config.test.ts (4 tests | 3 failed)
   × accepts a local-embedding config with no chunk and no indexing block
   × defaults indexing fields when the indexing block is omitted
   × IndexingConfigSchema parses an empty object via defaults
 FAIL  … accepts a local-embedding config with no chunk and no indexing block
   AssertionError: expected false to be true // Object.is equality

 Test Files  1 failed (1)
      Tests  3 failed | 1 passed (4)

(The 4th test — "REGRESSION: a full explicit config still validates unchanged" — passed under RED, confirming the baseline.)

GREEN (after the schema fix — same test)

 ✓ minimal RAG config (issue #88) > accepts a local-embedding config with no chunk and no indexing block
 ✓ minimal RAG config (issue #88) > defaults indexing fields when the indexing block is omitted
 ✓ minimal RAG config (issue #88) > IndexingConfigSchema parses an empty object via defaults
 ✓ minimal RAG config (issue #88) > REGRESSION: a full explicit config still validates unchanged

 Test Files  1 passed (1)
      Tests  4 passed (4)

Regression assertion

The REGRESSION: test parses a full explicit config (openai embedding, explicit indexing, explicit per-source chunk) and asserts every value passes through unchanged — defaults never override explicit input. Also updated src/__tests__/tool-config.test.ts: the prior rejects search config without indexing test (which asserted the old hard-fail) now asserts the new accept-with-defaults behavior.

Pre-push quality

Ran in CI order, all green: prettier --check (src + scripts) → tsc --noEmit -p tsconfig.scripts.jsonnpm run build → full vitest suite (343 files / 6531 tests passed). Dockerfile edit verified syntactically sane (image not built; change is comment-only on optional RUN lines).

Files changed

  • src/types.tschunk.default({}); IndexingConfigSchema field defaults; indexing block .default({}); removed dead superRefine indexing check.
  • src/__tests__/minimal-rag-config.test.ts — new red-green + regression tests.
  • src/__tests__/tool-config.test.ts — updated the indexing-required test to the new behavior.
  • Dockerfile — clarified optional peer-dep guidance (still optional/commented).
  • docs/deploy/index.html — added a Docker peer-deps callout.

Closes #88

🤖 Generated with Claude Code

…lidate

Fixes the three v1.13.3+ Zod-validator complaints in issue #88 that block a
docs-compliant minimal RAG config (local embeddings) from booting:

- IndexingConfigSchema fields (auto_reindex, reindex_hour_utc,
  stale_threshold_hours) now have sensible defaults (false / 3 / 24), and the
  top-level `indexing` block defaults to `{}`. A manual-only / minimal config
  no longer hard-fails for omitting a cron schedule. The now-dead
  `hasRag && !cfg.indexing` superRefine check is removed; the embedding
  presence check stays.
- BaseSourceFields.chunk is now optional (defaults to `{}`). Its inner fields
  were already all-optional, so a source can omit `chunk` and fall back to the
  chunker's per-type defaults.
- Local embeddings were never a schema bug — LocalEmbeddingConfigSchema is
  already in the embedding union. The real cause is the prod Docker image
  (`npm ci --omit=dev`) omitting the optional @xenova/transformers peer dep.
  Clarified the Dockerfile guidance and added a deploy-docs callout; kept the
  dep optional (not a hard dependency).

Existing valid configs are preserved (defaults only fill omitted fields;
explicit values pass through unchanged).

Closes #88
@jpr5

jpr5 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

CI note: test failures are pre-existing aimock flakiness, unrelated to this PR

CI's test job is red, but none of the failures are in code this PR touches. Evidence:

  • This branch is main + exactly one commit; the diff is src/types.ts (Zod config schema), two test files, Dockerfile, and docs/deploy/index.htmlzero src/atlas/** or aimock files.
  • All failures are (aimock)-tagged tests across atlas-llm, atlas-exclude, atlas-artifact-sync, and atlas-adapter-episodic, with the diagnostic [distiller] Failed to parse LLM JSON response: … "not valid json {{{" — i.e. the in-process aimock LLM server served a default/garbage response instead of the recorded fixture.
  • The failure count was non-deterministic across two runs (9 → 64) — the signature of a flake, not a logic regression.
  • The same aimock atlas tests pass on main's latest CI (Static Quality run 27993011256, test = success), and they pass 74/74 locally (3 consecutive runs) on this branch.
  • The atlas sync code imports a separate src/atlas/types.ts module; there is zero symbol overlap with the root src/types.ts schema this PR edits.

The four substantive checks relevant to this change — build, prettier, typecheck-scripts, version-sync — all pass, as do this PR's own new schema tests. The aimock atlas flake needs a separate fix on main (out of scope here).

@jpr5 jpr5 merged commit ca5e10f into main Jun 25, 2026
15 of 18 checks passed
@jpr5 jpr5 deleted the fix/issue-88-minimal-rag-config branch June 25, 2026 17:57
@jpr5 jpr5 mentioned this pull request Jun 25, 2026
jpr5 added a commit that referenced this pull request Jun 25, 2026
## Release v1.16.0 (minor)

Releases the user-visible changes already merged to `main`: **#124**
(config validation relaxation) and **#127** (Atlas distiller "Premature
close" runtime fix). Current `1.15.4` → `1.16.0`. #128 was a CI-only
vitest scoping change and is intentionally not in the changelog (does
not ship).

### CHANGELOG

## 1.16.0

### Minor Changes

- Config validation accepts minimal RAG configs — `indexing` and
per-source `chunk` now optional with defaults (#124)
- Fixed Atlas distiller LLM client "Premature close" errors, by
disabling keep-alive on the test/proxy client (#127)

### Version bumps
- `package.json` `version`: 1.15.4 → 1.16.0
- `src/cli.ts` `.version(...)`: 1.15.4 → 1.16.0
- version-sync verified in agreement.

### Publishing
Merging this PR triggers `publish-release.yml` to publish
`@copilotkit/pathfinder@1.16.0` to npm and create the tag/GitHub
Release. Do not tag or release by hand.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: v1.13.3 Zod Schema Validator strictly rejects local embeddings and enforces mandatory indexing/chunking parameters

1 participant