@quelvio/langchain 0.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@quelvio/langchain` are documented here. The format
4
+ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this
5
+ package adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.0] - 2026-05-22
8
+
9
+ Initial release. JavaScript/TypeScript sibling of the Python
10
+ [`quelvio-langchain`](https://pypi.org/project/quelvio-langchain/) package.
11
+
12
+ ### Added
13
+
14
+ - `QuelvioClient` — async HTTP client wrapping the Quelvio enterprise API
15
+ (`POST /v1/enterprise/query`, `GET /v1/enterprise/domains`,
16
+ `GET /v1/enterprise/sources/{query_id}`).
17
+ - `QuelvioRetriever` — LangChain.js retriever extending `BaseRetriever`.
18
+ Returns `Document`s with `chunk_id`, `source_url`, `authority_score`,
19
+ `taxonomy_domain`, and author metadata.
20
+ - `QuelvioTool` — LangChain.js tool extending `StructuredTool`. Schema
21
+ accepts `question` (required) plus optional `mode`, `max_sources`,
22
+ `domain`. Output is a synthesized answer + citation list.
23
+ - `synthesizeAnswer()` — one-shot helper that returns a final answer plus
24
+ cited sources without wiring a retriever or agent.
25
+ - Typed exceptions: `QuelvioError`, `QuelvioAuthError`, `QuelvioBadRequestError`,
26
+ `QuelvioNotFoundError`, `QuelvioRateLimitError`, `QuelvioServerError`,
27
+ `QuelvioTimeoutError`, `QuelvioNetworkError`.
28
+ - API key resolution from the `apiKey` constructor argument or the
29
+ `QUELVIO_API_KEY` environment variable. The token is held privately
30
+ and never appears in `toString()`, `JSON.stringify()`, or any error
31
+ message.
32
+ - Configurable base URL via `baseUrl` or `QUELVIO_API_BASE`. Trailing
33
+ slashes are stripped.
34
+ - Exponential backoff with jitter for transient 5xx errors and network
35
+ timeouts. Configurable `maxRetries` (default 3).
36
+ - Dual ESM + CommonJS distribution. Compatible with `@langchain/core` 0.3.x.
37
+
38
+ [0.1.0]: https://github.com/Quelvio/quelvio-langchain-js/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Quelvio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,299 @@
1
+ # @quelvio/langchain
2
+
3
+ > Quelvio for LangChain.js — your company's brain as a LangChain tool and retriever.
4
+
5
+ `@quelvio/langchain` is the official TypeScript / JavaScript integration
6
+ that plugs Quelvio's enterprise knowledge API into
7
+ [LangChain.js](https://js.langchain.com). It ships two first-class
8
+ building blocks — a `Retriever` for RAG chains and a `Tool` for agents —
9
+ both wired to your organization's connected sources (Google Drive,
10
+ SharePoint, Confluence, Slack, Notion, and the rest of your content
11
+ fabric) and scoped to the running user's individual permissions.
12
+
13
+ [![npm version](https://img.shields.io/npm/v/@quelvio/langchain.svg)](https://www.npmjs.com/package/@quelvio/langchain)
14
+ [![Node.js](https://img.shields.io/node/v/@quelvio/langchain.svg)](https://www.npmjs.com/package/@quelvio/langchain)
15
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
16
+
17
+ ## Why Quelvio (and not vanilla RAG)?
18
+
19
+ A naive RAG pipeline embeds every chunk it can find and ranks by cosine
20
+ similarity. That's why most internal copilots confidently quote a
21
+ three-year-old draft. Quelvio is a managed company-brain that does the
22
+ work a generic vector store can't:
23
+
24
+ - **Authority scoring.** Every chunk is ranked by *who authored it*, *how
25
+ fresh it is*, and *how many downstream documents reference it* — not
26
+ just semantic similarity to the question.
27
+ - **Lifecycle awareness.** Drafts, deprecated docs, and superseded
28
+ decisions are demoted automatically; chunks return a `lifecycle_state`
29
+ the LLM can quote when hedging.
30
+ - **Per-employee permissioning.** Every query is scoped to the running
31
+ user's identity. Results never include documents the user can't
32
+ already read in the source system (Drive ACLs, Confluence space
33
+ restrictions, SharePoint groups).
34
+ - **Synthesized answers with citations.** The API returns a final answer
35
+ *plus* the chunks that informed it, so your agent can hand the user a
36
+ link to the source of truth, not a hallucination.
37
+
38
+ ## Install
39
+
40
+ ```bash
41
+ npm install @quelvio/langchain @langchain/core
42
+ # or
43
+ pnpm add @quelvio/langchain @langchain/core
44
+ # or
45
+ yarn add @quelvio/langchain @langchain/core
46
+ ```
47
+
48
+ Requires Node.js 20+ and `@langchain/core` 0.3.x as a peer dependency.
49
+
50
+ ## Quickstart
51
+
52
+ ### As a retriever (RAG chain)
53
+
54
+ ```ts
55
+ import { QuelvioRetriever } from '@quelvio/langchain';
56
+
57
+ const retriever = new QuelvioRetriever({ apiKey: 'qlv_pat_...' }); // or set QUELVIO_API_KEY
58
+ const docs = await retriever.invoke("what's our refund policy?");
59
+
60
+ for (const d of docs) {
61
+ console.log(`${d.metadata.title} (authority=${d.metadata.authority_score ?? '—'})`);
62
+ console.log(d.pageContent.slice(0, 200));
63
+ console.log('---');
64
+ }
65
+ ```
66
+
67
+ Each returned `Document` carries the chunk's `source_url`,
68
+ `authority_score`, `taxonomy_domain`, `chunk_id`, and (when present) the
69
+ author's name, email, and department on `metadata`.
70
+
71
+ ### As an agent tool
72
+
73
+ ```ts
74
+ import { ChatAnthropic } from '@langchain/anthropic';
75
+ import { AgentExecutor, createToolCallingAgent } from 'langchain/agents';
76
+ import { ChatPromptTemplate } from '@langchain/core/prompts';
77
+ import { QuelvioTool } from '@quelvio/langchain';
78
+
79
+ const llm = new ChatAnthropic({ model: 'claude-sonnet-4-6' });
80
+ const tools = [new QuelvioTool({ apiKey: 'qlv_pat_...' })];
81
+
82
+ const prompt = ChatPromptTemplate.fromMessages([
83
+ [
84
+ 'system',
85
+ 'You are a helpful assistant. Use the quelvio_query tool whenever the user asks ' +
86
+ 'about internal company information.',
87
+ ],
88
+ ['human', '{input}'],
89
+ ['placeholder', '{agent_scratchpad}'],
90
+ ]);
91
+
92
+ const agent = await createToolCallingAgent({ llm, tools, prompt });
93
+ const executor = new AgentExecutor({ agent, tools });
94
+
95
+ const { output } = await executor.invoke({ input: "What's our parental leave policy?" });
96
+ console.log(output);
97
+ ```
98
+
99
+ The tool's name is `quelvio_query` and its schema accepts `question`
100
+ (required) plus optional `mode` (`fast` | `standard` | `deep`),
101
+ `max_sources` (1–50), and `domain` (taxonomy domain filter).
102
+
103
+ ### One-shot synthesis
104
+
105
+ For the simplest case — single answer, no chain, no agent:
106
+
107
+ ```ts
108
+ import { synthesizeAnswer } from '@quelvio/langchain';
109
+
110
+ const result = await synthesizeAnswer('what is our deployment process?');
111
+ console.log(result.answer);
112
+ for (const source of result.sources) {
113
+ console.log(` • ${source.title} → ${source.source_url}`);
114
+ }
115
+ ```
116
+
117
+ ## Authentication
118
+
119
+ `@quelvio/langchain` resolves a bearer token from the first non-empty
120
+ source, in order:
121
+
122
+ | Precedence | Source | Notes |
123
+ | ---------- | ------------------------------- | ---------------------------------------------------- |
124
+ | 1 | `apiKey: '…'` constructor arg | Highest priority; never persisted, never logged. |
125
+ | 2 | `QUELVIO_API_KEY` env var | Best for CI, notebooks, and one-off scripts. |
126
+
127
+ Three token types are accepted — the wire format is identical, so the
128
+ library does not need to know which kind you provided:
129
+
130
+ - **Personal Access Token (PAT).** Long-lived bearer tied to a human
131
+ user. Generate at <https://enterprise.quelvio.com/account> → *Personal
132
+ API Keys* → *Create token*. Best for ad-hoc use and CI.
133
+ - **OAuth access token.** Short-lived token from the device-code flow
134
+ (`quelvio login` in the [CLI](https://github.com/Quelvio/quelvio-cli)).
135
+ - **Service Account key.** Long-lived, machine-scoped. Generate at
136
+ *Settings* → *Service Accounts*. Best for production agents.
137
+
138
+ The token is held privately on the client (via a `#private` field and a
139
+ closure); it never appears in `toString()`, `JSON.stringify()`, or any
140
+ error message emitted by this library.
141
+
142
+ ## Configuration
143
+
144
+ | Constructor arg / env var | Default | Purpose |
145
+ | ------------------------------- | ----------------------------- | ------------------------------------------------------- |
146
+ | `apiKey` / `QUELVIO_API_KEY` | *(required)* | Bearer token (PAT, OAuth, or Service Account). |
147
+ | `baseUrl` / `QUELVIO_API_BASE` | `https://api.quelvio.com` | API base — point at `api-dev` for staging. |
148
+ | `timeoutMs` | `30000` | Per-request HTTP timeout in milliseconds. |
149
+ | `maxRetries` | `3` | Retries for transient 5xx / network errors. |
150
+ | `limit` (retriever) / `defaultMaxSources` (tool) | `5` | Max chunks returned per query (1–50). |
151
+ | `mode` / `defaultMode` | `'standard'` | `fast` / `standard` / `deep`. |
152
+ | `domainFilter` (retriever) / `domain` (tool) | `null` | Restrict to one taxonomy domain. |
153
+
154
+ ## Examples
155
+
156
+ ### 1. Simple Q&A with citations
157
+
158
+ ```ts
159
+ import { QuelvioRetriever } from '@quelvio/langchain';
160
+
161
+ const retriever = new QuelvioRetriever(); // reads QUELVIO_API_KEY
162
+
163
+ const docs = await retriever.invoke('how do we handle on-call escalations?');
164
+ for (const d of docs) {
165
+ const title = d.metadata.title;
166
+ const url = d.metadata.source_url ?? '(no link)';
167
+ const authority = d.metadata.authority_score ?? '—';
168
+ console.log(`[authority ${authority}] ${title}`);
169
+ console.log(` ${url}`);
170
+ console.log(` ${d.pageContent.slice(0, 160)}\n`);
171
+ }
172
+ ```
173
+
174
+ ### 2. Agent that combines Quelvio + web search
175
+
176
+ ```ts
177
+ import { ChatAnthropic } from '@langchain/anthropic';
178
+ import { AgentExecutor, createToolCallingAgent } from 'langchain/agents';
179
+ import { ChatPromptTemplate } from '@langchain/core/prompts';
180
+ import { DynamicStructuredTool } from '@langchain/core/tools';
181
+ import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
182
+ import { z } from 'zod';
183
+ import { QuelvioTool } from '@quelvio/langchain';
184
+
185
+ const calculator = new DynamicStructuredTool({
186
+ name: 'calculator',
187
+ description: 'Evaluate a simple arithmetic expression. Supports + - * / ( ).',
188
+ schema: z.object({ expression: z.string() }),
189
+ func: async ({ expression }) => {
190
+ // Tiny safe evaluator — only digits, whitespace, and arithmetic operators.
191
+ if (!/^[\d+\-*/().\s]+$/.test(expression)) throw new Error('unsupported chars');
192
+ // eslint-disable-next-line no-new-func
193
+ const result = Function(`"use strict"; return (${expression});`)();
194
+ return String(result);
195
+ },
196
+ });
197
+
198
+ const tools = [new QuelvioTool(), new TavilySearchResults({ maxResults: 3 }), calculator];
199
+
200
+ const llm = new ChatAnthropic({ model: 'claude-sonnet-4-6' });
201
+ const prompt = ChatPromptTemplate.fromMessages([
202
+ [
203
+ 'system',
204
+ 'Use quelvio_query for anything about THIS company. Use the web search for ' +
205
+ 'external/public information. Use the calculator for math. Always cite ' +
206
+ 'Quelvio sources by URL.',
207
+ ],
208
+ ['human', '{input}'],
209
+ ['placeholder', '{agent_scratchpad}'],
210
+ ]);
211
+
212
+ const agent = await createToolCallingAgent({ llm, tools, prompt });
213
+ const executor = new AgentExecutor({ agent, tools, verbose: true });
214
+
215
+ const { output } = await executor.invoke({
216
+ input:
217
+ 'How does our refund window compare to the industry standard, and how many ' +
218
+ 'refunds did we process last quarter?',
219
+ });
220
+ console.log(output);
221
+ ```
222
+
223
+ ### 3. RAG chain with Quelvio as the retriever
224
+
225
+ ```ts
226
+ import { ChatAnthropic } from '@langchain/anthropic';
227
+ import { StringOutputParser } from '@langchain/core/output_parsers';
228
+ import { ChatPromptTemplate } from '@langchain/core/prompts';
229
+ import { RunnablePassthrough, RunnableSequence } from '@langchain/core/runnables';
230
+ import type { Document } from '@langchain/core/documents';
231
+ import { QuelvioRetriever } from '@quelvio/langchain';
232
+
233
+ const retriever = new QuelvioRetriever({ mode: 'deep', limit: 8 });
234
+
235
+ const prompt = ChatPromptTemplate.fromTemplate(
236
+ "Answer the user's question using ONLY the context below. After your " +
237
+ 'answer, list the source URLs you used.\n\n' +
238
+ 'Context:\n{context}\n\n' +
239
+ 'Question: {question}',
240
+ );
241
+
242
+ const formatDocs = (docs: Document[]): string =>
243
+ docs
244
+ .map((d) => `[${d.metadata.title} — ${d.metadata.source_url ?? '(no url)'}]\n${d.pageContent}`)
245
+ .join('\n\n');
246
+
247
+ const llm = new ChatAnthropic({ model: 'claude-sonnet-4-6' });
248
+
249
+ const chain = RunnableSequence.from([
250
+ {
251
+ context: async (input: string) => formatDocs(await retriever.invoke(input)),
252
+ question: new RunnablePassthrough(),
253
+ },
254
+ prompt,
255
+ llm,
256
+ new StringOutputParser(),
257
+ ]);
258
+
259
+ console.log(await chain.invoke('Summarize our Q4 OKR review decisions.'));
260
+ ```
261
+
262
+ ## Related packages
263
+
264
+ - **[`@quelvio/cli`](https://github.com/Quelvio/quelvio-cli)** — query
265
+ the brain from your terminal, scriptable in CI, JSON output.
266
+ - **[`quelvio-langchain` (Python)](https://pypi.org/project/quelvio-langchain/)** —
267
+ the Python sibling of this package. Identical surface area, same API.
268
+ - **[`@quelvio/mcp-server`](https://github.com/Quelvio/quelvio-mcp-server)** —
269
+ use Quelvio from any Model Context Protocol client (Claude Desktop,
270
+ Cursor, VS Code, etc.).
271
+ - **[Quelvio docs](https://docs.quelvio.com)** — concepts, API reference,
272
+ source connectors.
273
+
274
+ ## Development
275
+
276
+ ```bash
277
+ git clone https://github.com/Quelvio/quelvio-langchain-js
278
+ cd quelvio-langchain-js
279
+ pnpm install
280
+ pnpm test
281
+ ```
282
+
283
+ Build, type-check, lint:
284
+
285
+ ```bash
286
+ pnpm build
287
+ pnpm typecheck
288
+ pnpm lint
289
+ ```
290
+
291
+ ## Contributing
292
+
293
+ Issues and pull requests welcome at
294
+ <https://github.com/Quelvio/quelvio-langchain-js>. Please run `pnpm
295
+ lint`, `pnpm typecheck`, and `pnpm test` before opening a PR.
296
+
297
+ ## License
298
+
299
+ MIT — see [LICENSE](./LICENSE).