arcane-os 0.5.10 → 0.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +117 -26
- package/browser-runtime/ai/browser-speech-providers.mjs +1 -1
- package/docs/architecture.md +303 -0
- package/docs/compatibility.md +38 -0
- package/docs/event-manager.md +263 -0
- package/docs/platform-targets.md +104 -0
- package/docs/publishing.md +126 -0
- package/docs/reference/README.md +206 -0
- package/docs/reference/ai/browser-speech.md +879 -0
- package/docs/reference/ai/browser-wasm.md +637 -0
- package/docs/reference/ai/twin-cloud.md +156 -0
- package/docs/reference/arcane-ollama.md +288 -0
- package/docs/reference/availability-and-normalization.md +224 -0
- package/docs/reference/behavioral-testing.md +129 -0
- package/docs/reference/cli.md +820 -0
- package/docs/reference/core/README.md +61 -0
- package/docs/reference/core/arcane-ai-contracts.md +906 -0
- package/docs/reference/core/arcane-api.md +601 -0
- package/docs/reference/core/arcane-entities.md +59 -0
- package/docs/reference/core/arcane-events.md +134 -0
- package/docs/reference/core/ollama-module.md +181 -0
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
- package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
- package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
- package/docs/reference/event-manager.md +1409 -0
- package/docs/reference/inventory/package-api.json +3194 -0
- package/docs/reference/inventory/runtime-components.json +1015 -0
- package/docs/reference/inventory/runtime-entities.json +25 -0
- package/docs/reference/inventory/runtime-modules.json +1367 -0
- package/docs/reference/mail.md +309 -0
- package/docs/reference/protocols.md +749 -0
- package/docs/reference/runtime-components.md +1532 -0
- package/docs/reference/runtime-entities.md +305 -0
- package/docs/reference/runtime-modules.md +3310 -0
- package/docs/reference/sdk-api.md +6733 -0
- package/docs/roadmap.md +79 -0
- package/docs/work-amplification.md +66 -0
- package/examples/wasm-ai-demo/README.md +80 -0
- package/examples/wasm-ai-demo/app.js +787 -0
- package/examples/wasm-ai-demo/index.html +343 -0
- package/examples/wasm-ai-demo/profile-tools.js +217 -0
- package/examples/wasm-ai-demo/profiles/BOSS.Modelfile +106 -0
- package/examples/wasm-ai-demo/profiles/PreCrisis.Modelfile +693 -0
- package/examples/wasm-ai-demo/rag/boss-library.json +3006 -0
- package/examples/wasm-ai-demo/rag.js +295 -0
- package/examples/wasm-ai-demo/server.mjs +71 -0
- package/package.json +10 -1
- package/runtime/arcane/modules/AI.js +60 -11
- package/runtime/arcane/modules/AIProviderRuntime.js +26 -5
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# TWiN Cloud: one request
|
|
2
|
+
|
|
3
|
+
TWiN Cloud is the high-level `AI.js` default remote LLM service, named `TWIN`.
|
|
4
|
+
Speech stays on device and does not use the TWiN access key. This guide uses the
|
|
5
|
+
same managed browser imports as the [browser speech quick start](browser-speech.md).
|
|
6
|
+
|
|
7
|
+
## Install and import
|
|
8
|
+
|
|
9
|
+
Create an application and start its source server:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx arcane-os@0.5.12 new hello-twin --path ./hello-twin --target browser
|
|
13
|
+
cd hello-twin
|
|
14
|
+
npm install
|
|
15
|
+
npm run dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Keep the generated Arcane theme and import map. Place the JavaScript below in
|
|
19
|
+
`apps/hello-twin/modules/App.js`. Run it in the served browser page, not Node.
|
|
20
|
+
This first example is for the new application created above. An existing
|
|
21
|
+
application must complete the saved-preference migration below before importing
|
|
22
|
+
`arcane/AI` or any module that imports it.
|
|
23
|
+
|
|
24
|
+
## Supply the key at runtime and display the response
|
|
25
|
+
|
|
26
|
+
`applicationRuntime` is the **one application-supplied placeholder** in this
|
|
27
|
+
example. It represents the authenticated host/application configuration that
|
|
28
|
+
supplies a `twinKey` at runtime. Replace the placeholder with your existing
|
|
29
|
+
configuration source; do not put a real key in this module, Git, or diagnostics.
|
|
30
|
+
The SDK also reads `globalThis.arcane.config.twinCloud.accessKey` when present.
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import arcaneThemeReady from 'arcane/ThemeBootstrap';
|
|
34
|
+
|
|
35
|
+
await arcaneThemeReady;
|
|
36
|
+
// In an upgrade bootstrap, the existing preference owner's migration must
|
|
37
|
+
// already be complete before this dynamic import evaluates AI.js.
|
|
38
|
+
const { default: AI } = await import('arcane/AI');
|
|
39
|
+
const applicationRuntime = globalThis.applicationRuntime;
|
|
40
|
+
const ai = new AI();
|
|
41
|
+
ai.twinKey = applicationRuntime.twinKey;
|
|
42
|
+
|
|
43
|
+
const button = document.createElement('button');
|
|
44
|
+
button.textContent = 'Ask TWiN';
|
|
45
|
+
const output = document.createElement('pre');
|
|
46
|
+
output.style.whiteSpace = 'pre-wrap';
|
|
47
|
+
document.body.append(button, output);
|
|
48
|
+
|
|
49
|
+
button.addEventListener('click', async function askTwin() {
|
|
50
|
+
button.disabled = true;
|
|
51
|
+
output.textContent = 'Thinking';
|
|
52
|
+
try {
|
|
53
|
+
const response = await ai.fetchRequest({
|
|
54
|
+
messages: [{ role: 'user', content: 'Say hello in one sentence.' }]
|
|
55
|
+
});
|
|
56
|
+
output.textContent = JSON.stringify(response, null, 2);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
output.textContent = `${error.code ?? 'ERROR'}\n${error.message}`;
|
|
59
|
+
} finally {
|
|
60
|
+
button.disabled = false;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The example displays the complete returned response so its actual fields are
|
|
66
|
+
visible. It makes one `fetchRequest()` per click. A normal `new AI()` selects
|
|
67
|
+
TWiN Cloud and its default model, `openai-gpt-oss-120b`; assigning `twinKey`
|
|
68
|
+
reconciles that remote route's readiness. No browser speech model is loaded by
|
|
69
|
+
this request. `ai.license` remains an alias of `ai.twinKey` for existing callers.
|
|
70
|
+
|
|
71
|
+
For an application-owned cancellation control, pass a fresh
|
|
72
|
+
`AbortController`'s `signal` to `fetchRequest({messages,signal})` and call that
|
|
73
|
+
controller's `abort()` when the operation is cancelled or its page detaches.
|
|
74
|
+
`streamRequest()` is the corresponding object-form streaming API. See the
|
|
75
|
+
[AI module reference](../runtime-modules.md#aijs) for its complete options.
|
|
76
|
+
|
|
77
|
+
## Migrate saved preference tuples before using them
|
|
78
|
+
|
|
79
|
+
The six tuple slots consumed by `ai.setAI(...tuple)` are:
|
|
80
|
+
|
|
81
|
+
| Slot | Meaning | Migration |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| 0 | LLM provider | Exact uppercase `OPENAI` becomes `TWIN`. |
|
|
84
|
+
| 1 | STT provider | Preserve. |
|
|
85
|
+
| 2 | TTS provider | Preserve. |
|
|
86
|
+
| 3 | LLM model or default-model sentinel | Exact uppercase `OPENAI` becomes `TWIN`. |
|
|
87
|
+
| 4 | TTS model | Preserve. |
|
|
88
|
+
| 5 | STT model | Preserve. |
|
|
89
|
+
|
|
90
|
+
Use this narrow transformation in the application's existing preference loader:
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
function migrateSavedAISelection(savedTuple) {
|
|
94
|
+
return savedTuple.map(function migrateProviderOrDefault(value, slot) {
|
|
95
|
+
return (slot === 0 || slot === 3) && value === 'OPENAI' ? 'TWIN' : value;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const savedTuple = [
|
|
100
|
+
'OPENAI', 'LOCAL_SPEACH', 'LOCAL_SPEACH',
|
|
101
|
+
'OPENAI', 'LOCAL_SPEACH', 'LOCAL_SPEACH'
|
|
102
|
+
];
|
|
103
|
+
const migratedTuple = migrateSavedAISelection(savedTuple);
|
|
104
|
+
console.log(migratedTuple);
|
|
105
|
+
// ['TWIN', 'LOCAL_SPEACH', 'LOCAL_SPEACH', 'TWIN', 'LOCAL_SPEACH', 'LOCAL_SPEACH']
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
In the application's upgrade bootstrap, read saved settings, run this
|
|
109
|
+
transformation, and complete the write through the **existing application
|
|
110
|
+
preference owner before importing `AI.js` or any module that imports it**.
|
|
111
|
+
Ensure that owner also exposes the migrated tuple to the current page before
|
|
112
|
+
continuing. Use the application's actual storage/readiness operations; the SDK
|
|
113
|
+
does not supply a new migration storage API.
|
|
114
|
+
|
|
115
|
+
This ordering matters during module evaluation: `AI.js` installs its
|
|
116
|
+
user-readiness handler immediately. If `window.user.ready` is already true, it
|
|
117
|
+
can immediately read that user's preference tuple and construct `window.ai`.
|
|
118
|
+
Waiting until a later `setAI()`, provider-startup call, or button click is too
|
|
119
|
+
late. A static `import AI from 'arcane/AI'` evaluates before the surrounding
|
|
120
|
+
module body, even if its text appears below migration code. Keep AI and its
|
|
121
|
+
importing modules out of the bootstrap's static import graph, finish the
|
|
122
|
+
existing owner's migration, then cross the dynamic-import boundary:
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
// Place these lines after the application's existing preference migration
|
|
126
|
+
// has finished writing and exposing migratedTuple, not before that operation.
|
|
127
|
+
const { default: AI } = await import('arcane/AI');
|
|
128
|
+
const ai = new AI(...migratedTuple);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Here `migratedTuple` is the result of the exact transformation shown above,
|
|
132
|
+
using the real saved tuple in the application's bootstrap. Configure browser
|
|
133
|
+
speech only after this initialization. Migration belongs to upgrade startup;
|
|
134
|
+
do not inject it into an in-flight request. For later changes to an already
|
|
135
|
+
valid active selection, `await ai.transitionAI(...migratedTuple)` remains the
|
|
136
|
+
asynchronous lifecycle; it unloads roles and disposes SDK-owned browser speech,
|
|
137
|
+
so configure desired speech afterward. It is not a substitute for migration
|
|
138
|
+
before the first AI import.
|
|
139
|
+
|
|
140
|
+
The SDK deliberately has no built-in `OPENAI` alias and performs no saved-data
|
|
141
|
+
migration. This guide does not instruct a rewrite of chat history or unrelated
|
|
142
|
+
settings. Preserve every tuple value except those two exact sentinel matches.
|
|
143
|
+
In particular, do not change:
|
|
144
|
+
|
|
145
|
+
- `openai-gpt-oss-120b` or `openai-gpt-oss-20b`: actual upstream model IDs;
|
|
146
|
+
- OpenAI-compatible chat-completion wire terminology; or
|
|
147
|
+
- Core's separate `provider:'openai'` behavior and public native contract.
|
|
148
|
+
|
|
149
|
+
TWiN's default-model sentinel `TWIN` resolves to `openai-gpt-oss-120b`.
|
|
150
|
+
An explicitly saved `openai-gpt-oss-20b` in slot 3 stays that exact model.
|
|
151
|
+
|
|
152
|
+
## Related
|
|
153
|
+
|
|
154
|
+
- [Browser speech quick start and streaming](browser-speech.md)
|
|
155
|
+
- [Normalized AI and readiness](../README.md#normalized-ai)
|
|
156
|
+
- [Core AI contracts](../core/arcane-ai-contracts.md)
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Arcane Ollama
|
|
2
|
+
|
|
3
|
+
Arcane Ollama lets an admitted application use local Ollama without knowing the
|
|
4
|
+
service port, service account, model directory, host process, or native
|
|
5
|
+
transport. Application code imports one browser module and calls one API:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import ollama from '/arcane/modules/Ollama.js';
|
|
9
|
+
|
|
10
|
+
const reply = await ollama.chatText({
|
|
11
|
+
model: 'arcane:latest',
|
|
12
|
+
messages: [{role: 'user', content: 'Summarize this record.'}]
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
console.log(reply);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The module never connects directly to `localhost:11434`. It delegates to the
|
|
19
|
+
capability-gated `globalThis.Arcane.ollama` bridge. Core binds application
|
|
20
|
+
identity, checks the exact method and package-owned model policy, admits native
|
|
21
|
+
resources, and calls the managed ArcaneOllama service.
|
|
22
|
+
|
|
23
|
+
This npm package exposes the synchronized browser client only. It does not
|
|
24
|
+
bundle, install, start, or grant an Arcane Core or ArcaneOllama service. Every
|
|
25
|
+
native call therefore requires a separately installed, compatible Arcane host,
|
|
26
|
+
an app-scoped admitted Core session, the required capabilities, and a service
|
|
27
|
+
that is ready under native policy. Import success alone proves none of those
|
|
28
|
+
conditions.
|
|
29
|
+
|
|
30
|
+
## What developers can do
|
|
31
|
+
|
|
32
|
+
| Capability | Preferred call | Result style |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| Check whether the admitted service answers | `ollama.readiness()` | Arcane-normalized frozen readiness snapshot |
|
|
35
|
+
| Generate text | `ollama.generateText(request)` | Arcane helper string |
|
|
36
|
+
| Chat and return only assistant text | `ollama.chatText(request)` | Arcane helper string |
|
|
37
|
+
| Use full generation/chat/tool/provider fields | `ollama.generate()` / `ollama.chat()` | Bounded Ollama provider-native envelope |
|
|
38
|
+
| Create embeddings | `ollama.embed()` | Bounded Ollama provider-native envelope |
|
|
39
|
+
| Read raw version/model/running/show inventory | `version()`, `models()`, `list()`, `running()`, `show()` | Provider-native diagnostic envelope |
|
|
40
|
+
| Unload one model | `ollama.unload(model)` | Translates to generate with `prompt: ""` and `keep_alive: 0` |
|
|
41
|
+
| Read managed selection/runtime/service settings | `selection()`, `settings()`, `serviceSettings()` | Arcane-managed snapshot; some service fields are platform-dependent |
|
|
42
|
+
| Change managed selection/runtime/service settings | `select()`, `saveSettings()`, `saveServiceSettings()` | Arcane-managed result plus operation receipt |
|
|
43
|
+
| Run admitted raw model mutations | `pull()`, `push()`, `create()`, `copy()`, `delete()` | Policy-bound provider-native result; several calls are intentionally denied to ordinary apps |
|
|
44
|
+
| Create an Arcane-managed brain alias | `createBrain()` | Arcane-managed model/default result plus operation receipt |
|
|
45
|
+
|
|
46
|
+
## Fast start
|
|
47
|
+
|
|
48
|
+
### 1. Feature-detect the module
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import ollama from '/arcane/modules/Ollama.js';
|
|
52
|
+
|
|
53
|
+
const readiness = await ollama.readiness();
|
|
54
|
+
|
|
55
|
+
if (!readiness.ready) {
|
|
56
|
+
console.info('Local AI is unavailable:', readiness.errorCode);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`readiness()` catches a failed `version()` call and returns a frozen object:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
{ ready: boolean, version: string|null, errorCode: string|null }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It is a connectivity convenience, not model admission or inference readiness.
|
|
67
|
+
Use `Arcane.localAI.status()` when the application needs the package-filtered
|
|
68
|
+
runnable model catalog.
|
|
69
|
+
|
|
70
|
+
### 2. Read admitted models
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const access = await globalThis.Arcane.capabilities.list();
|
|
74
|
+
|
|
75
|
+
if (!access.methods.includes('localAI.status')) {
|
|
76
|
+
throw new Error('This application is not admitted for local AI.');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const status = await globalThis.Arcane.localAI.status();
|
|
80
|
+
console.table(status.models.ollama);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Populate product UI from this filtered catalog. `ollama.models()` is the raw
|
|
84
|
+
diagnostic inventory for admitted Settings, Shell, or Terminal journeys; it is
|
|
85
|
+
not the application's package-admitted model list.
|
|
86
|
+
|
|
87
|
+
### 3. Stream a chat response
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
let text = '';
|
|
91
|
+
|
|
92
|
+
const final = await ollama.chat({
|
|
93
|
+
model: 'arcane:latest',
|
|
94
|
+
messages: [{role: 'user', content: 'Explain the evidence.'}]
|
|
95
|
+
}, {
|
|
96
|
+
onChunk(chunk) {
|
|
97
|
+
text += chunk.message?.content ?? '';
|
|
98
|
+
},
|
|
99
|
+
signal: AbortSignal.timeout(60_000)
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
console.log(text, final.done);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Arcane correlates chunks to the originating request. The final promise resolves
|
|
106
|
+
with Ollama's final bounded chunk/envelope.
|
|
107
|
+
|
|
108
|
+
## Complete module API
|
|
109
|
+
|
|
110
|
+
`/arcane/modules/Ollama.js` exports the `Ollama` class, a frozen `ollama`
|
|
111
|
+
singleton, and that singleton as the default export. It also installs the
|
|
112
|
+
non-writable `globalThis.arcaneOllama` convenience and emits
|
|
113
|
+
`arcane-ollama-ready`. The pinned class defines exactly 24 public methods: the
|
|
114
|
+
20 bridge delegates below and the four normalized helpers that follow.
|
|
115
|
+
|
|
116
|
+
### Raw bridge methods
|
|
117
|
+
|
|
118
|
+
| Module method | Delegation | Capability/use | Detailed Core guide |
|
|
119
|
+
| --- | --- | --- | --- |
|
|
120
|
+
| `version()` | `Arcane.ollama.version()` | Raw service version diagnostic. | [version](core/reference/arcane-api/ai-and-ollama.md#arcaneollamaversion) |
|
|
121
|
+
| `models()` | `Arcane.ollama.models()` | Raw installed-model diagnostic. | [models](core/reference/arcane-api/ai-and-ollama.md#arcaneollamamodels) |
|
|
122
|
+
| `list()` | Calls `Arcane.ollama.models()` | Module alias for `models()`; it does not call the bridge's separate `list` alias. | [list](core/reference/arcane-api/ai-and-ollama.md#arcaneollamalist) |
|
|
123
|
+
| `running()` | `Arcane.ollama.running()` | Raw resident-model diagnostic. | [running](core/reference/arcane-api/ai-and-ollama.md#arcaneollamarunning) |
|
|
124
|
+
| `show(model, options)` | `Arcane.ollama.show(...)` | Raw bounded model metadata. | [show](core/reference/arcane-api/ai-and-ollama.md#arcaneollamashow) |
|
|
125
|
+
| `generate(request, options)` | `Arcane.ollama.generate(...)` | Admitted generation; optional chunk callback/signal/timeout. | [generate](core/reference/arcane-api/ai-and-ollama.md#arcaneollamagenerate) |
|
|
126
|
+
| `chat(request, options)` | `Arcane.ollama.chat(...)` | Admitted chat/tools; optional chunk callback/signal/timeout. | [chat](core/reference/arcane-api/ai-and-ollama.md#arcaneollamachat) |
|
|
127
|
+
| `embed(request)` | `Arcane.ollama.embed(...)` | Admitted embeddings. | [embed](core/reference/arcane-api/ai-and-ollama.md#arcaneollamaembed) |
|
|
128
|
+
| `pull(model, options, streamOptions)` | `Arcane.ollama.pull(...)` | Managed/policy-bound pull; denied to ordinary raw app flow. | [pull](core/reference/arcane-api/ai-and-ollama.md#arcaneollamapull) |
|
|
129
|
+
| `push(model, options, streamOptions)` | `Arcane.ollama.push(...)` | Raw push is policy-restricted/denied where documented. | [push](core/reference/arcane-api/ai-and-ollama.md#arcaneollamapush) |
|
|
130
|
+
| `create(request, options)` | `Arcane.ollama.create(...)` | Exact package-owned verified definition only. | [create](core/reference/arcane-api/ai-and-ollama.md#arcaneollamacreate) |
|
|
131
|
+
| `copy(source, destination)` | `Arcane.ollama.copy(...)` | Intentionally denied to applications; managed selection owns aliases. | [copy](core/reference/arcane-api/ai-and-ollama.md#arcaneollamacopy) |
|
|
132
|
+
| `delete(model)` | `Arcane.ollama.delete(...)` | Destructive exact package-owned verified model deletion. | [delete](core/reference/arcane-api/ai-and-ollama.md#arcaneollamadelete) |
|
|
133
|
+
| `selection()` | `Arcane.ollama.selection()` | Reads managed model preference/effective state. | [selection](core/reference/arcane-api/ai-and-ollama.md#arcaneollamaselection) |
|
|
134
|
+
| `select(preference)` | `Arcane.ollama.select(...)` | Runs managed size-selection/download/alias workflow. | [select](core/reference/arcane-api/ai-and-ollama.md#arcaneollamaselect) |
|
|
135
|
+
| `settings()` | `Arcane.ollama.settings()` | Reads managed runtime/provider settings. | [settings](core/reference/arcane-api/ai-and-ollama.md#arcaneollamasettings) |
|
|
136
|
+
| `saveSettings(settings)` | `Arcane.ollama.saveSettings(...)` | Saves runtime-owned default/load/context settings. | [saveSettings](core/reference/arcane-api/ai-and-ollama.md#arcaneollamasavesettings) |
|
|
137
|
+
| `createBrain(definition)` | `Arcane.ollama.createBrain(...)` | Creates a managed `arcane-<slug>:latest` alias. | [createBrain](core/reference/arcane-api/ai-and-ollama.md#arcaneollamacreatebrain) |
|
|
138
|
+
| `serviceSettings()` | `Arcane.ollama.serviceSettings()` | Reads host-level Ollama service configuration/support. | [serviceSettings](core/reference/arcane-api/ai-and-ollama.md#arcaneollamaservicesettings) |
|
|
139
|
+
| `saveServiceSettings(settings)` | `Arcane.ollama.saveServiceSettings(...)` | Applies privileged machine-wide service settings/restart. | [saveServiceSettings](core/reference/arcane-api/ai-and-ollama.md#arcaneollamasaveservicesettings) |
|
|
140
|
+
|
|
141
|
+
### Normalized helper methods
|
|
142
|
+
|
|
143
|
+
## `ollama.readiness()`
|
|
144
|
+
|
|
145
|
+
### Overview
|
|
146
|
+
|
|
147
|
+
Calls `version()` and converts success/failure into a frozen readiness snapshot.
|
|
148
|
+
It never throws for service unavailability.
|
|
149
|
+
|
|
150
|
+
### Return value
|
|
151
|
+
|
|
152
|
+
`{ready:true, version, errorCode:null}` on success, or
|
|
153
|
+
`{ready:false, version:null, errorCode}` on failure. A string version and an
|
|
154
|
+
object `{version}` are both accepted.
|
|
155
|
+
|
|
156
|
+
### Example
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const {ready, version, errorCode} = await ollama.readiness();
|
|
160
|
+
console.log(ready ? version : errorCode);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## `ollama.generateText()`
|
|
164
|
+
|
|
165
|
+
### Overview
|
|
166
|
+
|
|
167
|
+
Calls `generate()` and coerces the final envelope's `response` field to a
|
|
168
|
+
string with `String(response?.response || '')`. Valid Ollama responses document
|
|
169
|
+
`response` as a string. If an out-of-contract response supplies a truthy
|
|
170
|
+
nonstring, the helper stringifies it; a missing, null, undefined, or other
|
|
171
|
+
falsy nonstring value becomes an empty string.
|
|
172
|
+
|
|
173
|
+
### Example
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
const text = await ollama.generateText({
|
|
177
|
+
model: 'arcane:latest',
|
|
178
|
+
prompt: 'Write one sentence.'
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## `ollama.chatText()`
|
|
183
|
+
|
|
184
|
+
### Overview
|
|
185
|
+
|
|
186
|
+
Calls `chat()` and coerces the final envelope's `message.content` field to a
|
|
187
|
+
string with `String(response?.message?.content || '')`. Valid Ollama responses
|
|
188
|
+
document `message.content` as a string. If an out-of-contract response supplies
|
|
189
|
+
a truthy nonstring, the helper stringifies it; a missing, null, undefined, or
|
|
190
|
+
other falsy nonstring value becomes an empty string. Use `chat()` when tool
|
|
191
|
+
calls, metrics, context, or optional provider fields matter.
|
|
192
|
+
|
|
193
|
+
### Example
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
const text = await ollama.chatText({
|
|
197
|
+
model: 'arcane:latest',
|
|
198
|
+
messages: [{role: 'user', content: 'Hello'}]
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## `ollama.unload()`
|
|
203
|
+
|
|
204
|
+
### Overview
|
|
205
|
+
|
|
206
|
+
Translates `unload(model)` to:
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
ollama.generate({model, prompt: '', keep_alive: 0});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
It returns the raw final generation envelope. It is a convenience request, not
|
|
213
|
+
a proof that no other admitted client reloaded the model concurrently.
|
|
214
|
+
|
|
215
|
+
### Example
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
async function unloadAfterTheUserChooses(model) {
|
|
219
|
+
return ollama.unload(model);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Availability matrix
|
|
224
|
+
|
|
225
|
+
| Host | Inference | Raw inventory | Managed model/settings mutation | Notes |
|
|
226
|
+
| --- | --- | --- | --- | --- |
|
|
227
|
+
| Microsoft NT desktop Core | Yes when `ai.inference` is admitted | Settings/Shell/Terminal with `ai.models.read` | Admitted Settings/Shell journeys with management capabilities and privilege where required | Full managed ArcaneOllama service path. |
|
|
228
|
+
| Linux desktop Core | Yes when admitted | Admitted diagnostics | Managed workflows where implemented; administrator-owned service settings can return manual/unsupported guidance | Same application API, different host/service implementation. |
|
|
229
|
+
| Android WebView | Narrow admitted chat/inference projection for configured user-managed loopback | No general desktop raw inventory | No desktop model/service management | `managedLocalAI` remains false; listener reachability is not management authority. |
|
|
230
|
+
| Development HTTP bridge | Only when connected to an admitted Core-backed development host | Host/method dependent | Host/method dependent; never production authority | Development transport, not a standalone-browser upgrade. |
|
|
231
|
+
| Standalone browser | No Arcane Ollama | No | No | `ARCANE_OLLAMA_UNAVAILABLE`. |
|
|
232
|
+
| TWiN Cloud | Not through `Arcane.ollama` | No | No | Use an explicitly selected `AI.js` cloud profile; no automatic fallback. |
|
|
233
|
+
|
|
234
|
+
## Capabilities and policy
|
|
235
|
+
|
|
236
|
+
- `ai.inference` admits package-filtered local generation, chat, and embeddings.
|
|
237
|
+
- `ai.models.read` admits raw model diagnostics only to authorized system apps.
|
|
238
|
+
- `ai.models.manage` admits policy-bound managed model lifecycle operations.
|
|
239
|
+
- `ai.settings.manage` admits Settings-owned runtime/service configuration.
|
|
240
|
+
- `ai.models.unverified.inference` is an explicit inference-only exception for
|
|
241
|
+
already installed, hardware-admitted unverified models when the package says
|
|
242
|
+
`verified_only:false`; it does not admit model mutation.
|
|
243
|
+
|
|
244
|
+
The method allowlist is necessary but not sufficient. Exact package-owned model
|
|
245
|
+
definitions, reserved aliases, native resources, platform support, installed
|
|
246
|
+
state, and exclusive mutation policy remain authoritative.
|
|
247
|
+
|
|
248
|
+
## Raw versus normalized behavior
|
|
249
|
+
|
|
250
|
+
The module intentionally has two levels:
|
|
251
|
+
|
|
252
|
+
| Boundary | Normalized by Arcane | Intentionally preserved |
|
|
253
|
+
| --- | --- | --- |
|
|
254
|
+
| Missing bridge | Throws coded `ARCANE_OLLAMA_UNAVAILABLE`. | Nothing reaches a provider. |
|
|
255
|
+
| Core call | Promise settlement, capability/policy errors, request limits, diagnostics, stream ids/chunks. | Bounded Ollama success fields and optional provider detail. |
|
|
256
|
+
| `readiness()` | Frozen Boolean/version/error-code snapshot. | Provider error detail is reduced to `errorCode`. |
|
|
257
|
+
| `generateText()` / `chatText()` | Uses `String(value || '')`: documented string values pass through, truthy nonstrings stringify, and falsy nonstrings become empty. | Tool calls, timings, context, and other fields are discarded. |
|
|
258
|
+
| `unload()` | Stable translation to `keep_alive:0`. | Final generation envelope remains provider-native. |
|
|
259
|
+
|
|
260
|
+
## Streaming, cancellation, and uncertain mutation state
|
|
261
|
+
|
|
262
|
+
`generate`, `chat`, `pull`, `push`, and `create` accept stream controls through
|
|
263
|
+
the bridge forms documented on their detailed pages. Core cooperatively cancels
|
|
264
|
+
admitted inference methods where documented. For pull, push, create, selection,
|
|
265
|
+
settings, or service mutation, abort/timeout/page teardown can stop renderer
|
|
266
|
+
observation without proving host work rolled back.
|
|
267
|
+
|
|
268
|
+
After an uncertain model mutation, refresh the relevant raw inventory,
|
|
269
|
+
`selection()`, `settings()`, `serviceSettings()`, or `localAI.status()` before
|
|
270
|
+
retrying. Do not stack a second mutation merely because the renderer timed out.
|
|
271
|
+
|
|
272
|
+
## Behavioral testing
|
|
273
|
+
|
|
274
|
+
The SDK behavior suite uses an explicit fake `Arcane.ollama` to prove:
|
|
275
|
+
|
|
276
|
+
- every wrapper forwards the exact argument objects and provider-native result;
|
|
277
|
+
- stream options and signals are not rewritten;
|
|
278
|
+
- bridge absence throws `ARCANE_OLLAMA_UNAVAILABLE` before provider work;
|
|
279
|
+
- `readiness()` returns frozen success/failure snapshots;
|
|
280
|
+
- `generateText()` and `chatText()` use the pinned `String(value || '')`
|
|
281
|
+
behavior: truthy nonstrings stringify and falsy nonstrings become empty;
|
|
282
|
+
- `unload()` sends exactly `{model, prompt: "", keep_alive: 0}`.
|
|
283
|
+
|
|
284
|
+
Those tests prove the shipped renderer module. Live Core dispatch, cancellation,
|
|
285
|
+
ArcaneOllama health, real model pulls, GPU admission, service restart, and
|
|
286
|
+
rollback remain Arcane OS host/integration evidence.
|
|
287
|
+
|
|
288
|
+
Deep implementation path: [Arcane Ollama protocol](protocols.md#arcane-ollama-protocol-path).
|