@ocno/oryn-sdk 0.0.0-stage → 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/CONTRIBUTING.md +3 -0
- package/LICENSE +21 -0
- package/README.md +184 -2
- package/SECURITY.md +3 -0
- package/dist/index.d.ts +800 -0
- package/dist/index.js +1773 -0
- package/docs/api-reference.md +280 -0
- package/docs/images/request-lifecycle.png +0 -0
- package/docs/images/request-lifecycle.svg +59 -0
- package/docs/recipes.md +288 -0
- package/package.json +34 -3
package/CONTRIBUTING.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OCNO
|
|
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
CHANGED
|
@@ -1,3 +1,185 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Oryn SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Local AI for ordinary websites.** `@ocno/oryn-sdk` is a TypeScript-first ESM client for Oryn Browser. Request a model, submit a job, and receive streaming text, structured data, or media artifacts through one framework-independent API.
|
|
4
|
+
|
|
5
|
+
**[Quickstart](#stream-your-first-response) · [API reference](docs/api-reference.md) · [Recipes](docs/recipes.md)**
|
|
6
|
+
|
|
7
|
+
- No runtime dependencies on React, Electron, Node.js, Python, or an inference engine.
|
|
8
|
+
- Safe to import and create during server-side rendering.
|
|
9
|
+
- Typed model requests, job events, artifacts, and task contracts.
|
|
10
|
+
- Browser-owned permission, model choice, and origin isolation.
|
|
11
|
+
|
|
12
|
+
> **Developer alpha · 0.1.0**
|
|
13
|
+
>
|
|
14
|
+
> LocalAI requires a compatible Oryn Browser. Installing this package alone does not provide model execution.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @ocno/oryn-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The package exports ESM and TypeScript declarations. Execute Local AI feature work in the browser, from a deliberate user action. Serve production integrations over HTTPS; use loopback origins for development.
|
|
23
|
+
|
|
24
|
+
## Stream your first response
|
|
25
|
+
|
|
26
|
+
This function requests a chat model, streams text into your callback, handles terminal failure/cancellation, and releases the session. Call it from your Send button and pass an `AbortController` signal from your Cancel button.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import {
|
|
30
|
+
createLocalAIClient,
|
|
31
|
+
invokeStream,
|
|
32
|
+
LocalAIError,
|
|
33
|
+
} from "@ocno/oryn-sdk";
|
|
34
|
+
|
|
35
|
+
export async function streamReply(
|
|
36
|
+
prompt: string,
|
|
37
|
+
appendText: (text: string) => void,
|
|
38
|
+
signal: AbortSignal,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const localAI = createLocalAIClient();
|
|
41
|
+
const capabilities = await localAI.getCapabilities();
|
|
42
|
+
if (!capabilities.runtimeAvailable) {
|
|
43
|
+
throw new Error("Open this page in Oryn with Local AI available.");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const session = await localAI.models.request(
|
|
47
|
+
{
|
|
48
|
+
role: "chat",
|
|
49
|
+
requirements: {
|
|
50
|
+
task: "text-generation",
|
|
51
|
+
inputModalities: ["text"],
|
|
52
|
+
outputModalities: ["text"],
|
|
53
|
+
capabilities: { chat: true, streaming: true },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{ signal, onProgress: (progress) => console.info(progress.stage) },
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
for await (const event of invokeStream(
|
|
61
|
+
localAI,
|
|
62
|
+
{
|
|
63
|
+
sessionId: session.sessionId,
|
|
64
|
+
input: { messages: [{ role: "user", content: prompt }] },
|
|
65
|
+
},
|
|
66
|
+
{ signal },
|
|
67
|
+
)) {
|
|
68
|
+
if (event.event === "job.output.delta" && event.data.channel === "text") {
|
|
69
|
+
appendText(String(event.data.delta));
|
|
70
|
+
} else if (event.event === "job.failed") {
|
|
71
|
+
throw new LocalAIError(event.data.error);
|
|
72
|
+
} else if (event.event === "job.cancelled") {
|
|
73
|
+
throw new LocalAIError({
|
|
74
|
+
code: "REQUEST_ABORTED",
|
|
75
|
+
message: "Generation was cancelled.",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} finally {
|
|
80
|
+
await localAI.models.releaseSession(session.sessionId);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A capability-only request lets Oryn resolve a matching model. It may require model choice, permission, or a download; it can fail if no executable match exists. To suggest a particular model, use the [model selection recipe](docs/recipes.md#choose-a-model).
|
|
86
|
+
|
|
87
|
+
`invokeStream()` yields **all** job events, including terminal failure and cancellation. It does not convert those terminal events into thrown errors. `invokeAndWait()` does that conversion for callers that want a final result. Both helpers subscribe before submitting the job.
|
|
88
|
+
|
|
89
|
+
## The request lifecycle
|
|
90
|
+
|
|
91
|
+

|
|
92
|
+
|
|
93
|
+
[View the full-size lifecycle diagram](docs/images/request-lifecycle.svg).
|
|
94
|
+
|
|
95
|
+
| Concept | Meaning |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| **Client** | A lightweight wrapper around Oryn's injected website bridge |
|
|
98
|
+
| **Model request** | Your task, preferred model or capability requirements, and substitution policy |
|
|
99
|
+
| **Session** | An origin-bound handle to the resolved model and its effective task capabilities |
|
|
100
|
+
| **Job** | One asynchronous invocation, with queue/progress/output and a terminal event |
|
|
101
|
+
| **Artifact** | An opaque capability for binary input or output |
|
|
102
|
+
|
|
103
|
+
A session can be reused across jobs. The quickstart releases it after one response for clarity; a chat app can keep one while the conversation UI is active. Release it when the feature is disposed.
|
|
104
|
+
|
|
105
|
+
## Detect Oryn and provide a fallback
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { createLocalAIClient } from "@ocno/oryn-sdk";
|
|
109
|
+
|
|
110
|
+
export async function canUseLocalAI(): Promise<boolean> {
|
|
111
|
+
const localAI = createLocalAIClient();
|
|
112
|
+
return (await localAI.getCapabilities()).runtimeAvailable;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Outside Oryn, `getCapabilities()` resolves with `runtimeAvailable: false`. Privileged operations reject with `LocalAIError` code `RUNTIME_NOT_AVAILABLE`. Importing and creating the client are SSR-safe; model requests and jobs belong in client-side code.
|
|
117
|
+
|
|
118
|
+
Build your own explanation, disable the local action, or offer a clearly disclosed fallback. You can optionally create the client with `{ showOrynBrowserAlert: true }` to show a website-owned Oryn explanation once per document outside Oryn. It is off by default and is not a trusted permission prompt.
|
|
119
|
+
|
|
120
|
+
## Pick the right invocation API
|
|
121
|
+
|
|
122
|
+
| API | Use it when | Completion behavior |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| `invokeAndWait(client, request, options)` | You need the final structured/media result | Resolves on completion; rejects on job failure or cancellation |
|
|
125
|
+
| `invokeStream(client, request, options)` | You need incremental text, progress, or previews | Yields events through the terminal event; inspect its outcome |
|
|
126
|
+
| `client.invoke(request)` + `client.subscribe(listener)` | You manage your own job state | Returns a job reference; subscribe before invocation and filter by job ID |
|
|
127
|
+
|
|
128
|
+
Pass `signal` to model requests and helpers for cancellation. `client.cancel(jobId)` targets a known job directly. Breaking out of a stream only unsubscribes the helper; it does not cancel the underlying job. Read the [cancellation notes](docs/api-reference.md#cancellation-and-cleanup) before building a custom job manager.
|
|
129
|
+
|
|
130
|
+
## Work with files and results
|
|
131
|
+
|
|
132
|
+
Use `artifacts.create(fileOrBlob)` for binary input and put the returned ID in the task input. Results use one of three shapes:
|
|
133
|
+
|
|
134
|
+
| `result.kind` | Payload |
|
|
135
|
+
| --- | --- |
|
|
136
|
+
| `structured` | `result.value`: task-specific JSON |
|
|
137
|
+
| `artifact` | `result.artifact`: metadata for an image, audio file, video, or other output |
|
|
138
|
+
| `multi` | `result.outputs`: a list of result envelopes |
|
|
139
|
+
|
|
140
|
+
Display media with `artifacts.getUrl(id)`, read complete bytes with `artifacts.readBlob(id)`, or open a trusted save dialog with `artifacts.saveAs(id)`. Release artifacts after their final consumer is finished. An upload is a separate, explicit website action.
|
|
141
|
+
|
|
142
|
+
See [transcription](docs/recipes.md#transcribe-a-wav-file) and [media outputs](docs/recipes.md#display-save-and-upload-an-output) for complete examples. Artifact IDs and URLs do not expose local paths and should not be treated as permanent links.
|
|
143
|
+
|
|
144
|
+
## Handle expected failures
|
|
145
|
+
|
|
146
|
+
Use `LocalAIError.code`, not the English message, for application behavior. Common cases include:
|
|
147
|
+
|
|
148
|
+
| Code | Suggested UI |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| `RUNTIME_NOT_AVAILABLE`, `RUNTIME_STARTING` | Show availability state or a fallback |
|
|
151
|
+
| `USER_DENIED`, `PERMISSION_DENIED` | Respect the decision and leave the feature idle |
|
|
152
|
+
| `NO_EXECUTABLE_MODEL`, `MODEL_NOT_EXECUTABLE` | Explain the unmet model/task requirement |
|
|
153
|
+
| `MODEL_OUT_OF_MEMORY`, `RESOURCE_REQUIREMENTS_UNSATISFIABLE` | Offer a smaller compatible model or lower supported settings |
|
|
154
|
+
| `JOB_QUEUE_FULL` | Keep the input and let the user retry later |
|
|
155
|
+
| `REQUEST_ABORTED`, `JOB_CANCELLED` | Treat cancellation as an ordinary outcome |
|
|
156
|
+
|
|
157
|
+
Browser/Engine failures are sanitized at the bridge. Application code and some local validation or network operations can also throw ordinary JavaScript errors, so retain a general error path.
|
|
158
|
+
|
|
159
|
+
## Task profiles and compatibility
|
|
160
|
+
|
|
161
|
+
Check `capabilities.features.taskProfiles` before opting into versioned task requirements. A returned `session.taskProfile` describes effective features, parameter bounds/defaults, limits, and streaming channels. Requirements must not silently disappear on an older browser; if a feature is necessary for your app, explain that it is unavailable.
|
|
162
|
+
|
|
163
|
+
`SharedTaskInputs`, `SharedTaskOutputs`, and `validateSharedTaskInput` support additional typed tasks. Their presence describes data contracts, not availability of a model on a particular device. See the [typed-task recipe](docs/recipes.md#use-a-typed-task-contract).
|
|
164
|
+
|
|
165
|
+
The npm version and `localAI.sdkVersion` identify the SDK. `browserApiVersion` identifies the injected browser API; task contracts carry their own revisions. Check feature flags and effective profiles instead of inferring support from the SDK version alone. The current `0.1.0` API is a developer alpha and may evolve before a stable release.
|
|
166
|
+
|
|
167
|
+
## Develop the SDK
|
|
168
|
+
|
|
169
|
+
From this directory:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pnpm install --frozen-lockfile
|
|
173
|
+
pnpm typecheck
|
|
174
|
+
pnpm test
|
|
175
|
+
pnpm build
|
|
176
|
+
pnpm pack
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The `dist` and `docs` directories, this README, and the MIT license are included in the package. Documentation examples are checked against the SDK types from the full workspace with `node scripts/check-public-docs.mjs`.
|
|
180
|
+
|
|
181
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) for API change requirements and [SECURITY.md](SECURITY.md) for sensitive reports.
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
Oryn SDK is licensed under the [MIT License](LICENSE).
|
package/SECURITY.md
ADDED