Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/feature-reorganization.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"@launchstack/llm": minor
"@launchstack/conversion": minor
"@launchstack/indexing": minor
"@launchstack/search": minor
"@launchstack/retrieval": minor
"@launchstack/orchestration": minor
"@launchstack/editing": minor
"@launchstack/collab": minor
Expand Down
19 changes: 19 additions & 0 deletions .changeset/retrieval-rename.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
"@launchstack/retrieval": minor
"@launchstack/engine": patch
"@launchstack/tools": patch
"@launchstack/pipelines": patch
---

Rename `@launchstack/search` to `@launchstack/retrieval` and consolidate
every retrieval algorithm and tool into it, organized as one documented
folder per algorithm: `algorithms/{bm25,vector,fusion,ensemble,rlm,graph,
reranking}` and `tools/{citation-builder,grounded-retrieval,rag-search-tool,
rlm-search}`. The RLM, graph, and ensemble retrievers move in from apps/web;
the predictive-analysis ANN strategies become named modules behind the
vector retriever; grounded-retrieval moves over from `@launchstack/tools`
(a re-export keeps the old path). The `RagPort` contract is unchanged; the
ensemble's env reads become `configureEnsemble()` injected by the
composition root; old subpaths (`./retrievers`, `./reranking`,
`./citation-builder`) survive one release as aliases. The old package name
is lint-banned alongside the ADR-008 legacy names.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
run: >-
pnpm --filter @launchstack/evidence
--filter @launchstack/conversion
--filter @launchstack/search
--filter @launchstack/retrieval
--filter @launchstack/document-conversion-engine
--filter @launchstack/worker test

