@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 +38 -0
- package/LICENSE +21 -0
- package/README.md +299 -0
- package/dist/index.cjs +594 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +789 -0
- package/dist/index.d.ts +789 -0
- package/dist/index.js +564 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
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
|
+
[](https://www.npmjs.com/package/@quelvio/langchain)
|
|
14
|
+
[](https://www.npmjs.com/package/@quelvio/langchain)
|
|
15
|
+
[](./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).
|