arcane-os 0.33.5 → 0.33.6

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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.33.6
4
+
5
+ - Resume transcript bottom-follow when an accepted non-synthetic user message
6
+ is sent, including when the reader had scrolled upward. Preserve reading
7
+ position for incoming content, synthetic requests, and canceled submissions.
8
+ - Keep HTTP 529 on its existing bounded retry path when reading its diagnostic
9
+ body fails. Preserve the actual parser or body-read error in retry observations
10
+ and final failure, with cancellation and other HTTP behavior unchanged.
11
+
3
12
  ## 0.33.5
4
13
 
5
14
  - Deliver the first visible streamed chat chunk to speech exactly once, without
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.33.5` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.33.6` 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.33.5 new hello-speech --path ./hello-speech --target browser
88
+ npx arcane-os@0.33.6 new hello-speech --path ./hello-speech --target browser
89
89
  cd hello-speech
90
90
  npm install
91
91
  ```
@@ -170,16 +170,23 @@ export async function fetchHTTPResponse(url, options, {onRetry = null} = {}) {
170
170
  if (response?.ok) {
171
171
  return response;
172
172
  }
173
+ const status = response?.status ?? null;
173
174
  if (response) {
174
175
  const contentType = response.headers.get('content-type') || '';
175
- error = contentType.includes('application/json')
176
- ? await response.json()
177
- : await response.text();
176
+ try {
177
+ error = contentType.includes('application/json')
178
+ ? await response.json()
179
+ : await response.text();
180
+ } catch (bodyError) {
181
+ if (status !== 529 || isAIRequestAbort(bodyError, signal)) {
182
+ throw bodyError;
183
+ }
184
+ error = bodyError;
185
+ }
178
186
  if (signal?.aborted) {
179
187
  throw normalizeAIRequestAbort(signal.reason);
180
188
  }
181
189
  }
182
- const status = response?.status ?? null;
183
190
  const message = is.string(error)
184
191
  ? error
185
192
  : error?.error?.message ?? error?.message;
@@ -81,8 +81,11 @@ two failure types share that three-retry budget. HTTP `429` with a message
81
81
  containing `overload` (case-insensitive) retains its unlimited three-second
82
82
  retry behavior and does not consume that budget. Each attempt reuses the exact
83
83
  destination, Fetch options, serialized request, and signal. Other HTTP errors,
84
- response decoding failures, and application callback failures do not retry.
85
- The last complete failure is thrown unchanged when recovery is exhausted.
84
+ successful-response decoding failures, and application callback failures do not
85
+ retry. A known HTTP `529` also retries when reading or parsing its diagnostic
86
+ body fails; `onRetry.error` retains that exact failure, which is thrown unchanged
87
+ if recovery is exhausted. Diagnostic-body failures for other HTTP statuses do
88
+ not retry. The last complete failure is thrown unchanged when recovery is exhausted.
86
89
  Pass a fresh
87
90
  `AbortController`'s `signal` and call `abort()` to cancel. Cancellation during
88
91
  the request, response-body read, retry wait, or callback settlement prevents
@@ -342,7 +342,9 @@ transcript is a masked vertical scroll viewport; status and composer remain
342
342
  outside it. Initial restoration follows the true bottom. User, assistant, tool,
343
343
  streaming, progress, and failure updates continue following it, including later
344
344
  message-card, status, composer, or viewport resizing, until the reader scrolls
345
- toward earlier content. Scrolling down to the bottom resumes following. Layout
345
+ toward earlier content. Scrolling down to the bottom or submitting an accepted
346
+ non-synthetic user message resumes following. Canceled or rejected submissions
347
+ and synthetic requests preserve the reader's position. Layout
346
348
  clamping, hidden views, and BFCache restoration preserve that choice;
347
349
  destruction releases scroll observation. Each
348
350
  restored or new message uses a separate semantic `<time>` element at the card's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.33.5",
3
+ "version": "0.33.6",
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",
@@ -1161,9 +1161,13 @@
1161
1161
  scrollTranscriptToBottom();
1162
1162
  }
1163
1163
 
1164
- function scrollTranscriptToBottom() {
1164
+ function scrollTranscriptToBottom(resumeFollowing = false) {
1165
1165
  // Read movement before writing: a reader's scroll event may still be queued.
1166
- if(!trackTranscriptScrollPosition() || !transcriptFollowing) return false;
1166
+ const visible = trackTranscriptScrollPosition();
1167
+ if(resumeFollowing === true && !destroyed) {
1168
+ transcriptFollowing = true;
1169
+ }
1170
+ if(!visible || !transcriptFollowing) return false;
1167
1171
  chatOutput.scrollTop = chatOutput.scrollHeight;
1168
1172
  transcriptScrollTop = chatOutput.scrollTop;
1169
1173
  return true;
@@ -3831,7 +3835,7 @@
3831
3835
  const visibleMessage=appendTranscriptMessage('user',text,host.name);
3832
3836
  visibleMessage.dataset.operationId=operationId;
3833
3837
  }
3834
- scrollTranscriptToBottom();
3838
+ scrollTranscriptToBottom(!eventContext.synthetic);
3835
3839
 
3836
3840
  if(host.aiAvailability.tts&&speech.muted===false){
3837
3841
  const aiRuntime=boundChatAI??globalThis.ai;