arcane-os 0.34.0 → 0.34.1

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.34.1
4
+
5
+ - Honor an optional request-local `model` in `AI.fetchRequest()` and
6
+ `AI.streamRequest()`. Direct and registered built-in TWiN/native Ollama
7
+ requests carry the supplied model without changing the shared selection.
8
+ Calls that omit the option retain the selected default.
9
+ - Preserve complete messages, streaming, tools, cancellation and request
10
+ observers. Provider-reported stream model metadata remains authoritative;
11
+ generated stream completion metadata falls back to the request's model.
12
+ The option does not load or switch a browser-WASM model.
13
+
3
14
  ## 0.34.0
4
15
 
5
16
  - Add `createDigitalOceanFalTTSProvider` through `arcane-os/ai/browser-speech`
package/README.md CHANGED
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
19
19
  `arcane/` runtime. Both profiles share the theme, packaging, event, cancellation,
20
20
  and browser run contracts while retaining their selected application layout.
21
21
 
22
- This checkout defines the `0.34.0` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.34.1` SDK contract. Applications pin one exact npm
23
23
  version and lockfile; registry state is deliberately not baked into application
24
24
  artifacts.
25
25
 
@@ -85,7 +85,7 @@ Create one browser application, install its pinned SDK, and start its source
85
85
  server:
86
86
 
87
87
  ```bash
88
- npx arcane-os@0.34.0 new hello-speech --path ./hello-speech --target browser
88
+ npx arcane-os@0.34.1 new hello-speech --path ./hello-speech --target browser
89
89
  cd hello-speech
90
90
  npm install
