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
24 changes: 12 additions & 12 deletions API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Two surfaces: the **TypeScript SDK** (`@augur/core`) and the **HTTP API** (`@aug
```ts
import { Augur } from "@augur/core";

const qb = new Augur({
const augr = new Augur({
adapter, // VectorAdapter — default: InMemoryAdapter
embedder, // Embedder — default: HashEmbedder
chunker, // Chunker — default: SentenceChunker
Expand All @@ -24,21 +24,21 @@ const qb = new Augur({

All options are optional; with none, you get a fully functional in-memory pipeline.

### `qb.index(documents)`
### `augr.index(documents)`

Chunks → embeds → upserts.

```ts
const result = await qb.index([
const result = await augr.index([
{ id: "1", content: "...", metadata: { source: "wiki" } },
]);
// result = { documents: 1, chunks: 4, trace: { chunkingMs, embeddingMs, upsertMs, totalMs } }
```

### `qb.search(request)`
### `augr.search(request)`

```ts
const { results, trace } = await qb.search({
const { results, trace } = await augr.search({
query: "...",
documents, // optional — ad-hoc inline docs
topK: 10, // default 10
Expand Down Expand Up @@ -100,7 +100,7 @@ interface SearchTrace {
}
```

### `qb.clear()`
### `augr.clear()`

Wipes the underlying adapter.

Expand All @@ -112,7 +112,7 @@ Default base URL: `http://localhost:3001`. All endpoints accept and return JSON.

### Auth

If the server was started with `QUERYBRAIN_API_KEY=<secret>`, every request must include `x-api-key: <secret>`. Otherwise no auth.
If the server was started with `AUGUR_API_KEY=<secret>`, every request must include `x-api-key: <secret>`. Otherwise no auth.

### `GET /health`

Expand Down Expand Up @@ -203,23 +203,23 @@ Wipes the underlying adapter. Idempotent.
### Force a strategy for testing

```ts
await qb.search({ query: "...", forceStrategy: "keyword" });
await augr.search({ query: "...", forceStrategy: "keyword" });
```

The decision still ends up in the trace, with `forceStrategy=...` as the recorded reason.

### Bound latency

```ts
await qb.search({ query: "...", latencyBudgetMs: 250 });
await augr.search({ query: "...", latencyBudgetMs: 250 });
```

A budget under 800ms disables reranking automatically. The trace will say "reranking skipped (latency budget)".

### Filter by metadata

```ts
await qb.search({ query: "...", filter: { source: "wiki", lang: "en" } });
await augr.search({ query: "...", filter: { source: "wiki", lang: "en" } });
```

Adapters that report `capabilities.filtering = true` (all of ours except HashEmbedder-mode) honor this. Filters are AND-combined.
Expand All @@ -242,10 +242,10 @@ class LoggingRouter extends HeuristicRouter {
import { Augur } from "@augur/core";
import express from "express";

const qb = new Augur({ /* prod config */ });
const augr = new Augur({ /* prod config */ });
const app = express();
app.post("/search", async (req, res) => {
const result = await qb.search(req.body);
const result = await augr.search(req.body);
res.json(result);
});
```
Expand Down
16 changes: 8 additions & 8 deletions DEVELOPMENT_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ pnpm dev:server
The server runs with the `InMemoryAdapter` and `HashEmbedder` by default. To use real services:

```bash
QUERYBRAIN_ADAPTER=pgvector \
AUGUR_ADAPTER=pgvector \
DATABASE_URL=postgres://localhost/qb \
QUERYBRAIN_EMBEDDER=openai \
AUGUR_EMBEDDER=openai \
OPENAI_API_KEY=sk-... \
pnpm dev:server
```
Expand All @@ -65,7 +65,7 @@ pnpm dev:dashboard
# → http://localhost:3000
```

The dashboard expects the server at `http://localhost:3001`. Override with `QUERYBRAIN_URL=...`.
The dashboard expects the server at `http://localhost:3001`. Override with `AUGUR_URL=...`.

### Run tests

Expand Down Expand Up @@ -122,7 +122,7 @@ class MyRouter implements Router {
}
}

const qb = new Augur({ router: new MyRouter() });
const augr = new Augur({ router: new MyRouter() });
```

Two principles:
Expand Down Expand Up @@ -162,7 +162,7 @@ When this is more than once a month, switch to changesets.

**The server returns 500 on `/search`** — check `/health`. The `capabilities` block tells you what the configured adapter supports. If you forced a strategy the adapter can't do, that's the cause.

**`HashEmbedder` results look random** — they kind of are. It's a feature-hash, not a semantic embedder. For real semantics, set `QUERYBRAIN_EMBEDDER=openai`.
**`HashEmbedder` results look random** — they kind of are. It's a feature-hash, not a semantic embedder. For real semantics, set `AUGUR_EMBEDDER=openai`.

## Deployment

Expand All @@ -171,9 +171,9 @@ When this is more than once a month, switch to changesets.
```bash
docker build -t augur-server .
docker run -p 3001:3001 \
-e QUERYBRAIN_ADAPTER=pgvector \
-e AUGUR_ADAPTER=pgvector \
-e DATABASE_URL=... \
-e QUERYBRAIN_API_KEY=$(openssl rand -hex 32) \
-e AUGUR_API_KEY=$(openssl rand -hex 32) \
augur-server
```

Expand All @@ -189,7 +189,7 @@ Most teams will want:
- `/qb/*` → dashboard
- All HTTPS / auth / rate limits handled at the proxy

The server has an optional `QUERYBRAIN_API_KEY` for shared-secret auth. For anything more sophisticated (per-user keys, OAuth) use your reverse proxy or wrap the Fastify app.
The server has an optional `AUGUR_API_KEY` for shared-secret auth. For anything more sophisticated (per-user keys, OAuth) use your reverse proxy or wrap the Fastify app.

## Contributing

Expand Down
18 changes: 9 additions & 9 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ The 30-line "hello world".
```ts
import { Augur } from "@augur/core";

const qb = new Augur();
const augr = new Augur();

await qb.index([
await augr.index([
{ id: "pg", content: "PostgreSQL supports vector search via pgvector." },
{ id: "redis", content: "Redis is an in-memory key-value store." },
{ id: "k8s", content: "Kubernetes manages containers across hosts." },
]);

const { results, trace } = await qb.search({ query: "vector database" });
const { results, trace } = await augr.search({ query: "best vector database for production" });

console.log(trace.decision.strategy); // → "hybrid"
console.log(results[0].chunk.documentId);
Expand Down Expand Up @@ -80,7 +80,7 @@ class JsonFileAdapter extends BaseAdapter {
// ... upsert / searchVector / searchKeyword / delete / count / clear ...
}

const qb = new Augur({ adapter: new JsonFileAdapter("./store.json") });
const augr = new Augur({ adapter: new JsonFileAdapter("./store.json") });
```

The full implementation is `examples/custom-adapter/index.ts`. About 90 lines, including the BM25-ish keyword search.
Expand Down Expand Up @@ -121,7 +121,7 @@ import {
CohereReranker,
} from "@augur/core";

const qb = new Augur({
const augr = new Augur({
adapter: new PineconeAdapter({
indexHost: process.env.PINECONE_INDEX_HOST!,
apiKey: process.env.PINECONE_API_KEY!,
Expand Down Expand Up @@ -163,7 +163,7 @@ import { Augur, PgVectorAdapter, OpenAIEmbedder } from "@augur/core";
const client = new pg.Client({ connectionString: process.env.DATABASE_URL });
await client.connect();

const qb = new Augur({
const augr = new Augur({
adapter: new PgVectorAdapter({
client: { query: (sql, params) => client.query(sql, params).then((r) => ({ rows: r.rows })) },
table: "chunks",
Expand All @@ -182,7 +182,7 @@ Vector + keyword + hybrid all in one place, no extra services.
The whole point of the system. Every search produces a trace; every trace is enough to explain (or debug) the result.

```ts
const { trace } = await qb.search({ query: "how to deploy with zero downtime" });
const { trace } = await augr.search({ query: "how to deploy with zero downtime" });

console.log(trace.decision);
// {
Expand Down Expand Up @@ -226,10 +226,10 @@ import { BaseRetriever } from "@langchain/core/retrievers";
import { Augur } from "@augur/core";

class AugurRetriever extends BaseRetriever {
qb = new Augur({ /* ... */ });
augr = new Augur({ /* ... */ });
lc_namespace = ["custom", "augur"];
async _getRelevantDocuments(query: string) {
const { results } = await this.qb.search({ query });
const { results } = await this.augr.search({ query });
return results.map((r) => ({
pageContent: r.chunk.content,
metadata: { ...r.chunk.metadata, score: r.score, traceId: r.chunk.id },
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ It is **not** a vector database. It is a thin, composable orchestration layer de
```ts
import { Augur } from "@augur/core";

const qb = new Augur();
const augr = new Augur();

await qb.index([
await augr.index([
{ id: "1", content: "PostgreSQL supports vector indexing via pgvector." },
{ id: "2", content: "Pinecone is a managed vector database." },
]);

const { results, trace } = await qb.search({
const { results, trace } = await augr.search({
query: "How do I store vectors in Postgres?",
});

Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<nav className="flex gap-6 text-ink-300 text-xs">
<a href="/" className="hover:text-white">Playground</a>
<a href="/traces" className="hover:text-white">Traces</a>
<a href={process.env.QUERYBRAIN_URL + "/docs"} target="_blank" className="hover:text-white">API Docs ↗</a>
<a href={process.env.AUGUR_URL + "/docs"} target="_blank" className="hover:text-white">API Docs ↗</a>
</nav>
</header>
<main className="px-6 py-6 max-w-6xl mx-auto">{children}</main>
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState } from "react";
import { TraceView } from "@/components/TraceView";
import { ResultList } from "@/components/ResultList";

const QB = process.env.QUERYBRAIN_URL ?? "http://localhost:3001";
const AUGR = process.env.AUGUR_URL ?? "http://localhost:3001";

interface SearchResp {
results: Array<{
Expand All @@ -31,7 +31,7 @@ export default function PlaygroundPage() {
const body: any = { query, topK };
if (forced) body.forceStrategy = forced;
if (budget !== "") body.latencyBudgetMs = Number(budget);
const r = await fetch(`${QB}/search`, {
const r = await fetch(`${AUGR}/search`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/app/traces/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { useEffect, useState } from "react";
import { TraceView } from "@/components/TraceView";

const QB = process.env.QUERYBRAIN_URL ?? "http://localhost:3001";
const AUGR = process.env.AUGUR_URL ?? "http://localhost:3001";

export default function TracesPage() {
const [traces, setTraces] = useState<any[]>([]);
Expand All @@ -12,7 +12,7 @@ export default function TracesPage() {

async function load() {
try {
const r = await fetch(`${QB}/traces?limit=200`);
const r = await fetch(`${AUGR}/traces?limit=200`);
const json = await r.json();
setTraces(json.traces);
if (!selected && json.traces[0]) setSelected(json.traces[0]);
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const nextConfig = {
reactStrictMode: true,
env: {
QUERYBRAIN_URL: process.env.QUERYBRAIN_URL ?? "http://localhost:3001",
AUGUR_URL: process.env.AUGUR_URL ?? "http://localhost:3001",
},
};
export default nextConfig;
8 changes: 4 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ services:
environment:
PORT: "3001"
LOG_LEVEL: "info"
QUERYBRAIN_ADAPTER: "in-memory"
QUERYBRAIN_EMBEDDER: "hash"
AUGUR_ADAPTER: "in-memory"
AUGUR_EMBEDDER: "hash"
healthcheck:
test: ["CMD", "wget", "-q", "-O-", "http://localhost:3001/health"]
interval: 5s
Expand All @@ -29,13 +29,13 @@ services:
dashboard:
image: node:20-alpine
working_dir: /app
command: sh -c "corepack enable && pnpm install && pnpm --filter dashboard dev"
command: sh -c "corepack enable && pnpm install && pnpm --filter @augur/dashboard dev"
volumes:
- ./:/app
ports:
- "3000:3000"
environment:
QUERYBRAIN_URL: "http://server:3001"
AUGUR_URL: "http://server:3001"
depends_on:
server:
condition: service_healthy
6 changes: 3 additions & 3 deletions examples/basic-search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import { Augur } from "@augur/core";

async function main() {
const qb = new Augur();
const augr = new Augur();

await qb.index([
await augr.index([
{
id: "pg-pooling",
content:
Expand Down Expand Up @@ -53,7 +53,7 @@ async function main() {
];

for (const q of queries) {
const { results, trace } = await qb.search({ query: q, topK: 2 });
const { results, trace } = await augr.search({ query: q, topK: 2 });
console.log("\n=== Query:", q);
console.log(
`Strategy: ${trace.decision.strategy}${trace.decision.reranked ? " (+rerank)" : ""} ` +
Expand Down
6 changes: 3 additions & 3 deletions examples/custom-adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ function cosine(a: number[], b: number[]) {
async function main() {
const adapter = new JsonFileAdapter("./store.json");
await adapter.load();
const qb = new Augur({ adapter });
const augr = new Augur({ adapter });

await qb.index([
await augr.index([
{ id: "1", content: "Augur is an adaptive retrieval orchestration layer." },
{ id: "2", content: "Custom adapters are easy: implement the VectorAdapter interface." },
]);

const { results, trace } = await qb.search({ query: "how to write an adapter" });
const { results, trace } = await augr.search({ query: "how to write an adapter" });
console.log("strategy:", trace.decision.strategy);
for (const r of results) console.log(r.chunk.id, r.score.toFixed(3), r.chunk.content);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ npm install @augur/core
```ts
import { Augur } from "@augur/core";

const qb = new Augur();
const augr = new Augur();

await qb.index([
await augr.index([
{ id: "1", content: "Postgres supports vector search via pgvector." },
{ id: "2", content: "Pinecone is a managed vector database." },
]);

const { results, trace } = await qb.search({
const { results, trace } = await augr.search({
query: "How do I store vectors in Postgres?",
topK: 5,
});
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"build": "tsc -p tsconfig.json",
"dev": "tsc -p tsconfig.json --watch",
"typecheck": "tsc --noEmit",
"test": "node --test --experimental-strip-types --import tsx 'src/**/*.test.ts'",
"test": "node --test --import tsx 'src/**/*.test.ts'",
"clean": "rm -rf dist"
},
"devDependencies": {
Expand Down
Loading
Loading