Expand Down
6 changes: 3 additions & 3 deletions REPOSITORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ outright, since nothing was ever published under the old names.
| `packages/orchestration` | TS library (published) | Durable work (ADR-003): the pipeline-events contract, the SKIP LOCKED outbox store, the worker tick with bounded retries, transactional source acceptance, and the stage ports. |
| `packages/conversion` | TS library (published) | Any source → EvidenceDocument: per-type document converters with their wire + client, audio- and video-transcription in their own folders, OCR primitives, chunking, archive expansion, the extraction router. |
| `packages/indexing` | TS library (published) | EvidenceDocument → searchable: the two-stage doc-ingestion pipeline, entity extraction, Neo4j graph sync (optional peer). |
| `packages/search` | TS library (published) | Question → cited answer: BM25 + vector ensemble behind a replaceable port, reranking, the citation builder. |
| `packages/retrieval` | TS library (published) | Question → cited answer (renamed from `search`): every retrieval algorithm as a documented folder under `src/algorithms/` (bm25, vector, fusion, ensemble, rlm, graph, reranking) behind the replaceable RagPort, plus the retrieval-facing tools under `src/tools/`. |
| `packages/editing` | TS library (published) | Tracked-changes Word editing (ADR-007): the adeu wire contract + typed client. |
| `packages/document-conversion-engine` | TS library (published) | PDF rendering (ADR-009): the typed client for the Gotenberg service — Office → PDF via LibreOffice, HTML/Markdown → PDF via Chromium. Imports nothing, reads no env. |
| `packages/google-drive` | TS library (published) | Thin typed client for the Google Drive v3 REST API and Google OAuth 2.0 token endpoints — the wire layer for Drive-linked documents. Framework-free; credentials injected, never read from the environment. |
| `packages/collab` | TS library (published) | Agent meetings in Slack-shaped channels, signed HTTP agent transport. Node built-ins only. |
| `packages/engine` | TS library (published) | The one-install aggregate: `createEngine(CoreConfig)` plus re-exports of every feature surface. |
| `packages/schema-generator` | TS library (published) | Walks the feature wire contracts and emits the one `schemas/v1/` bundle the Python contract tests validate against. |
| `packages/tools` | TS library | Shared, contract-typed capabilities the verticals compose (company-context, grounded-retrieval, brand-voice, persona, web-research, social-publish, platform-profiles, content-scoring, claim-evidence, stage-runner). Tools may import bricks up to `search`, never a vertical. |
| `packages/tools` | TS library | Shared, contract-typed capabilities the verticals compose (company-context, grounded-retrieval, brand-voice, persona, web-research, social-publish, platform-profiles, content-scoring, claim-evidence, stage-runner). Tools may import bricks up to `retrieval`, never a vertical. |
| `packages/design-tokens` | CSS (published) | The design contract: primitives feeding semantic tokens, one file, no build step. |
| `pipelines/` | TS library (published) | **The compositions tier** — nine verticals (marketing, email, founder-weekly-review, legal-templates, company-metadata, client-prospector, trend-search, connectors, repo-explainer) + the product schema they own. May import any brick; no brick may import it (lint-enforced). |
| `services/document-converter` | Node/Express | Routing decisions, vision classification, PDF page rendering, docling-backed parsing → typed `EvidenceDocument`. Replaced `ocr-router` + `ocr-worker` (ADR-004). |
Expand All @@ -65,7 +65,7 @@ store llm ← persistence · model calls (embeddings live here)
orchestration ← events, outbox, tick, source acceptance
conversion ← any source → EvidenceDocument
indexing ← EvidenceDocument → chunks, vectors, graph
search ← question → cited answer
retrieval ← question → cited answer
engine ← createEngine() aggregate
pipelines/ apps/ ← compositions and products (never imported by bricks)
```
Expand Down
2 changes: 1 addition & 1 deletion apps/web/__tests__/api/agent/references.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
buildReferences,
extractRecommendedPages,
} from "~/app/api/agents/documentQ&A/services/references";
import type { SearchResult } from "~/lib/tools/rag";
import type { SearchResult } from "@launchstack/retrieval/search-types";

describe("references service", () => {
it("extracts sorted unique recommended pages and ignores invalid values", () => {
Expand Down
17 changes: 8 additions & 9 deletions apps/web/__tests__/api/agents/documentQ&A/AIChat/query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { POST } from "~/app/api/agents/documentQ&A/AIChat/query/route";
import { requireWorkspaceContext } from "~/lib/require-workspace-context";
import type { WorkspaceContext } from "~/lib/require-workspace-context";
import { companyEnsembleSearch, documentEnsembleSearch } from "~/lib/tools/rag";
import { companyEnsembleSearch, documentEnsembleSearch } from "~/server/rag/ensemble";

jest.mock("~/lib/require-workspace-context", () => {
const actual = jest.requireActual("~/lib/require-workspace-context");
Expand Down Expand Up @@ -78,20 +78,19 @@ jest.mock("~/server/metrics/registry", () => ({
qaRequestDuration: { startTimer: () => jest.fn() },
}));

jest.mock("~/app/api/agents/predictive-document-analysis/services/annOptimizer", () => ({
__esModule: true,
default: class {
searchSimilarChunks = jest.fn().mockResolvedValue([]);
},
}));

const RETRIEVED = [{ pageContent: "chunk text", metadata: { page: 1 } }];

jest.mock("~/lib/tools/rag", () => ({
jest.mock("~/server/rag/ensemble", () => ({
companyEnsembleSearch: jest.fn(),
documentEnsembleSearch: jest.fn(),
multiDocEnsembleSearch: jest.fn(),
}));

jest.mock("@launchstack/retrieval/algorithms/vector", () => ({
createDocumentVectorRetriever: jest.fn(),
ANNOptimizer: class {
searchSimilarChunks = jest.fn().mockResolvedValue([]);
},
}));

jest.mock("@launchstack/llm/embeddings", () => ({
Expand Down
18 changes: 14 additions & 4 deletions apps/web/__tests__/api/predictiveDocumentAnalysis/content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import {
} from "~/app/api/agents/predictive-document-analysis/utils/content";
import type { PdfChunk } from "~/app/api/agents/predictive-document-analysis/types";
import { db } from "~/server/db/index";
import { getDb } from "@launchstack/store/client";
import { document, documentSections } from "@launchstack/store/schema";
import { hybridSearchWithRRF } from "~/app/api/agents/predictive-document-analysis/services/hybridSearch";
import { hybridSearchWithRRF } from "@launchstack/retrieval/algorithms/fusion";
import { findSuggestedCompanyDocuments } from "~/app/api/agents/predictive-document-analysis/services/documentMatcher";

jest.mock("~/server/db/index", () => ({
Expand All @@ -19,6 +20,13 @@ jest.mock("~/server/db/index", () => ({
},
}));

// The moved fusion/strategy algorithms reach the database through the store
// client, not the app's ~/server/db proxy — same chain mock, second seam.
jest.mock("@launchstack/store/client", () => ({
getDb: jest.fn(),
toRows: (rows: unknown) => rows,
}));

jest.mock("~/app/api/agents/predictive-document-analysis/utils/embeddings", () => ({
getEmbeddings: jest.fn().mockResolvedValue([]),
}));
Expand Down Expand Up @@ -88,7 +96,7 @@ type QueryChain = {
};

function mockPredictiveSelects(): void {
(db.select as jest.Mock).mockImplementation(() => {
const makeSelect = () => {
let source: unknown;
let condition: unknown;
const query: QueryChain = {
Expand Down Expand Up @@ -117,7 +125,9 @@ function mockPredictiveSelects(): void {
},
};
return query;
});
};
(db.select as jest.Mock).mockImplementation(makeSelect);
(getDb as jest.Mock).mockImplementation(() => ({ select: makeSelect }));
}

describe("predictive current-version retrieval", () => {
Expand All @@ -127,7 +137,7 @@ describe("predictive current-version retrieval", () => {
});

it("excludes historical chunks from hybrid results", async () => {
const results = await hybridSearchWithRRF("schedule a", [2], 8);
const results = await hybridSearchWithRRF("schedule a", [2], 8, async () => []);

expect(results).toHaveLength(1);
expect(results[0]?.content).toBe(currentChunk.content);
Expand Down
Loading
Loading