91
91
  ```
@@ -211,6 +211,38 @@ controller's `abort()` when the operation is cancelled or its page detaches.
211
211
  `streamRequest()` is the corresponding object-form streaming API. See the
212
212
  [AI module reference](../runtime-modules.md#aijs) for its complete options.
213
213
 
214
+ ## Use a model for one browser request
215
+
216
+ Both object-form methods accept `model` for that request. For example, an
217
+ application can use 20B for document search while retaining its configured
218
+ 120B conversation model:
219
+
220
+ ```javascript
221
+ const result = await ai.fetchRequest({
222
+ model: 'openai-gpt-oss-20b',
223
+ messages: searchMessages
224
+ });
225
+
226
+ await ai.streamRequest({
227
+ model: 'openai-gpt-oss-20b',
228
+ messages: summaryMessages,
229
+ onChunk: displaySummaryChunk
230
+ });
231
+ ```
232
+
233
+ `searchMessages`, `summaryMessages`, and `displaySummaryChunk` are supplied by
234
+ the application. Their content and callbacks keep their ordinary contracts.
235
+ The exact model goes into each TWiN request payload without changing `ai.model`
236
+ or selecting another provider. Concurrent calls can choose different models;
237
+ later calls that omit `model` (or pass `undefined`) use the configured model.
238
+ Retries keep the same request model. Provider-returned model metadata remains
239
+ authoritative; an assembled stream completion uses the request model only when
240
+ the response omits it.
241
+
242
+ The browser API forwards an explicitly supplied model to registered providers,
243
+ whose own request contract determines its meaning. This does not switch or
244
+ activate the loaded model of a browser-WASM provider.
245
+
214
246
  ## Migrate saved preference tuples before using them
215
247
 
216
248
  The six tuple slots consumed by `ai.setAI(...tuple)` are:
@@ -164,6 +164,21 @@ entry points. `streamMessage(...)` and `streamRequest(options)` deliver
164
164
  incremental responses. The positional and object forms share the existing
165
165
  provider implementations; neither form is a retired compatibility API.
166
166
 
167
+ `fetchRequest({model,...})` and `streamRequest({model,...})` accept an optional
168
+ request-local model. On the built-in TWiN Cloud route, its exact value becomes
169
+ the outbound `model` field; native Ollama receives the same request-local value.
170
+ Omitting it or passing `undefined` preserves the configured model. Each built-in
171
+ request captures its model before asynchronous callbacks, so concurrent requests
172
+ may use different models without assigning `ai.model`, changing provider
173
+ selection, or loading/unloading another model. Request observers and retries
174
+ receive that request's model. Stream/native completion metadata uses it only
175
+ when the provider omits its own `model` field.
176
+
177
+ Registered providers receive a supplied `model` unchanged in their request
178
+ payload; an omitted value remains absent. The provider owns interpretation.
179
+ This option does not switch a loaded browser-WASM model or its lifecycle:
180
+ explicit provider/model selection and activation remain necessary there.
181
+
167
182
  Built-in cloud chat decodes an HTTP error body once as JSON or text and rejects
168
183
  with that complete value unchanged. It does not reconstruct an Error, replace
169
184
  the message, or add `providerMessage`, `status`, or an SDK failure code to the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.34.0",
3
+ "version": "0.34.1",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -86,7 +86,7 @@
86
86
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
87
87
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
88
88
  "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
89
- "test:functional": "node ./bin/arcane-test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
89
+ "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
90
90
  "test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
91
91
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
92
92
  "check": "node tools/check-source.mjs && npm test",
@@ -4443,7 +4443,8 @@ class AI {
4443
4443
  function ignoreBuiltInLLMProviderRequest(){},
4444
4444
  signal,
4445
4445
  payload.reasoningEffort,
4446
- onRetry
4446
+ onRetry,
4447
+ payload.model
4447
4448
  );
4448
4449
  }
4449
4450
 
@@ -4474,7 +4475,8 @@ class AI {
4474
4475
  function ignoreBuiltInLLMStreamResult(){},
4475
4476
  payload.reasoningEffort,
4476
4477
  observeToolText,
4477
- onRetry
4478
+ onRetry,
4479
+ payload.model
4478
4480
  );
4479
4481
  }
4480
4482
 
@@ -4555,7 +4557,7 @@ class AI {
4555
4557
  });
4556
4558
  }
4557
4559
 
4558
- #openAICompatibleOllamaResponse(response={},id=Date.now()){
4560
+ #openAICompatibleOllamaResponse(response={},id=Date.now(),model=this.model){
4559
4561
  const responseRecord=isPlainAIRecord(response)?response:{};
4560
4562
  const message=isPlainAIRecord(responseRecord.message)
4561
4563
  ?responseRecord.message
@@ -4597,7 +4599,7 @@ class AI {
4597
4599
  :Math.floor(Date.now()/1000),
4598
4600
  model:Object.hasOwn(responseRecord,'model')
4599
4601
  ?responseRecord.model
4600
- :this.model,
4602
+ :model,
4601
4603
  choices:[
4602
4604
  {
4603
4605
  index:0,
@@ -4620,6 +4622,7 @@ class AI {
4620
4622
 
4621
4623
  async streamRequest({
4622
4624
  messages=[],
4625
+ model,
4623
4626
  structuredOutput=false,
4624
4627
  localOnly=false,
4625
4628
  onChunk=function ignoreStreamChunk(){},
@@ -4676,6 +4679,7 @@ class AI {
4676
4679
  if(this.#shouldUseProviderRuntime('llm',this.llmService,localOnly)){
4677
4680
  const request={
4678
4681
  messages,
4682
+ ...(model!==undefined?{model}:{}),
4679
4683
  structuredOutput,
4680
4684
  tools,
4681
4685
  toolChoice,
@@ -4801,7 +4805,8 @@ class AI {
4801
4805
  onDataResult,
4802
4806
  normalizedReasoningEffort,
4803
4807
  observeToolText,
4804
- onRetry
4808
+ onRetry,
4809
+ model
4805
4810
  );
4806
4811
  const structuralToolCalls=normalizeAICompletionToolCalls(
4807
4812
  completion
@@ -4910,7 +4915,8 @@ class AI {
4910
4915
  dataResultHandler=function ignoreBuiltInStreamDataResult(){},
4911
4916
  reasoningEffort,
4912
4917
  observeToolText=null,
4913
- onRetry = null
4918
+ onRetry = null,
4919
+ model=this.model
4914
4920
  ){
4915
4921
  let speechTurnCompleted=false;
4916
4922
 
@@ -4934,7 +4940,7 @@ class AI {
4934
4940
  reasoningEffort===undefined?this.reasoningEffort:reasoningEffort
4935
4941
  );
4936
4942
  const request={
4937
- model:this.model,
4943
+ model,
4938
4944
  messages:messages,
4939
4945
  stream:true
4940
4946
  }
@@ -4981,7 +4987,7 @@ class AI {
4981
4987
  const ollamaMessages=this.#ollamaMessages(messages,tool_choice);
4982
4988
  const adaptNativeToolCalls=value=>this.#openAICompatibleOllamaToolCalls(value,id);
4983
4989
  const ollamaRequest={
4984
- model:this.model,
4990
+ model,
4985
4991
  messages:ollamaMessages,
4986
4992
  stream:true,
4987
4993
  ...(normalizedReasoningEffort
@@ -5091,7 +5097,8 @@ class AI {
5091
5097
  :nativeContent
5092
5098
  }
5093
5099
  },
5094
- id
5100
+ id,
5101
+ model
5095
5102
  );
5096
5103
  const structuralToolCalls=normalizeAICompletionToolCalls(
5097
5104
  nativeCompletion
@@ -5583,7 +5590,7 @@ class AI {
5583
5590
  created:Object.hasOwn(streamMetadata,'created')
5584
5591
  ?streamMetadata.created
5585
5592
  :Math.floor(Date.now()/1000),
5586
- model:Object.hasOwn(streamMetadata,'model')?streamMetadata.model:this.model,
5593
+ model:Object.hasOwn(streamMetadata,'model')?streamMetadata.model:model,
5587
5594
  choices:completionChoices
5588
5595
  };
5589
5596
  const terminalToolCalls=normalizeAICompletionToolCalls(completion);
@@ -5628,6 +5635,7 @@ class AI {
5628
5635
 
5629
5636
  async fetchRequest({
5630
5637
  messages=[],
5638
+ model,
5631
5639
  structuredOutput=false,
5632
5640
  localOnly=false,
5633
5641
  tools=[],
@@ -5670,6 +5678,7 @@ class AI {
5670
5678
  }
5671
5679
  const request={
5672
5680
  messages,
5681
+ ...(model!==undefined?{model}:{}),
5673
5682
  structuredOutput,
5674
5683
  tools,
5675
5684
  toolChoice,
@@ -5726,7 +5735,8 @@ class AI {
5726
5735
  onRequest,
5727
5736
  signal,
5728
5737
  normalizedReasoningEffort,
5729
- onRetry
5738
+ onRetry,
5739
+ model
5730
5740
  );
5731
5741
  }
5732
5742
 
@@ -5780,7 +5790,8 @@ class AI {
5780
5790
  requestHandler=function ignoreFetchRequest(){},
5781
5791
  signal=null,
5782
5792
  reasoningEffort,
5783
- onRetry = null
5793
+ onRetry = null,
5794
+ model=this.model
5784
5795
  ){
5785
5796
  validateAIStructuralRequest(messages,tools,parallel_tool_calls);
5786
5797
  this.#assertServiceConfigured(this.llmService);
@@ -5799,7 +5810,7 @@ class AI {
5799
5810
  reasoningEffort===undefined?this.reasoningEffort:reasoningEffort
5800
5811
  );
5801
5812
  const request={
5802
- model:this.model,
5813
+ model,
5803
5814
  messages:messages,
5804
5815
  stream:false
5805
5816
  }
@@ -5838,7 +5849,7 @@ class AI {
5838
5849
  const ollamaTools=this.#ollamaTools(tools,tool_choice);
5839
5850
  const ollamaMessages=this.#ollamaMessages(messages,tool_choice);
5840
5851
  const nativeRequest={
5841
- model:this.model,
5852
+ model,
5842
5853
  messages:ollamaMessages,
5843
5854
  stream:false,
5844
5855
  ...(normalizedReasoningEffort
@@ -5869,7 +5880,8 @@ class AI {
5869
5880
  }
5870
5881
  const responseJSON=this.#openAICompatibleOllamaResponse(
5871
5882
  nativeResponse,
5872
- id
5883
+ id,
5884
+ model
5873
5885
  );
5874
5886
  this.#assertRequiredOllamaToolCall(
5875
5887
  normalizeAICompletionToolCalls(responseJSON),