evolink-sdk 0.1.0__tar.gz

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.
@@ -0,0 +1,48 @@
1
+ .env
2
+ .env.*
3
+ *.env
4
+ !.env.example
5
+
6
+ # Credentials and secret material
7
+ *.secret
8
+ *.secrets
9
+ *.secret.*
10
+ *.secrets.*
11
+ secret.*
12
+ secrets.*
13
+ credentials.*
14
+ secrets/
15
+ secret/
16
+ credentials/
17
+ credential/
18
+ credentials.json
19
+ credentials.yaml
20
+ credentials.yml
21
+ *-credentials.json
22
+ service-account*.json
23
+ google-credentials*.json
24
+ .npmrc
25
+ .pypirc
26
+ .netrc
27
+
28
+ # Private keys, certificates, and keystores
29
+ *.pem
30
+ *.key
31
+ *.p12
32
+ *.pfx
33
+ *.jks
34
+ *.keystore
35
+
36
+ # Local provider and tool configuration
37
+ .aws/credentials
38
+ .aws/config
39
+ .config/gcloud/application_default_credentials.json
40
+ .docker/config.json
41
+ __pycache__/
42
+ *.py[cod]
43
+ .pytest_cache/
44
+ .mypy_cache/
45
+ .ruff_cache/
46
+ .next/
47
+ node_modules/
48
+ dist/
@@ -0,0 +1,468 @@
1
+ Metadata-Version: 2.5
2
+ Name: evolink-sdk
3
+ Version: 0.1.0
4
+ Summary: Async Python SDK for the Evolink memory and RAG API
5
+ Project-URL: Documentation, https://github.com/sireto/evolink/blob/master/sdk/README.md
6
+ Project-URL: Repository, https://github.com/sireto/evolink
7
+ Author: Evolink
8
+ License: MIT
9
+ Requires-Python: >=3.12
10
+ Requires-Dist: httpx<1,>=0.27
11
+ Description-Content-Type: text/markdown
12
+
13
+ # evolink-sdk
14
+
15
+ Async Python HTTP client for the Evolink API.
16
+
17
+ This package is intentionally a remote client, not the Evolink engine. It sends HTTPS requests and
18
+ does not contain ingestion, memory, RAG, prompts, database access, provider SDKs, or LLM logic.
19
+ Use it from another product calling a deployed Evolink API.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pip install evolink-sdk
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ The SDK needs the public API URL and the API key generated from the Evolink admin dashboard:
30
+
31
+ ```env
32
+ EVOLINK_API_URL=https://sdk.evolink.example.com/api/v1
33
+ EVOLINK_API_KEY=sk_generated-from-admin-dashboard
34
+ EVOLINK_TIMEOUT=60
35
+ ```
36
+
37
+ `EVOLINK_API_KEY` is the caller-to-Evolink-API credential. It is sent as `Authorization: Bearer ...`;
38
+ it is not an OpenAI/LLM key. `LLM_API_KEY` and `OCR_API_KEY` remain server-side settings and are
39
+ never bundled into this client. Generate an `sk_...` secret key for the target workspace using the
40
+ SDK.
41
+
42
+ ## Before you use the SDK
43
+
44
+ The SDK requires:
45
+
46
+ 1. A deployed Evolink API reachable from the application, including the `/api/v1` URL prefix.
47
+ 2. An API key generated for the target workspace in the Evolink dashboard's **API Keys** section.
48
+ Copy the `sk_...` key when
49
+ it is created; the plaintext value is shown only once.
50
+
51
+ The API key is sent as `Authorization: Bearer ...`. Store it as a server-side application secret;
52
+ never expose it in browser code or commit it to source control. Python and other server-side SDK
53
+ consumers do not need CORS configuration.
54
+
55
+ The capabilities available to your application depend on how the connected Evolink deployment is
56
+ configured. For example, memory extraction and answer generation require an enabled language model,
57
+ while semantic retrieval requires embeddings. If a capability is unavailable, the API returns an
58
+ error rather than requiring additional packages in the client.
59
+
60
+ The SDK package does not start the API, create workspaces, generate keys, or contain provider
61
+ credentials. Those setup tasks are completed before configuring the client.
62
+
63
+ ## Usage
64
+
65
+ ```python
66
+ from evolink_sdk import EvolinkClient
67
+
68
+ async with EvolinkClient(
69
+ api_url="https://sdk.evolink.example.com/api/v1",
70
+ api_key="sk_generated-from-admin-dashboard",
71
+ ) as client:
72
+ document = await client.add(
73
+ content="The team standard is PostgreSQL.",
74
+ task_type="memory",
75
+ )
76
+
77
+ answer = await client.rag.query(
78
+ query="What is the team database standard?",
79
+ document_id=document["id"],
80
+ )
81
+ ```
82
+
83
+ Document ingestion supports two task types:
84
+
85
+ - `task_type="memory"` (default): extracts atomic facts, creates workspace memories, and updates profiles/graph relationships when the server LLM is configured.
86
+ - `task_type="superrag"`: extracts and chunks content for retrieval, but intentionally does not generate memories.
87
+
88
+ Memory ingestion also accepts `dreaming="dynamic"` (default) or `dreaming="instant"`.
89
+ `dynamic` gives the extractor related workspace memory context for reconsolidation and updates;
90
+ `instant` processes the document independently without previous-memory context. This option is
91
+ available on `client.add()`, `client.documents.create()`, and `client.documents.upload_file()`.
92
+
93
+ Memory extraction processes document chunks in batches of five by default. Pass `batch_size` to
94
+ `client.add()`, `client.documents.create()`, or `client.documents.upload_file()` to customize the
95
+ batch size to any positive integer. The same option is available on the stateless
96
+ `client.memories.generate()` and `client.profiles.generate()` methods.
97
+
98
+ Use the same option with `client.add()`, `client.documents.create()`, and
99
+ `client.documents.upload_file()`:
100
+
101
+ ```python
102
+ reference = await client.documents.upload_file(
103
+ file="architecture.pdf",
104
+ task_type="superrag",
105
+ )
106
+
107
+ facts = await client.add(
108
+ content="The team standard is PostgreSQL.",
109
+ task_type="memory",
110
+ )
111
+ ```
112
+
113
+ The typed SDK alias is available as `evolink_sdk.TaskType` and accepts only
114
+ `"memory"` or `"superrag"`.
115
+
116
+ Generated memories are classified as `semantic`, `episodic`, or `preference` by the configured
117
+ memory extractor. Direct memory writes can select the type explicitly:
118
+
119
+ ```python
120
+ memory = await client.memories.add(
121
+ content="The user prefers PostgreSQL.",
122
+ memory_type="preference",
123
+ )
124
+ ```
125
+
126
+ The typed SDK alias `evolink_sdk.MemoryType` accepts `"semantic"`, `"episodic"`, or
127
+ `"preference"`.
128
+
129
+ The client exposes ingestion, documents, memories, profiles, stateless memory/profile generation,
130
+ stateless embeddings and reranking, safe configuration, and RAG operations. It does not expose
131
+ workspace provisioning, admin settings, dashboards, graph administration, or API-key generation.
132
+ See the repository [SDK documentation](../docs/SDK.md) for the complete task-by-task reference.
133
+
134
+ RAG retrieval supports `search_mode="memory"` for extracted memories only,
135
+ `search_mode="document"` for original document chunks only, and
136
+ `search_mode="hybrid"` (default) for both sources:
137
+
138
+ ```python
139
+ results = await client.rag.retrieve(
140
+ query="What database does the team use?",
141
+ search_mode="memory",
142
+ rerank_limit=5,
143
+ )
144
+ answer = await client.rag.query(
145
+ query="How do I configure the database?",
146
+ search_mode="document",
147
+ )
148
+ ```
149
+
150
+ `client.config()` fetches safe published project configuration. `client.rag.query()` returns the
151
+ complete answer and retrieval evidence. The admin panel is not an SDK consumer and uses the admin
152
+ API directly.
153
+
154
+ ## Complete client reference
155
+
156
+ All methods are asynchronous and must be called with `await`.
157
+
158
+ ### Client setup
159
+
160
+ ```python
161
+ from evolink_sdk import EvolinkClient
162
+
163
+ client = EvolinkClient(
164
+ api_url="https://sdk.example.com/api/v1", # required
165
+ api_key="sk_live_...", # required
166
+ timeout=60.0, # optional seconds; default: 60
167
+ )
168
+ try:
169
+ config = await client.config()
170
+ finally:
171
+ await client.close()
172
+ ```
173
+
174
+ `EvolinkClient.from_env()` reads `EVOLINK_API_URL` (required), `EVOLINK_API_KEY` (required), and
175
+ `EVOLINK_TIMEOUT` (optional, default `60`).
176
+ The async context-manager form closes the HTTP connection automatically.
177
+
178
+ ### `client.add(...)`
179
+
180
+ Adds text or a URL as a document. The server determines whether `content` is a URL or text.
181
+
182
+ | Parameter | Required | Default | Description |
183
+ | --- | --- | --- | --- |
184
+ | `content` | Yes | — | Text or URL to ingest; must not be empty. |
185
+ | `metadata` | No | `{}` | JSON-compatible application metadata. |
186
+ | `task_type` | No | `"memory"` | `"memory"` extracts facts; `"superrag"` indexes content without creating memories. |
187
+ | `dreaming` | No | `"dynamic"` | `"dynamic"` uses related memory context; `"instant"` processes independently. |
188
+ | `batch_size` | No | `5` | Number of document chunks sent to the memory extractor per batch; must be positive. |
189
+ | `name` | No | `"content"` | Document display name. |
190
+
191
+ ```python
192
+ document = await client.add(
193
+ content="https://example.com/architecture",
194
+ name="Architecture reference",
195
+ task_type="superrag",
196
+ metadata={"source_system": "docs", "team": "platform"},
197
+ )
198
+ ```
199
+
200
+ ### `client.config`
201
+
202
+ Returns safe server configuration for a workspace, such as enabled providers and model names.
203
+ Provider credentials are never returned. The client workspace is used automatically by every
204
+ service.
205
+
206
+ ### `client.documents`
207
+
208
+ #### `documents.create(...)`
209
+
210
+ | Parameter | Required | Default | Description |
211
+ | --- | --- | --- | --- |
212
+ | `name` | Yes | — | Non-empty document name, for example `"meeting-notes.md"`. |
213
+ | `content` | Yes | — | Text content or a URL. |
214
+ | `source` | No | `"upload"` | Source label, for example `"notion"`, `"url"`, or `"upload"`. |
215
+ | `content_type` | No | `"text/plain"` | MIME type, for example `"text/markdown"` or `"text/html"`. |
216
+ | `task_type` | No | `"memory"` | `"memory"` or `"superrag"`. |
217
+ | `dreaming` | No | `"dynamic"` | `"dynamic"` or `"instant"`. |
218
+ | `batch_size` | No | `5` | Number of document chunks sent to the memory extractor per batch; must be positive. |
219
+ | `metadata` | No | `{}` | JSON-compatible metadata. |
220
+
221
+ ```python
222
+ document = await client.documents.create(
223
+ name="team-preferences.md",
224
+ content="The team prefers PostgreSQL for transactional workloads.",
225
+ source="internal-wiki",
226
+ content_type="text/markdown",
227
+ task_type="memory",
228
+ dreaming="dynamic",
229
+ metadata={"department": "engineering", "quarter": "2026-Q1"},
230
+ )
231
+ ```
232
+
233
+ #### `documents.upload_file(...)`
234
+
235
+ `file` is required and accepts raw `bytes`, a `bytearray`, a binary file object, or a filesystem
236
+ path. All other parameters are optional. `name` defaults to the path filename, or `"upload"` for
237
+ raw bytes. `content_type` defaults to `"application/octet-stream"`.
238
+
239
+ | Parameter | Required | Default | Description |
240
+ | --- | --- | --- | --- |
241
+ | `file` | Yes | — | Raw bytes, a binary file object, or a filesystem path. |
242
+ | `name` | No | Path filename or `"upload"` | Document display name. |
243
+ | `content_type` | No | `"application/octet-stream"` | MIME type of the uploaded file. |
244
+ | `task_type` | No | `"memory"` | `"memory"` extracts facts; `"superrag"` indexes without creating memories. |
245
+ | `dreaming` | No | `"dynamic"` | `"dynamic"` uses related memory context; `"instant"` processes independently. |
246
+ | `batch_size` | No | `5` | Number of document chunks sent to the memory extractor per batch; must be positive. |
247
+ | `metadata` | No | `{}` | JSON-compatible application metadata. |
248
+
249
+ ```python
250
+ document = await client.documents.upload_file(
251
+ file="./handbook.pdf",
252
+ name="engineering-handbook.pdf",
253
+ content_type="application/pdf",
254
+ task_type="superrag",
255
+ dreaming="instant",
256
+ metadata={"source": "handbook", "version": 3},
257
+ )
258
+ ```
259
+
260
+ #### Document lookup and lifecycle methods
261
+
262
+ `documents.list()` returns lightweight document summaries containing identity, source, type, and
263
+ processing status; it intentionally excludes large `content` and `metadata` fields.
264
+ `documents.get(document_id)` returns one full document. `documents.retry(document_id)` retries a
265
+ failed document. `documents.chunks(document_id)` returns its indexed chunks.
266
+ `documents.memories(document_id)` returns memories linked to it.
267
+ `documents.delete(document_id)` permanently deletes it and returns `None`.
268
+ `document_id` is always required; the client workspace is used automatically.
269
+
270
+ ```python
271
+ details = await client.documents.get(document["id"])
272
+ chunks = await client.documents.chunks(document["id"])
273
+ if details["status"] == "failed":
274
+ await client.documents.retry(document["id"])
275
+ ```
276
+
277
+ ### `client.memories`
278
+
279
+ #### `memories.add(...)`
280
+
281
+ | Parameter | Required | Default | Description |
282
+ | --- | --- | --- | --- |
283
+ | `content` | Yes | — | The fact or event to store. |
284
+ | `document_id` | No | — | Optional source document UUID. |
285
+ | `summary` | No | — | Short human-readable summary. |
286
+ | `memory_type` | No | `"semantic"` | `"semantic"`, `"episodic"`, or `"preference"`. |
287
+ | `importance` | No | `0.5` | Number from `0.0` to `1.0`. |
288
+ | `metadata` | No | `{}` | JSON-compatible metadata. |
289
+
290
+ ```python
291
+ memory = await client.memories.add(
292
+ content="The user prefers concise technical explanations.",
293
+ memory_type="preference",
294
+ importance=0.85,
295
+ metadata={"source": "onboarding", "confidence": 0.94},
296
+ )
297
+ ```
298
+
299
+ `memories.list(memory_type=None, document_id=None)` lists shared workspace
300
+ memories. `memory_type` and `document_id` are optional filters; `memory_type` accepts
301
+ the same three values as `memories.add`.
302
+
303
+ `memories.search(content)` searches shared workspace memories. The content is
304
+ required and the client workspace is used automatically.
305
+
306
+ `memories.update(memory_id, content=None, summary=None, importance=None,
307
+ metadata=None)` updates only supplied fields. `memory_id` is required. `importance`, when supplied,
308
+ must be between `0.0` and `1.0`; `None` means leave the field unchanged.
309
+
310
+ `memories.delete(memory_id)` deletes one memory. `memory_id` is required and
311
+ the method returns `None` on success.
312
+
313
+ #### `memories.generate(...)` (stateless)
314
+
315
+ Extracts memory drafts from supplied content using the configured server-side LLM. It returns
316
+ atomic facts with their type, importance, and relationship hints, but does not create memory
317
+ records or modify the database. Optional `existing_memories` are supplied only for comparison.
318
+ `batch_size` controls how many generated content chunks are sent to the extractor per LLM call and
319
+ defaults to `5`; it must be a positive integer.
320
+
321
+ ```python
322
+ drafts = await client.memories.generate(
323
+ content="The user prefers PostgreSQL and attended PyCon last month.",
324
+ existing_memories=["The user uses MySQL."],
325
+ batch_size=10,
326
+ )
327
+ ```
328
+
329
+
330
+ ### `client.profiles`
331
+
332
+ `profiles.list(document_id=None)` lists the workspace/document-derived profile,
333
+ optionally limited to a source document. `profiles.get(document_id=None)` returns
334
+ that profile, and `profiles.refresh(document_id=None)` rebuilds it. Profiles are
335
+ workspace/document projections and do not require a user ID.
336
+
337
+ ```python
338
+ profile = await client.profiles.get(
339
+ document_id="22222222-2222-2222-2222-222222222222",
340
+ )
341
+ await client.profiles.refresh(document_id="22222222-2222-2222-2222-222222222222")
342
+ ```
343
+
344
+ #### `profiles.generate(...)` (stateless)
345
+
346
+ Generates memory drafts from supplied content and builds a profile from those drafts. It does not
347
+ load persisted memories, write profile data, create memory records, or create relationships.
348
+ `batch_size` controls how many generated content chunks are sent to the extractor per LLM call. It
349
+ defaults to `5` and must be a positive integer.
350
+
351
+ ```python
352
+ profile = await client.profiles.generate(
353
+ workspace_id="workspace-123",
354
+ document_id="22222222-2222-2222-2222-222222222222",
355
+ content="The team prefers PostgreSQL and attended PyCon last month.",
356
+ batch_size=10,
357
+ )
358
+ ```
359
+
360
+ The response contains the generated `profile`, the extracted `memories`, and `persisted: false`.
361
+
362
+ ### `client.embeddings`
363
+
364
+ #### `embeddings.generate(...)` (stateless)
365
+
366
+ Generates vectors for caller-provided texts using the configured embedding provider. Vectors and
367
+ input text are not stored in the database.
368
+
369
+ ```python
370
+ embeddings = await client.embeddings.generate(
371
+ texts=[
372
+ "The team prefers PostgreSQL.",
373
+ "Redis is used for caching.",
374
+ ],
375
+ input_type="document", # or "query"
376
+ )
377
+ ```
378
+
379
+ The request accepts up to 256 texts. The response contains one embedding per input text.
380
+
381
+ ### `client.reranking`
382
+
383
+ #### `reranking.rerank(...)` (stateless)
384
+
385
+ Scores and orders only the contexts supplied by the caller. It does not retrieve additional
386
+ contexts and does not write reranking results to the database.
387
+
388
+ ```python
389
+ ranked = await client.reranking.rerank(
390
+ query="Which database does the team prefer?",
391
+ contexts=[
392
+ {"id": "redis", "content": "The team uses Redis for caching."},
393
+ {"id": "postgres", "content": "The team prefers PostgreSQL."},
394
+ ],
395
+ top_k=1,
396
+ )
397
+ ```
398
+
399
+ The request accepts up to 100 contexts. Each context can include an optional `id`, `content`,
400
+ and `metadata`. The response includes the original index, context, and reranking score.
401
+
402
+ ### `client.rag`
403
+
404
+ #### `rag.retrieve(...)`
405
+
406
+ Retrieves evidence without generating an answer.
407
+
408
+ | Parameter | Required | Default | Description |
409
+ | --- | --- | --- | --- |
410
+ | `query` | Yes | — | Search question or phrase. |
411
+ | `document_id` | No | — | Restrict retrieval to one document. |
412
+ | `limit` | No | `10` | Number of candidates, from `1` to `100`. |
413
+ | `search_mode` | No | `"hybrid"` | `"memory"`, `"document"`, or `"hybrid"`. |
414
+ | `rerank` | No | `False` | Apply the configured optional reranker. |
415
+ | `rewrite_query` | No | `False` | Rewrite/expand the query before retrieval while preserving the original. |
416
+ | `rerank_limit` | No | — | Candidate count for reranking, from `1` to `100`. |
417
+
418
+ ```python
419
+ evidence = await client.rag.retrieve(
420
+ query="Which database does the platform team standardize on?",
421
+ search_mode="hybrid",
422
+ limit=20,
423
+ rerank=True,
424
+ rerank_limit=8,
425
+ rewrite_query=True,
426
+ )
427
+ ```
428
+
429
+ #### `rag.query(...)`
430
+
431
+ Retrieves evidence and generates an answer using the server-configured LLM.
432
+
433
+ | Parameter | Required | Default | Description |
434
+ | --- | --- | --- | --- |
435
+ | `query` | Yes | — | User question. |
436
+ | `document_id` | No | — | Restrict retrieval to one document. |
437
+ | `top_k` | No | `10` | Retrieved candidates, from `1` to `50`. |
438
+ | `rephrasing_enabled` | No | `False` | Enable query rephrasing. |
439
+ | `rephrasing_mode` | No | `"rewrite"` | Server rephrasing strategy; use `"rewrite"` for the standard mode. |
440
+ | `search_mode` | No | `"hybrid"` | `"memory"`, `"document"`, or `"hybrid"`. |
441
+ | `rerank` | No | `False` | Apply the configured optional reranker. |
442
+ | `rerank_top_k` | No | — | Reranking candidate count, from `1` to `50`. |
443
+
444
+ ```python
445
+ result = await client.rag.query(
446
+ query="What is the team's database standard and why?",
447
+ search_mode="hybrid",
448
+ top_k=12,
449
+ rephrasing_enabled=True,
450
+ rephrasing_mode="rewrite",
451
+ rerank=True,
452
+ rerank_top_k=6,
453
+ )
454
+ print(result["answer"])
455
+ print(result["sources"])
456
+ ```
457
+
458
+ `rag.history` returns stored RAG query results for the workspace. The response
459
+ contains the original query, rewritten query when used, answer, sources, retrieved chunks, scores,
460
+ and creation timestamp.
461
+
462
+ ### Errors and validation
463
+
464
+ Successful methods return decoded JSON, except delete methods, which return `None` for HTTP 204.
465
+ Failures raise `EvolinkError` with `status_code`, `message`, and the original response `payload`.
466
+ Typical statuses are `400` for invalid parameters, `401` for a missing/revoked API key, `404` for
467
+ an unknown workspace/document/memory, and `422` for schema validation errors. UUID values may be
468
+ passed as either `uuid.UUID` objects or strings.