@ragieai/skills 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/.claude-plugin/plugin.json +8 -0
- package/.mcp.json +11 -0
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/index.cjs +55 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +26 -0
- package/package.json +43 -0
- package/skills/ragie/SKILL.md +50 -0
- package/skills/ragie/references/api-reference.md +203 -0
- package/skills/ragie/references/ingestion.md +127 -0
- package/skills/ragie/references/mcp.md +84 -0
- package/skills/ragie/references/metadata-filtering.md +149 -0
- package/skills/ragie/references/partitions.md +85 -0
- package/skills/ragie/references/python.md +232 -0
- package/skills/ragie/references/quickstart.md +69 -0
- package/skills/ragie/references/rag-patterns.md +160 -0
- package/skills/ragie/references/retrieval.md +77 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Ragie MCP Server
|
|
2
|
+
|
|
3
|
+
The Ragie MCP server exposes a `retrieve` tool scoped to a specific partition. Use it to search your knowledge base interactively from Claude Code — without writing code.
|
|
4
|
+
|
|
5
|
+
## URL Pattern
|
|
6
|
+
|
|
7
|
+
Each partition gets its own endpoint:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
https://api.ragie.ai/mcp/{partition}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Examples:
|
|
14
|
+
- `https://api.ragie.ai/mcp/debug` → `debug` partition
|
|
15
|
+
- `https://api.ragie.ai/mcp/production` → `production` partition
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
### Via this plugin (recommended)
|
|
20
|
+
|
|
21
|
+
Set environment variables before starting Claude Code:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
export RAGIE_API_KEY=ragie_...
|
|
25
|
+
export RAGIE_PARTITION=your-partition-name
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The plugin's `.mcp.json` handles the rest automatically.
|
|
29
|
+
|
|
30
|
+
### Manual project config
|
|
31
|
+
|
|
32
|
+
Add to your project's `.mcp.json`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"ragie": {
|
|
38
|
+
"type": "http",
|
|
39
|
+
"url": "https://api.ragie.ai/mcp/your-partition",
|
|
40
|
+
"headers": {
|
|
41
|
+
"Authorization": "Bearer ${RAGIE_API_KEY}"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Multiple partitions
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"ragie-main": {
|
|
54
|
+
"type": "http",
|
|
55
|
+
"url": "https://api.ragie.ai/mcp/main",
|
|
56
|
+
"headers": { "Authorization": "Bearer ${RAGIE_API_KEY}" }
|
|
57
|
+
},
|
|
58
|
+
"ragie-debug": {
|
|
59
|
+
"type": "http",
|
|
60
|
+
"url": "https://api.ragie.ai/mcp/debug",
|
|
61
|
+
"headers": { "Authorization": "Bearer ${RAGIE_API_KEY}" }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## The `retrieve` Tool
|
|
68
|
+
|
|
69
|
+
Once the MCP server is connected, Claude can call `retrieve` directly.
|
|
70
|
+
|
|
71
|
+
Example prompts:
|
|
72
|
+
- *"Search my Ragie knowledge base for rate limit documentation"*
|
|
73
|
+
- *"What does Ragie have indexed about authentication?"*
|
|
74
|
+
- *"Retrieve the top 5 chunks about error handling and show me the scores"*
|
|
75
|
+
|
|
76
|
+
## When to Use MCP vs SDK
|
|
77
|
+
|
|
78
|
+
| Situation | Use |
|
|
79
|
+
|-----------|-----|
|
|
80
|
+
| Testing retrieval quality during development | MCP |
|
|
81
|
+
| Exploring what's indexed in a partition | MCP |
|
|
82
|
+
| Debugging poor search results | MCP |
|
|
83
|
+
| Production application code | SDK (`client.retrievals.retrieve()`) |
|
|
84
|
+
| Ingesting documents | SDK (MCP only exposes `retrieve`) |
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Ragie Metadata Filtering
|
|
2
|
+
|
|
3
|
+
Metadata is arbitrary key-value pairs attached to documents at ingest time. Use them to filter retrieval to a relevant subset of documents.
|
|
4
|
+
|
|
5
|
+
> Python user? See `references/python.md` for Python equivalents.
|
|
6
|
+
|
|
7
|
+
## Attaching Metadata on Ingest
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
await client.documents.createRaw({
|
|
11
|
+
content: contentBuffer,
|
|
12
|
+
contentType: "application/pdf",
|
|
13
|
+
name: "API Docs v3",
|
|
14
|
+
metadata: {
|
|
15
|
+
product: "api",
|
|
16
|
+
version: 3, // numbers are allowed
|
|
17
|
+
active: true, // booleans are allowed
|
|
18
|
+
tags: ["public", "stable"], // list of strings is allowed
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Metadata values can be: **strings**, **numbers** (stored as 64-bit float), **booleans**, or **lists of strings**. Keys set to `null` in a patch operation are deleted.
|
|
24
|
+
|
|
25
|
+
## Filtering at Retrieval
|
|
26
|
+
|
|
27
|
+
### Simple equality (shorthand)
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
const results = await client.retrievals.retrieve({
|
|
31
|
+
query: "rate limits",
|
|
32
|
+
filter: {
|
|
33
|
+
product: "api",
|
|
34
|
+
version: 3,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
All keys in a plain object filter must match — it's an implicit `$and` of equality checks.
|
|
40
|
+
|
|
41
|
+
### Filter operators
|
|
42
|
+
|
|
43
|
+
For range, set membership, and logical combinations use explicit operators:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Greater than / less than
|
|
47
|
+
filter: { year: { $gt: 2022 } }
|
|
48
|
+
filter: { score: { $gte: 0.8, $lte: 1.0 } }
|
|
49
|
+
|
|
50
|
+
// Not equal
|
|
51
|
+
filter: { status: { $ne: "draft" } }
|
|
52
|
+
|
|
53
|
+
// In / not in a set
|
|
54
|
+
filter: { lang: { $in: ["en", "fr"] } }
|
|
55
|
+
filter: { env: { $nin: ["test", "staging"] } }
|
|
56
|
+
|
|
57
|
+
// Logical OR
|
|
58
|
+
filter: {
|
|
59
|
+
$or: [
|
|
60
|
+
{ product: "api" },
|
|
61
|
+
{ product: "dashboard" }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Logical AND with sub-conditions
|
|
66
|
+
filter: {
|
|
67
|
+
$and: [
|
|
68
|
+
{ product: "api" },
|
|
69
|
+
{ version: { $gte: 2 } }
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Operator | Purpose | Supported types |
|
|
75
|
+
|----------|---------|-----------------|
|
|
76
|
+
| `$eq` | Equal | number, string, boolean |
|
|
77
|
+
| `$ne` | Not equal | number, string, boolean |
|
|
78
|
+
| `$gt` | Greater than | number only |
|
|
79
|
+
| `$gte` | Greater than or equal | number only |
|
|
80
|
+
| `$lt` | Less than | number only |
|
|
81
|
+
| `$lte` | Less than or equal | number only |
|
|
82
|
+
| `$in` | Value in array | string or number |
|
|
83
|
+
| `$nin` | Value not in array | string or number |
|
|
84
|
+
| `$and` | Logical AND | compound |
|
|
85
|
+
| `$or` | Logical OR | compound |
|
|
86
|
+
|
|
87
|
+
## Updating Metadata
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Partial update — only specified keys are changed; keys set to null are deleted
|
|
91
|
+
await client.documents.patchMetadata({
|
|
92
|
+
documentId: docId,
|
|
93
|
+
patchDocumentMetadataParams: { metadata: { reviewed: "true", version: 4 } },
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Common Patterns
|
|
98
|
+
|
|
99
|
+
### Product + version scoping
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// Tag by product and version on ingest
|
|
103
|
+
await client.documents.createDocumentFromUrl({
|
|
104
|
+
url,
|
|
105
|
+
metadata: { product: "dashboard", version: 4 },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Query only that version's docs
|
|
109
|
+
const results = await client.retrievals.retrieve({
|
|
110
|
+
query: "usage metrics",
|
|
111
|
+
filter: { product: "dashboard", version: 4 },
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Language filtering
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
metadata: { lang: "fr" }
|
|
119
|
+
filter: { lang: "fr" }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Environment separation
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
metadata: { env: "staging" }
|
|
126
|
+
filter: { env: "staging" }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Date range filtering
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Store dates as Unix timestamps (numbers)
|
|
133
|
+
metadata: { published_at: 1704067200 }
|
|
134
|
+
|
|
135
|
+
// Query documents published after 2024-01-01
|
|
136
|
+
filter: { published_at: { $gt: 1704067200 } }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Metadata vs Partitions
|
|
140
|
+
|
|
141
|
+
Metadata filtering and partitions serve different purposes — see `partitions.md` for the comparison.
|
|
142
|
+
|
|
143
|
+
## Gotchas
|
|
144
|
+
|
|
145
|
+
- Metadata values may be strings, numbers, booleans, or lists of strings. Numbers do **not** need to be stringified — use native numbers for range operators to work correctly.
|
|
146
|
+
- Filtering on a key that doesn't exist on a document excludes that document from results.
|
|
147
|
+
- Reserved keys (will cause a 422 error): `document_id`, `document_type`, `document_source`, `document_name`, `document_uploaded_at`. Keys beginning with `_` are also reserved.
|
|
148
|
+
- Metadata filtering is a **pre-filter**: Ragie guarantees `top_k` results if they exist after filtering.
|
|
149
|
+
- Up to 1000 total metadata values per document (each item in an array counts toward the total).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Ragie Partitions
|
|
2
|
+
|
|
3
|
+
Partitions are logical namespaces within a single Ragie account. Use them to isolate documents by tenant, environment, project, or any other boundary.
|
|
4
|
+
|
|
5
|
+
> Python user? See `references/python.md` for Python equivalents.
|
|
6
|
+
|
|
7
|
+
## Basic Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// Ingest into a partition
|
|
11
|
+
await client.documents.createDocumentFromUrl({
|
|
12
|
+
url: "https://example.com/doc",
|
|
13
|
+
partition: "tenant-42",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Retrieve from that partition only
|
|
17
|
+
const results = await client.retrievals.retrieve({
|
|
18
|
+
query: "pricing",
|
|
19
|
+
partition: "tenant-42",
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Multi-Tenant Pattern
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
function ingestForTenant(client: Ragie, tenantId: string, url: string) {
|
|
27
|
+
return client.documents.createDocumentFromUrl({
|
|
28
|
+
url,
|
|
29
|
+
partition: `tenant-${tenantId}`,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function retrieveForTenant(client: Ragie, tenantId: string, query: string) {
|
|
34
|
+
return client.retrievals.retrieve({
|
|
35
|
+
query,
|
|
36
|
+
partition: `tenant-${tenantId}`,
|
|
37
|
+
rerank: true,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Partition Management
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// List all partitions (returns a PageIterator — async iterable)
|
|
46
|
+
for await (const page of client.partitions.list()) {
|
|
47
|
+
for (const partition of page.result.partitions) {
|
|
48
|
+
console.log(partition.id, partition.name);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Create a partition explicitly
|
|
53
|
+
await client.partitions.create({ name: "tenant-42", description: "optional" });
|
|
54
|
+
// Note: partitions are also created implicitly on first document ingest
|
|
55
|
+
|
|
56
|
+
// Get partition details and usage metrics (document count, pages processed)
|
|
57
|
+
const detail = await client.partitions.get({ partitionId: "tenant-42" });
|
|
58
|
+
|
|
59
|
+
// Set page limits (triggers webhook when limit is exceeded)
|
|
60
|
+
await client.partitions.setLimits({
|
|
61
|
+
partitionId: "tenant-42",
|
|
62
|
+
partitionLimitParams: { pagesHostedLimitMonthly: 1000 },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Delete a partition and all its documents
|
|
66
|
+
await client.partitions.delete({ partitionId: "tenant-42" });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Partitions vs Metadata Filters
|
|
70
|
+
|
|
71
|
+
| | Partitions | Metadata filters |
|
|
72
|
+
|-|------------|-----------------|
|
|
73
|
+
| Isolation | Hard — separate index | Soft — same index, filtered at query time |
|
|
74
|
+
| Use for | Multi-tenancy, environments | Document categories, versions, tags |
|
|
75
|
+
| Performance | Fastest (no cross-partition scan) | Slightly slower on large corpora |
|
|
76
|
+
| Deletion | Delete whole partition at once | Must delete documents individually |
|
|
77
|
+
|
|
78
|
+
Use partitions for tenant isolation. Use metadata filters for sub-categorization within a tenant. See `metadata-filtering.md`.
|
|
79
|
+
|
|
80
|
+
## Gotchas
|
|
81
|
+
|
|
82
|
+
- Omitting `partition` on ingest places the document in the default partition.
|
|
83
|
+
- Omitting `partition` on retrieval searches **only** the default partition — not all partitions.
|
|
84
|
+
- Partition names are case-sensitive. `Tenant-42` and `tenant-42` are different partitions.
|
|
85
|
+
- Deleting a partition is irreversible and deletes all documents within it.
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Ragie Python SDK
|
|
2
|
+
|
|
3
|
+
The Python SDK mirrors the TypeScript SDK conceptually — same methods, snake_case naming.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install ragie
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import os
|
|
11
|
+
from ragie import Ragie
|
|
12
|
+
|
|
13
|
+
client = Ragie(auth=os.environ["RAGIE_API_KEY"])
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Ingestion
|
|
17
|
+
|
|
18
|
+
The Python SDK has three distinct methods depending on the source. Using the wrong one is a common source of errors.
|
|
19
|
+
|
|
20
|
+
| Source | Method | Request class |
|
|
21
|
+
|--------|--------|---------------|
|
|
22
|
+
| File upload (all file types) | `documents.create()` | `ragie.CreateDocumentParams` + `ragie.File` |
|
|
23
|
+
| In-memory data (text/JSON) | `documents.create_raw()` | `ragie.CreateDocumentRawParams` |
|
|
24
|
+
| URL | `documents.create_document_from_url()` | `ragie.CreateDocumentFromURLParams` |
|
|
25
|
+
|
|
26
|
+
**Prefer `documents.create()`** when uploading files from disk, as it supports all file types including binary formats. **Prefer `create_raw()`** when your data is already in memory as a string or dict — it is simpler and avoids unnecessary file wrapping, but only handles text and JSON.
|
|
27
|
+
|
|
28
|
+
### From a file
|
|
29
|
+
|
|
30
|
+
Use `documents.create()` with `ragie.File`. This is the only method that supports all file types including binary formats (PDF, DOCX, images, etc.).
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import ragie
|
|
34
|
+
|
|
35
|
+
with open("doc.pdf", "rb") as f:
|
|
36
|
+
doc = client.documents.create(
|
|
37
|
+
request=ragie.CreateDocumentParams(
|
|
38
|
+
file=ragie.File(
|
|
39
|
+
file_name="doc.pdf",
|
|
40
|
+
content=f.read(),
|
|
41
|
+
content_type="application/pdf",
|
|
42
|
+
),
|
|
43
|
+
name="Q4 Report",
|
|
44
|
+
partition="tenant-42",
|
|
45
|
+
metadata={"type": "report", "year": "2024"},
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### From a URL
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import ragie
|
|
54
|
+
|
|
55
|
+
doc = client.documents.create_document_from_url(
|
|
56
|
+
request=ragie.CreateDocumentFromURLParams(
|
|
57
|
+
url="https://example.com/report.pdf",
|
|
58
|
+
name="Q4 Report",
|
|
59
|
+
partition="tenant-42",
|
|
60
|
+
metadata={"type": "report", "year": "2024"},
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### From in-memory data (raw text or JSON)
|
|
66
|
+
|
|
67
|
+
**Preferred when your data is already in memory** (e.g., scraped content, generated text, API responses). Accepts strings and dicts — not bytes.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import ragie
|
|
71
|
+
|
|
72
|
+
doc = client.documents.create_raw(
|
|
73
|
+
request=ragie.CreateDocumentRawParams(
|
|
74
|
+
data="Your text content here...", # str or dict
|
|
75
|
+
name="my-note",
|
|
76
|
+
partition="tenant-42",
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Polling for Readiness
|
|
82
|
+
|
|
83
|
+
`documents.get()` returns `DocumentGet`, which is a **different type** from the `Document` returned by `create()` and `create_document_from_url()`. Both have `.status` and `.id`, but annotate them separately if you need type safety.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import time
|
|
87
|
+
from ragie.models import DocumentGet
|
|
88
|
+
|
|
89
|
+
def wait_for_ready(client, doc_id: str, timeout: int = 120) -> None:
|
|
90
|
+
start = time.time()
|
|
91
|
+
while time.time() - start < timeout:
|
|
92
|
+
doc: DocumentGet = client.documents.get(document_id=doc_id)
|
|
93
|
+
if doc.status == "ready":
|
|
94
|
+
return
|
|
95
|
+
if doc.status == "failed":
|
|
96
|
+
raise RuntimeError(f"Document {doc_id} failed")
|
|
97
|
+
time.sleep(3)
|
|
98
|
+
raise TimeoutError(f"Document {doc_id} not ready after {timeout}s")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Retrieval
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import ragie
|
|
105
|
+
|
|
106
|
+
results = client.retrievals.retrieve(
|
|
107
|
+
request=ragie.RetrieveParams(
|
|
108
|
+
query="your question",
|
|
109
|
+
top_k=8,
|
|
110
|
+
rerank=True,
|
|
111
|
+
partition="tenant-42",
|
|
112
|
+
filter={"product": "api", "version": "v3"},
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
for chunk in results.scored_chunks:
|
|
117
|
+
print(chunk.text, chunk.score)
|
|
118
|
+
# also: chunk.document_id, chunk.document_name, chunk.document_metadata
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Document Management
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import ragie
|
|
125
|
+
from ragie.models import DocumentGet
|
|
126
|
+
|
|
127
|
+
# Get a document — returns DocumentGet, not Document
|
|
128
|
+
doc: DocumentGet = client.documents.get(document_id=doc_id)
|
|
129
|
+
|
|
130
|
+
# List documents — use ListDocumentsRequest, not keyword args
|
|
131
|
+
# .result is a DocumentList object — access .result.documents for the list
|
|
132
|
+
page = client.documents.list(
|
|
133
|
+
request=ragie.ListDocumentsRequest(partition="tenant-42", page_size=50)
|
|
134
|
+
)
|
|
135
|
+
docs = page.result.documents
|
|
136
|
+
|
|
137
|
+
# Paginate
|
|
138
|
+
while page is not None:
|
|
139
|
+
for doc in page.result.documents:
|
|
140
|
+
print(doc.id, doc.name)
|
|
141
|
+
page = page.next() # .next() returns the next page or None
|
|
142
|
+
|
|
143
|
+
# Update metadata (partial update — keyword args are required)
|
|
144
|
+
client.documents.patch_metadata(
|
|
145
|
+
document_id=doc_id,
|
|
146
|
+
patch_document_metadata_params=ragie.PatchDocumentMetadataParams(
|
|
147
|
+
metadata={"reviewed": "true", "version": 4}
|
|
148
|
+
),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Delete a document (keyword args are required)
|
|
152
|
+
client.documents.delete(document_id=doc_id)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Bulk Ingestion (asyncio)
|
|
156
|
+
|
|
157
|
+
The Python SDK has no `AsyncRagie` class. Use `async with Ragie(...) as client:` and call the `_async`-suffixed method variants.
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
import asyncio
|
|
161
|
+
import os
|
|
162
|
+
import ragie
|
|
163
|
+
from ragie import Ragie
|
|
164
|
+
|
|
165
|
+
async def bulk_ingest(urls: list[str], partition: str):
|
|
166
|
+
async with Ragie(auth=os.environ["RAGIE_API_KEY"]) as client:
|
|
167
|
+
tasks = [
|
|
168
|
+
client.documents.create_document_from_url_async(
|
|
169
|
+
request=ragie.CreateDocumentFromURLParams(url=url, partition=partition)
|
|
170
|
+
)
|
|
171
|
+
for url in urls
|
|
172
|
+
]
|
|
173
|
+
return await asyncio.gather(*tasks)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## RAG Response
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import anthropic
|
|
180
|
+
import ragie
|
|
181
|
+
|
|
182
|
+
ragie_client = Ragie(auth=os.environ["RAGIE_API_KEY"])
|
|
183
|
+
claude = anthropic.Anthropic()
|
|
184
|
+
|
|
185
|
+
def answer(question: str) -> str:
|
|
186
|
+
chunks = ragie_client.retrievals.retrieve(
|
|
187
|
+
request=ragie.RetrieveParams(query=question, rerank=True, top_k=6)
|
|
188
|
+
)
|
|
189
|
+
context = "\n\n".join(c.text for c in chunks.scored_chunks)
|
|
190
|
+
msg = claude.messages.create(
|
|
191
|
+
model="claude-sonnet-4-6",
|
|
192
|
+
max_tokens=1024,
|
|
193
|
+
messages=[{"role": "user", "content": f"Context:\n{context}\n\nQuestion: {question}"}],
|
|
194
|
+
)
|
|
195
|
+
return msg.content[0].text
|
|
196
|
+
|
|
197
|
+
def stream_answer(question: str) -> None:
|
|
198
|
+
chunks = ragie_client.retrievals.retrieve(
|
|
199
|
+
request=ragie.RetrieveParams(query=question, rerank=True, top_k=6)
|
|
200
|
+
)
|
|
201
|
+
context = "\n\n".join(c.text for c in chunks.scored_chunks)
|
|
202
|
+
with claude.messages.stream(
|
|
203
|
+
model="claude-sonnet-4-6",
|
|
204
|
+
max_tokens=1024,
|
|
205
|
+
messages=[{"role": "user", "content": f"Context:\n{context}\n\nQuestion: {question}"}],
|
|
206
|
+
) as stream:
|
|
207
|
+
for text in stream.text_stream:
|
|
208
|
+
print(text, end="", flush=True)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Naming Differences vs TypeScript
|
|
212
|
+
|
|
213
|
+
| TypeScript | Python |
|
|
214
|
+
|------------|--------|
|
|
215
|
+
| `createDocumentFromUrl()` | `create_document_from_url()` |
|
|
216
|
+
| `createRaw()` | `create_raw()` |
|
|
217
|
+
| `topK` | `top_k` |
|
|
218
|
+
| `scoredChunks` | `scored_chunks` |
|
|
219
|
+
| `documentId` | `document_id` |
|
|
220
|
+
| `documentName` | `document_name` |
|
|
221
|
+
| `contentType` | `content_type` |
|
|
222
|
+
|
|
223
|
+
## Gotchas
|
|
224
|
+
|
|
225
|
+
- **`ragie.File`, not `ragie.FileUpload`** — the file wrapper class is `ragie.File`. `FileUpload` does not exist.
|
|
226
|
+
- **`ragie.ListDocumentsRequest`, not `ragie.ListDocumentsParams`** — always use the `Request` suffix for list operations.
|
|
227
|
+
- **Prefer `create_raw()` for in-memory data** — it's simpler when you already have a string or dict. **Prefer `create()` for file uploads** — it supports all file types. `create_raw()` only handles text and JSON; binary files (PDF, DOCX, etc.) must use `create()` with `ragie.File`.
|
|
228
|
+
- **`documents.list()` response requires `.result.documents`** — `.result` is a `DocumentList` object, not a list. Access `.result.documents` to get the actual `List[Document]`. Iterating `.result` directly yields Pydantic field tuples, not documents.
|
|
229
|
+
- **`documents.get()` returns `DocumentGet`, not `Document`** — these are distinct types. Import `from ragie.models import DocumentGet` and annotate accordingly. Do not assign a `DocumentGet` to a variable typed as `Document`.
|
|
230
|
+
- **Pagination via `.next()`** — call `page.next()` to get the next `ListDocumentsResponse`, or `None` if there are no more pages.
|
|
231
|
+
- **Keyword-only arguments** — `delete`, `patch_metadata`, and similar methods use keyword-only args (`*` in signature). Always pass `document_id=doc_id`, never positionally.
|
|
232
|
+
- **No `AsyncRagie` class** — there is only `Ragie`. For async usage, open it as a context manager (`async with Ragie(...) as client:`) and call `_async`-suffixed methods: `create_async()`, `create_document_from_url_async()`, `create_raw_async()`, etc.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Ragie Quickstart
|
|
2
|
+
|
|
3
|
+
> Python user? See `references/python.md` for Python equivalents.
|
|
4
|
+
|
|
5
|
+
## Get an API Key
|
|
6
|
+
|
|
7
|
+
Sign up at [ragie.ai](https://ragie.ai) and copy the API key from the dashboard.
|
|
8
|
+
|
|
9
|
+
## Install the SDK
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install ragie
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Ingest a Document
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { Ragie } from "ragie";
|
|
19
|
+
import { openAsBlob } from "fs";
|
|
20
|
+
|
|
21
|
+
const client = new Ragie({ auth: process.env.RAGIE_API_KEY });
|
|
22
|
+
|
|
23
|
+
// From a file (supports all file types: PDF, DOCX, images, …)
|
|
24
|
+
const doc = await client.documents.create({
|
|
25
|
+
file: await openAsBlob("report.pdf"),
|
|
26
|
+
name: "report.pdf",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// From in-memory data (preferred when data is already a string/object)
|
|
30
|
+
const doc2 = await client.documents.createRaw({
|
|
31
|
+
data: "Your text content here...",
|
|
32
|
+
name: "my-note",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log(doc.id, doc.status); // status: "pending" → "ready"
|
|
36
|
+
// Use createRaw() for in-memory text/JSON; use create() for file uploads (all file types supported)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
See `ingestion.md` for URL ingestion, polling, webhooks, and bulk patterns.
|
|
40
|
+
|
|
41
|
+
## Retrieve (Search)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const results = await client.retrievals.retrieve({
|
|
45
|
+
query: "What are the key findings?",
|
|
46
|
+
rerank: true,
|
|
47
|
+
});
|
|
48
|
+
for (const chunk of results.scoredChunks) {
|
|
49
|
+
console.log(chunk.text, chunk.score);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Environment Setup
|
|
54
|
+
|
|
55
|
+
Always load the API key from the environment:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
export RAGIE_API_KEY=ragie_...
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { Ragie } from "ragie";
|
|
63
|
+
const client = new Ragie({ auth: process.env.RAGIE_API_KEY });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Gotchas
|
|
67
|
+
|
|
68
|
+
- Documents process **asynchronously** — `status` starts as `pending`, transitions to `ready`. Don't query before it's ready. See `ingestion.md` for polling/webhook patterns.
|
|
69
|
+
- `rerank: true` significantly improves result quality. Always enable it for generation use cases unless latency is critical.
|