rocketride 1.0.2__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.
Files changed (67) hide show
  1. rocketride-1.0.2/LICENSE +21 -0
  2. rocketride-1.0.2/PKG-INFO +562 -0
  3. rocketride-1.0.2/README.md +518 -0
  4. rocketride-1.0.2/pyproject.toml +79 -0
  5. rocketride-1.0.2/setup.cfg +4 -0
  6. rocketride-1.0.2/src/rocketride/__init__.py +158 -0
  7. rocketride-1.0.2/src/rocketride/cli/__init__.py +57 -0
  8. rocketride-1.0.2/src/rocketride/cli/commands/__init__.py +55 -0
  9. rocketride-1.0.2/src/rocketride/cli/commands/base.py +184 -0
  10. rocketride-1.0.2/src/rocketride/cli/commands/events.py +389 -0
  11. rocketride-1.0.2/src/rocketride/cli/commands/list.py +160 -0
  12. rocketride-1.0.2/src/rocketride/cli/commands/start.py +258 -0
  13. rocketride-1.0.2/src/rocketride/cli/commands/status.py +249 -0
  14. rocketride-1.0.2/src/rocketride/cli/commands/stop.py +225 -0
  15. rocketride-1.0.2/src/rocketride/cli/commands/store.py +453 -0
  16. rocketride-1.0.2/src/rocketride/cli/commands/upload.py +335 -0
  17. rocketride-1.0.2/src/rocketride/cli/main.py +842 -0
  18. rocketride-1.0.2/src/rocketride/cli/monitors/__init__.py +53 -0
  19. rocketride-1.0.2/src/rocketride/cli/monitors/base.py +306 -0
  20. rocketride-1.0.2/src/rocketride/cli/monitors/events.py +362 -0
  21. rocketride-1.0.2/src/rocketride/cli/monitors/generic.py +105 -0
  22. rocketride-1.0.2/src/rocketride/cli/monitors/status.py +411 -0
  23. rocketride-1.0.2/src/rocketride/cli/monitors/upload.py +689 -0
  24. rocketride-1.0.2/src/rocketride/cli/ui/__init__.py +91 -0
  25. rocketride-1.0.2/src/rocketride/cli/ui/box.py +228 -0
  26. rocketride-1.0.2/src/rocketride/cli/ui/colors.py +72 -0
  27. rocketride-1.0.2/src/rocketride/cli/ui/display.py +151 -0
  28. rocketride-1.0.2/src/rocketride/cli/utils/__init__.py +50 -0
  29. rocketride-1.0.2/src/rocketride/cli/utils/config.py +120 -0
  30. rocketride-1.0.2/src/rocketride/cli/utils/file_utils.py +173 -0
  31. rocketride-1.0.2/src/rocketride/cli/utils/formatters.py +196 -0
  32. rocketride-1.0.2/src/rocketride/client.py +224 -0
  33. rocketride-1.0.2/src/rocketride/core/__init__.py +94 -0
  34. rocketride-1.0.2/src/rocketride/core/constants.py +84 -0
  35. rocketride-1.0.2/src/rocketride/core/dap_base.py +775 -0
  36. rocketride-1.0.2/src/rocketride/core/dap_client.py +348 -0
  37. rocketride-1.0.2/src/rocketride/core/exceptions.py +244 -0
  38. rocketride-1.0.2/src/rocketride/core/transport.py +315 -0
  39. rocketride-1.0.2/src/rocketride/core/transport_websocket.py +541 -0
  40. rocketride-1.0.2/src/rocketride/mixins/chat.py +196 -0
  41. rocketride-1.0.2/src/rocketride/mixins/connection.py +422 -0
  42. rocketride-1.0.2/src/rocketride/mixins/data.py +639 -0
  43. rocketride-1.0.2/src/rocketride/mixins/events.py +352 -0
  44. rocketride-1.0.2/src/rocketride/mixins/execution.py +427 -0
  45. rocketride-1.0.2/src/rocketride/mixins/ping.py +157 -0
  46. rocketride-1.0.2/src/rocketride/mixins/services.py +167 -0
  47. rocketride-1.0.2/src/rocketride/mixins/store.py +888 -0
  48. rocketride-1.0.2/src/rocketride/py.typed +2 -0
  49. rocketride-1.0.2/src/rocketride/rocketride.py +29 -0
  50. rocketride-1.0.2/src/rocketride/schema/__init__.py +84 -0
  51. rocketride-1.0.2/src/rocketride/schema/doc.py +128 -0
  52. rocketride-1.0.2/src/rocketride/schema/doc_filter.py +119 -0
  53. rocketride-1.0.2/src/rocketride/schema/doc_group.py +97 -0
  54. rocketride-1.0.2/src/rocketride/schema/doc_metadata.py +154 -0
  55. rocketride-1.0.2/src/rocketride/schema/question.py +661 -0
  56. rocketride-1.0.2/src/rocketride/types/__init__.py +125 -0
  57. rocketride-1.0.2/src/rocketride/types/client.py +174 -0
  58. rocketride-1.0.2/src/rocketride/types/data.py +172 -0
  59. rocketride-1.0.2/src/rocketride/types/events.py +307 -0
  60. rocketride-1.0.2/src/rocketride/types/pipeline.py +133 -0
  61. rocketride-1.0.2/src/rocketride/types/task.py +387 -0
  62. rocketride-1.0.2/src/rocketride.egg-info/PKG-INFO +562 -0
  63. rocketride-1.0.2/src/rocketride.egg-info/SOURCES.txt +65 -0
  64. rocketride-1.0.2/src/rocketride.egg-info/dependency_links.txt +1 -0
  65. rocketride-1.0.2/src/rocketride.egg-info/entry_points.txt +2 -0
  66. rocketride-1.0.2/src/rocketride.egg-info/requires.txt +16 -0
  67. rocketride-1.0.2/src/rocketride.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aparavi Software AG
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.
@@ -0,0 +1,562 @@
1
+ Metadata-Version: 2.4
2
+ Name: rocketride
3
+ Version: 1.0.2
4
+ Summary: RocketRide Pipeline Python Client SDK
5
+ Author-email: "RocketRide, Inc." <dev@rocketride.ai>
6
+ Maintainer-email: "RocketRide, Inc." <dev@rocketride.ai>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/rocketride-ai/rocketride-server
9
+ Project-URL: Documentation, https://github.com/rocketride-ai/rocketride-server#readme
10
+ Project-URL: Repository, https://github.com/rocketride-ai/rocketride-server.git
11
+ Project-URL: Bug Reports, https://github.com/rocketride-ai/rocketride-server/issues
12
+ Keywords: rocketride,pipeline,dap,debug-adapter-protocol,data-processing,client-sdk,async,websocket
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Classifier: Topic :: System :: Networking
17
+ Classifier: Topic :: Internet :: WWW/HTTP
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Operating System :: OS Independent
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.8
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: websockets>=11.0.0
30
+ Requires-Dist: aiofiles>=23.0.0
31
+ Requires-Dist: pydantic>=2.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.8.0; extra == "dev"
36
+ Requires-Dist: build>=0.10.0; extra == "dev"
37
+ Requires-Dist: twine>=4.0.0; extra == "dev"
38
+ Provides-Extra: test
39
+ Requires-Dist: pytest>=7.0.0; extra == "test"
40
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
41
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
42
+ Requires-Dist: python-dotenv>=1.0.0; extra == "test"
43
+ Dynamic: license-file
44
+
45
+ # rocketride
46
+
47
+ RocketRide Python Client -- Python SDK for the RocketRide Engine. Complete API reference below.
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install rocketride
53
+ ```
54
+
55
+ Import from the package (e.g. `from rocketride import RocketRideClient`).
56
+
57
+ ## Quick Start
58
+
59
+ ```python
60
+ import asyncio
61
+ from rocketride import RocketRideClient
62
+
63
+ async def main():
64
+ async with RocketRideClient(uri="https://cloud.rocketride.ai", auth="my-key") as client:
65
+ result = await client.use(filepath="pipeline.json")
66
+ token = result["token"]
67
+ out = await client.send(token, "Hello, pipeline!", objinfo={"name": "input.txt"}, mimetype="text/plain")
68
+ print(out)
69
+ await client.terminate(token)
70
+
71
+ asyncio.run(main())
72
+ ```
73
+
74
+ ## Features
75
+
76
+ - **Pipeline execution** -- Start with `use()`, send data via `send()`, `send_files()`, or `pipe()`
77
+ - **Chat** -- Conversational AI via `chat()` and `Question`
78
+ - **Event streaming** -- Real-time events via `on_event` and `set_events()`
79
+ - **File upload** -- `send_files()` with progress; streaming with `pipe()`
80
+ - **Connection lifecycle** -- Optional persist mode, reconnection, and callbacks (`on_connected`, `on_disconnected`, `on_connect_error`)
81
+ - **Async context manager** -- `async with RocketRideClient(...) as client:` for automatic cleanup
82
+
83
+ ---
84
+
85
+ ## RocketRideClient
86
+
87
+ ### Constructor
88
+
89
+ ```python
90
+ RocketRideClient(
91
+ uri: str = "",
92
+ auth: str = "",
93
+ *,
94
+ env: dict = None,
95
+ module: str = None,
96
+ request_timeout: float = None,
97
+ max_retry_time: float = None,
98
+ persist: bool = False,
99
+ on_event = None,
100
+ on_connected = None,
101
+ on_disconnected = None,
102
+ on_connect_error = None,
103
+ on_protocol_message = None,
104
+ on_debug_message = None,
105
+ )
106
+ ```
107
+
108
+ **Why the options matter:** `uri` and `auth` tell the client *where* and *how* to authenticate. `persist` and `max_retry_time` control what happens when the connection fails or the server is not ready yet: with `persist=True` the client retries with exponential backoff and calls `on_connect_error` on each failure, so you can show "Still connecting..." or "Connection failed" without implementing retry logic yourself. Use `on_disconnected` only for "we were connected and then dropped"; use `on_connect_error` for "failed to connect" or "gave up after max retry time."
109
+
110
+ | Argument | Type | Required | Description |
111
+ | --------------------- | ------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
112
+ | `uri` | `str` | Yes* | Server URI. *Can be empty if `ROCKETRIDE_URI` is set in env/`.env`. |
113
+ | `auth` | `str` | Yes* | API key. *Can be empty if `ROCKETRIDE_APIKEY` is set. |
114
+ | `env` | `dict` | No | Override env; if omitted, `.env` is loaded. Use when passing config in code instead of env files. |
115
+ | `module` | `str` | No | Client name for logging. |
116
+ | `request_timeout` | `float` | No | Default timeout in ms for requests. Prevents a single DAP call from hanging. |
117
+ | `max_retry_time` | `float` | No | Max time in ms to keep retrying connection. Use (e.g. 300000) so the app can show "gave up" after a bounded time. |
118
+ | `persist` | `bool` | No | Enable automatic reconnection. Default: `False`. Set `True` for long-lived scripts or UIs. |
119
+ | `on_event` | async callable | No | Called with each server event dict. Use for progress or status updates. |
120
+ | `on_connected` | async callable | No | Called when connection is established. |
121
+ | `on_disconnected` | async callable | No | Called when connection is lost **only if** connected first; args: `reason`, `has_error`. Do not call `disconnect()` here if you want auto-reconnect. |
122
+ | `on_connect_error` | callable `(message: str)` | No | Called on each failed connection attempt. On auth failure the client stops retrying. |
123
+ | `on_protocol_message` | callable `(message: str)` | No | Optional; for logging raw DAP messages. Helpful when debugging protocol issues. |
124
+ | `on_debug_message` | callable `(message: str)` | No | Optional; for debug output. |
125
+
126
+ Raises `ValueError` if both `uri` and `ROCKETRIDE_URI` are empty or if `auth` is missing and not in env.
127
+
128
+ **Example -- client with persist and callbacks:**
129
+
130
+ ```python
131
+ client = RocketRideClient(
132
+ uri="https://cloud.rocketride.ai",
133
+ auth="my-key",
134
+ persist=True,
135
+ max_retry_time=300000,
136
+ on_connect_error=lambda msg: print("Connect error:", msg),
137
+ on_event=handle_event,
138
+ )
139
+ ```
140
+
141
+ ### Context manager
142
+
143
+ | Method | Signature | Returns | Description |
144
+ | ------------ | ------------------------------------------------------ | ------- | ------------------------------------ |
145
+ | `__aenter__` | `async def __aenter__(self)` | `self` | Enters context; calls `connect()`. |
146
+ | `__aexit__` | `async def __aexit__(self, exc_type, exc_val, exc_tb)` | -- | Exits context; calls `disconnect()`. |
147
+
148
+ **How to use:** Prefer `async with RocketRideClient(...) as client:` so the connection is always closed when you leave the block, even on exception. No need to call `disconnect()` manually.
149
+
150
+ **Example:**
151
+
152
+ ```python
153
+ async with RocketRideClient(uri="wss://cloud.rocketride.ai", auth=os.environ["ROCKETRIDE_APIKEY"]) as client:
154
+ result = await client.use(filepath="pipeline.json")
155
+ token = result["token"]
156
+ await client.send(token, "Hello, pipeline!")
157
+ ```
158
+
159
+ ### Connection
160
+
161
+ | Method | Signature | Returns | Description |
162
+ | ----------------------- | --------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
163
+ | `connect` | `async def connect(self, uri: str = None, auth: str = None, timeout: float = None) -> None` | -- | Opens the WebSocket and performs DAP auth. Optional `uri`/`auth` override the constructor values for this connection attempt. Optional `timeout` (ms) bounds the connect + auth handshake (non-persist only). In **persist** mode, on failure the client calls `on_connect_error` and retries; on **auth** failure it does not retry. |
164
+ | `disconnect` | `async def disconnect(self) -> None` | -- | Closes the connection and cancels reconnection. Call when the user disconnects or the script is done. |
165
+ | `is_connected` | `def is_connected(self) -> bool` | `bool` | Whether the client is connected. Check before calling `use()` or `send()` if needed. |
166
+ | `set_connection_params` | `async def set_connection_params(self, uri: str = None, auth: str = None) -> None` | -- | Updates server URI and/or auth at runtime. If currently connected, disconnects and reconnects with the new params (in persist mode, reconnection is scheduled; otherwise reconnects once). Use when the user changes server or credentials without creating a new client. |
167
+ | `get_connection_info` | `def get_connection_info(self) -> dict` | `dict` | Current connection state and URI. Returns `{ 'connected': bool, 'transport': str, 'uri': str }`. Useful for debugging or displaying "Connected to ..." in the UI. |
168
+ | `get_apikey` | `def get_apikey(self) -> Optional[str]` | `str \| None` | The API key in use. For debugging only; avoid logging in production. |
169
+
170
+ ### Low-level DAP
171
+
172
+ | Method | Signature | Returns | Description |
173
+ | --------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
174
+ | `build_request` | `def build_request(self, command: str, *, token: str = None, arguments: dict = None, data: bytes \| str = None) -> dict` | `dict` | Builds a DAP request message. Use for custom commands not covered by `use()`, `send()`, etc. |
175
+ | `request` | `async def request(self, request: dict, timeout: float = None) -> dict` | `dict` | Sends the request and returns the response. `timeout` in ms overrides the default for this call. Use `did_fail(response)` before trusting `body`. |
176
+ | `dap_request` | `async def dap_request(self, command: str, arguments: dict = None, token: str = None, timeout: float = None) -> dict` | `dict` | Shorthand: builds a request and sends it in one call. Equivalent to `build_request()` + `request()`. |
177
+ | `did_fail` | `def did_fail(self, request: dict) -> bool` | `bool` | Returns `True` when the response indicates failure (`success === False`). |
178
+
179
+ **Example:**
180
+
181
+ ```python
182
+ # Two-step (build then request)
183
+ req = client.build_request("rrext_monitor", token=token, arguments={"types": ["apaevt_status_upload"]})
184
+ res = await client.request(req, timeout=5000)
185
+
186
+ # One-step with dap_request
187
+ res = await client.dap_request("rrext_services", {}, timeout=5000)
188
+
189
+ if client.did_fail(res):
190
+ raise RuntimeError(res.get("message", "Request failed"))
191
+ ```
192
+
193
+ ### Pipeline execution
194
+
195
+ | Method | Signature | Returns | Description |
196
+ | ----------------- | --------- | ------- | ----------- |
197
+ | `use` | `async def use(self, *, token: str = None, filepath: str = None, pipeline: dict = None, source: str = None, threads: int = None, use_existing: bool = None, args: list = None, ttl: int = None) -> dict` | `dict` | Starts a pipeline. Requires `filepath` or `pipeline`. The client substitutes `${ROCKETRIDE_*}` from its env. Returns a dict with at least `'token'`; use that token for all data and control operations. |
198
+ | `terminate` | `async def terminate(self, token: str) -> None` | -- | Stops the pipeline and frees server resources. |
199
+ | `get_task_status` | `async def get_task_status(self, token: str) -> dict` | `dict` | Returns current task status (e.g. completed count, total, state). Poll until `completed` or use for progress display. |
200
+
201
+ **Why a token:** The server runs each pipeline as a separate task. The token identifies that task so `send()`, `send_files()`, `pipe()`, `chat()`, and `get_task_status()` target the correct pipeline.
202
+
203
+ ### Data
204
+
205
+ | Method | Signature | Returns | Description |
206
+ | ------------ | --------- | ------- | ----------- |
207
+ | `pipe` | `async def pipe(self, token: str, objinfo: dict = None, mime_type: str = None, provider: str = None) -> DataPipe` | `DataPipe` | Creates a **streaming** pipe: open, then one or more write, then close. Use for large or chunked data. Default MIME: `'application/octet-stream'`. |
208
+ | `send` | `async def send(self, token: str, data: str \| bytes, objinfo: dict = None, mimetype: str = None) -> PIPELINE_RESULT` | `PIPELINE_RESULT` | Sends data in **one shot** (open pipe, write once, close). Use when you have the full payload in memory. |
209
+ | `send_files` | `async def send_files(self, files: List[str \| Tuple[str, dict] \| Tuple[str, dict, str]], token: str) -> List[UPLOAD_RESULT]` | `List[UPLOAD_RESULT]` | Uploads files. Each item: path `str`, or `(path, objinfo)`, or `(path, objinfo, mimetype)`. Progress via `on_event` as `apaevt_status_upload`. |
210
+
211
+ **When to use pipe vs send:** Use `send()` for a single string or bytes. Use `pipe()` when you read a file in chunks, or when data arrives incrementally.
212
+
213
+ **Example -- send a string:**
214
+
215
+ ```python
216
+ result = await client.send(token, "Hello, pipeline!", objinfo={"name": "greeting.txt"}, mimetype="text/plain")
217
+ ```
218
+
219
+ **Example -- stream with a pipe (context manager):**
220
+
221
+ ```python
222
+ pipe = await client.pipe(token, mime_type="application/json")
223
+ async with pipe:
224
+ await pipe.write(b'{"key": "value1"}')
225
+ await pipe.write(b'{"key": "value2"}')
226
+ result = await pipe.close() # result available after context
227
+ ```
228
+
229
+ ### Events
230
+
231
+ | Method | Signature | Returns | Description |
232
+ | ------------ | --------- | ------- | ----------- |
233
+ | `set_events` | `async def set_events(self, token: str, event_types: List[str]) -> None` | -- | Subscribes this task to the given event types. After this, those events are delivered to `on_event`. Call after `use()` when you need upload or processing progress. |
234
+
235
+ ### Services, validation, and ping
236
+
237
+ | Method | Signature | Returns | Description |
238
+ | -------------- | --------- | ------- | ----------- |
239
+ | `get_services` | `async def get_services(self) -> dict` | `dict` | Returns all service definitions. Use to discover what the server supports. |
240
+ | `get_service` | `async def get_service(self, service: str) -> Optional[dict]` | `dict \| None` | Returns one service by name; `None` if not found or on error. |
241
+ | `validate` | `async def validate(self, pipeline: PipelineConfig, *, source: str = None) -> dict` | `dict` | Validates a pipeline configuration without starting it. Returns validation results (e.g. errors, warnings). Use to check pipeline correctness before `use()`. |
242
+ | `ping` | `async def ping(self, token: str = None) -> None` | -- | Liveness check; raises on failure. |
243
+
244
+ ### Chat
245
+
246
+ | Method | Signature | Returns | Description |
247
+ | ------ | --------- | ------- | ----------- |
248
+ | `chat` | `async def chat(self, *, token: str, question: Question) -> PIPELINE_RESULT` | `PIPELINE_RESULT` | Sends the `Question` to the AI for the given token and returns the pipeline result. The answer is in the result body; use the schema's answer helpers if you need to parse JSON from the AI text. |
249
+
250
+ **How it works:** The client opens a pipe with the question MIME type, writes the serialized `Question`, closes the pipe, and returns the server result. The pipeline must support the chat provider.
251
+
252
+ ---
253
+
254
+ ## DataPipe
255
+
256
+ Returned by `await client.pipe(...)`. One streaming upload: **open** -> **write** (one or more) -> **close**. You can also use it as an async context manager: entering calls `open()`, exiting calls `close()`.
257
+
258
+ | Property | Type | Description |
259
+ | ----------- | -------------- | ---------------------------------------- |
260
+ | `is_opened` | `bool` | Whether the pipe is open. |
261
+ | `pipe_id` | `int \| None` | Server-assigned pipe ID after `open()`. |
262
+
263
+ | Method | Signature | Returns | Description |
264
+ | ------------ | ------------------------------------------------------ | ----------------- | ------------------------------------------------- |
265
+ | `open` | `async def open(self) -> DataPipe` | `self` | Opens the pipe; required before `write()`. |
266
+ | `write` | `async def write(self, buffer: bytes) -> None` | -- | Writes a chunk. Pipe must be open. |
267
+ | `close` | `async def close(self) -> PIPELINE_RESULT` | `PIPELINE_RESULT` | Closes the pipe and returns the processing result. |
268
+ | `__aenter__` | `async def __aenter__(self)` | `self` | Enters context; calls `open()`. |
269
+ | `__aexit__` | `async def __aexit__(self, exc_type, exc_val, exc_tb)` | -- | Exits context; calls `close()`. |
270
+
271
+ ---
272
+
273
+ ## Question
274
+
275
+ From `rocketride.schema`. Build a question for `client.chat(token=..., question=question)`. Add instructions, examples, context, history, and documents to steer the AI.
276
+
277
+ ### Constructor
278
+
279
+ ```python
280
+ Question(
281
+ type: QuestionType = QuestionType.QUESTION,
282
+ filter: DocFilter = None,
283
+ expectJson: bool = False,
284
+ role: str = '',
285
+ )
286
+ ```
287
+
288
+ `QuestionType`: `QUESTION`, `SEMANTIC`, `KEYWORD`, `GET`, `PROMPT`. Default type is `QUESTION`. Default filter and `expectJson=False`, `role=''` if omitted.
289
+
290
+ ### Methods
291
+
292
+ | Method | Signature | Description |
293
+ | ---------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
294
+ | `addInstruction` | `addInstruction(self, title: str, instruction: str)` | Adds an instruction (e.g. "Use bullet points"). |
295
+ | `addExample` | `addExample(self, given: str, result: dict \| list \| str)` | Adds an example input/output; `result` can be dict/list (JSON-serialized). |
296
+ | `addContext` | `addContext(self, context: str \| dict \| List[str] \| List[dict])` | Adds context. |
297
+ | `addHistory` | `addHistory(self, item: QuestionHistory)` | Adds a history item for multi-turn chat. |
298
+ | `addQuestion` | `addQuestion(self, question: str)` | Appends the question text. |
299
+ | `addDocuments` | `addDocuments(self, documents: Doc \| List[Doc])` | Adds documents for the AI to reference. |
300
+ | `getPrompt` | `getPrompt(self, has_previous_json_failed: bool = False) -> str` | Returns the full prompt (internal). |
301
+
302
+ ---
303
+
304
+ ## Answer
305
+
306
+ From `rocketride.schema`. Used to parse chat response content. The client does not attach an `Answer` instance to the pipeline result; you read the response body and, if needed, use these helpers to extract JSON or code from AI text (which often includes markdown or code fences).
307
+
308
+ | Method | Signature | Description |
309
+ | ------------- | ------------------------------------------ | ---------------------------------------------------------------------- |
310
+ | `getText` | `getText(self) -> str` | Get the answer as plain text. |
311
+ | `getJson` | `getJson(self) -> Optional[dict]` | Get the answer as parsed JSON; returns `None` if not valid JSON. |
312
+ | `isJson` | `isJson(self) -> bool` | Whether the answer contains valid JSON. |
313
+ | `parseJson` | `parseJson(self, value: str) -> Any` | Parses JSON from AI text (strips markdown/code blocks). |
314
+ | `parsePython` | `parsePython(self, value: str) -> Any` | Extracts Python code from a code block in the response. |
315
+
316
+ ---
317
+
318
+ ## Types
319
+
320
+ - **PIPELINE_RESULT**: TypedDict with `name`, `path`, `objectId`, optional `result_types`, and dynamic fields.
321
+ - **UPLOAD_RESULT**: Per-file result with `action`, `filepath`, `error?`, `result?`, `upload_time?`, etc.
322
+ - **TASK_STATUS**: Task status with `completedCount`, `totalCount`, `completed`, `state`, `exitCode`, and many more fields.
323
+ - **DAPMessage**: Dict with `type`, `seq`, and optional `command`, `arguments`, `body`, `success`, `message`, `event`, `token`, etc.
324
+ - **PipelineConfig**: Pipeline definition with `name`, `description`, `version`, `components`, `source`, `project_id`.
325
+ - **QuestionHistory**: `{ 'role': str, 'content': str }`.
326
+ - **QuestionInstruction**: `{ 'subtitle': str, 'instructions': str }`.
327
+ - **QuestionExample**: `{ 'given': str, 'result': str }`.
328
+
329
+ ---
330
+
331
+ ## Exceptions
332
+
333
+ The exception hierarchy provides fine-grained error handling:
334
+
335
+ ```text
336
+ DAPException # Base DAP protocol error (has dap_result dict)
337
+ └── RocketRideException # Base for all RocketRide errors
338
+ ├── ConnectionException # Connection/network issues
339
+ │ └── AuthenticationException # Bad API key or credentials
340
+ ├── PipeException # Data pipe errors (open/write/close)
341
+ ├── ExecutionException # Pipeline start/run failures
342
+ └── ValidationException # Invalid input/config
343
+ ```
344
+
345
+ All exceptions expose a `dap_result` dict with detailed server error context.
346
+
347
+ `AuthenticationException` is thrown on DAP auth failure. In persist mode the client catches it, calls `on_connect_error`, and does not retry so the app can fix credentials and call `connect()` again.
348
+
349
+ **Example:**
350
+
351
+ ```python
352
+ from rocketride import RocketRideClient, AuthenticationException
353
+ from rocketride.core.exceptions import PipeException, ExecutionException
354
+
355
+ try:
356
+ async with RocketRideClient(uri=uri, auth=auth) as client:
357
+ result = await client.use(filepath="pipeline.json")
358
+ await client.send(result["token"], data)
359
+ except AuthenticationException:
360
+ print("Bad credentials")
361
+ except ExecutionException as e:
362
+ print(f"Pipeline failed: {e}")
363
+ except PipeException as e:
364
+ print(f"Data transfer error: {e}")
365
+ ```
366
+
367
+ ---
368
+
369
+ ## Examples (Full API Usage)
370
+
371
+ ### 1. Minimal: connect, run pipeline from file, send one string, disconnect
372
+
373
+ ```python
374
+ import asyncio
375
+ from rocketride import RocketRideClient
376
+
377
+ async def main():
378
+ client = RocketRideClient(uri="https://cloud.rocketride.ai", auth="my-key")
379
+ await client.connect()
380
+ result = await client.use(filepath="pipeline.json")
381
+ token = result["token"]
382
+ out = await client.send(token, "Hello, pipeline!", objinfo={"name": "input.txt"}, mimetype="text/plain")
383
+ print(out)
384
+ await client.terminate(token)
385
+ await client.disconnect()
386
+
387
+ asyncio.run(main())
388
+ ```
389
+
390
+ ### 2. One-off script with context manager (recommended)
391
+
392
+ ```python
393
+ import asyncio
394
+ from rocketride import RocketRideClient
395
+
396
+ async def main():
397
+ async with RocketRideClient(uri="wss://cloud.rocketride.ai", auth="my-key") as client:
398
+ result = await client.use(pipeline={"pipeline": my_pipeline_config})
399
+ token = result["token"]
400
+ await client.send(token, '{"data": 1}')
401
+ status = await client.get_task_status(token)
402
+ print(status)
403
+ await client.terminate(token)
404
+
405
+ asyncio.run(main())
406
+ ```
407
+
408
+ ### 3. Long-lived app: persist mode, callbacks, and status handling
409
+
410
+ ```python
411
+ import asyncio
412
+ from rocketride import RocketRideClient
413
+
414
+ async def main():
415
+ client = RocketRideClient(
416
+ uri="https://cloud.rocketride.ai",
417
+ auth="my-key",
418
+ persist=True,
419
+ max_retry_time=300000,
420
+ on_connected=lambda info: print("Connected:", info),
421
+ on_disconnected=lambda reason, has_error: print("Disconnected:", reason, has_error),
422
+ on_connect_error=lambda msg: print("Connect error:", msg),
423
+ on_event=lambda e: print(e.get("event"), e.get("body")),
424
+ )
425
+ await client.connect()
426
+ # Later: use(), send_files(), etc. If connection drops, client retries; do not call disconnect() in on_disconnected.
427
+
428
+ asyncio.run(main())
429
+ ```
430
+
431
+ ### 4. Upload multiple files and poll until pipeline completes
432
+
433
+ ```python
434
+ import asyncio
435
+ from pathlib import Path
436
+ from rocketride import RocketRideClient
437
+
438
+ async def main():
439
+ client = RocketRideClient(uri="https://cloud.rocketride.ai", auth="my-key")
440
+ await client.connect()
441
+ result = await client.use(filepath="vectorize.json")
442
+ token = result["token"]
443
+ await client.set_events(token, ["apaevt_status_upload", "apaevt_status_processing"])
444
+
445
+ files = ["doc1.md", "doc2.md", ("doc3.json", {"tag": "export"}, "application/json")]
446
+ upload_results = await client.send_files(files, token)
447
+ for r in upload_results:
448
+ if r["action"] == "complete":
449
+ print("OK", r["filepath"])
450
+ else:
451
+ print("Failed", r["filepath"], r.get("error"))
452
+
453
+ while True:
454
+ status = await client.get_task_status(token)
455
+ print(f"Progress: {status.get('completedCount', 0)}/{status.get('totalCount', 0)}")
456
+ if status.get("completed"):
457
+ break
458
+ await asyncio.sleep(2)
459
+ await client.terminate(token)
460
+ await client.disconnect()
461
+
462
+ asyncio.run(main())
463
+ ```
464
+
465
+ ### 5. Streaming large data with a pipe
466
+
467
+ ```python
468
+ import asyncio
469
+ from rocketride import RocketRideClient
470
+
471
+ async def main():
472
+ async with RocketRideClient(uri="https://cloud.rocketride.ai", auth="my-key") as client:
473
+ result = await client.use(filepath="ingest.json")
474
+ token = result["token"]
475
+ pipe = await client.pipe(token, objinfo={"name": "large.csv"}, mime_type="text/csv")
476
+ async with pipe:
477
+ with open("large.csv", "rb") as f:
478
+ while True:
479
+ chunk = f.read(64 * 1024)
480
+ if not chunk:
481
+ break
482
+ await pipe.write(chunk)
483
+ result = await pipe.close()
484
+ print(result)
485
+ await client.terminate(token)
486
+
487
+ asyncio.run(main())
488
+ ```
489
+
490
+ ### 6. Chat: question with instructions and examples, parse JSON answer
491
+
492
+ ```python
493
+ import asyncio
494
+ from rocketride import RocketRideClient
495
+ from rocketride.schema import Question, Answer
496
+
497
+ async def main():
498
+ async with RocketRideClient(uri="https://cloud.rocketride.ai", auth="my-key") as client:
499
+ result = await client.use(filepath="chat_pipeline.json")
500
+ token = result["token"]
501
+ question = Question(expectJson=True)
502
+ question.addInstruction("Format", "Return a JSON object with keys: summary, keywords.")
503
+ question.addExample("Summarize X", {"summary": "...", "keywords": ["a", "b"]})
504
+ question.addQuestion("Summarize the main points and list keywords.")
505
+ response = await client.chat(token=token, question=question)
506
+ answer_text = response.get("data", {}).get("answer") or (response.get("answers") or [None])[0]
507
+ structured = Answer().parseJson(answer_text) if answer_text else None
508
+ print(structured)
509
+ await client.terminate(token)
510
+
511
+ asyncio.run(main())
512
+ ```
513
+
514
+ ### 7. Discover services and send a custom DAP request
515
+
516
+ ```python
517
+ import asyncio
518
+ from rocketride import RocketRideClient
519
+
520
+ async def main():
521
+ client = RocketRideClient(uri="https://cloud.rocketride.ai", auth="my-key")
522
+ await client.connect()
523
+ services = await client.get_services()
524
+ print("Available:", list(services.keys()))
525
+ ocr = await client.get_service("ocr")
526
+ if ocr:
527
+ print("OCR schema:", ocr.get("schema"))
528
+ req = client.build_request("rrext_ping", token=my_token)
529
+ res = await client.request(req, timeout=5000)
530
+ if client.did_fail(res):
531
+ raise RuntimeError(res.get("message", "Ping failed"))
532
+ await client.disconnect()
533
+
534
+ asyncio.run(main())
535
+ ```
536
+
537
+ ---
538
+
539
+ ## Directory Structure
540
+
541
+ Source location in the repository:
542
+
543
+ ```text
544
+ packages/client-python/
545
+ ├── src/rocketride/
546
+ │ ├── client.py # Main RocketRideClient class
547
+ │ ├── core/ # DAP protocol, transport, exceptions
548
+ │ ├── mixins/ # Connection, data, chat, events, services, store
549
+ │ ├── schema/ # Question, Answer, Doc, DocFilter, DocGroup, DocMetadata
550
+ │ ├── types/ # Type definitions (PIPELINE_RESULT, TASK_STATUS, etc.)
551
+ │ └── cli/ # CLI (rocketride command)
552
+ ├── tests/
553
+ ├── examples/
554
+ ├── pyproject.toml
555
+ └── README.md
556
+ ```
557
+
558
+ ---
559
+
560
+ ## License
561
+
562
+ MIT License -- see [LICENSE](../LICENSE).