bunnyquery 1.12.1 → 1.14.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/README.md CHANGED
@@ -140,7 +140,8 @@ Mounts the widget. Returns the `BunnyQuery` object.
140
140
  | `attachmentParsers` | `array` | `null` | Client-side attachment parsers. See [Attachment parser plugins](#attachment-parser-plugins). |
141
141
  | `windowedIndexing` | `boolean` | `true` | Server-driven windowed indexing for text and grid files (see [file types](#supported-file-types)). Pass `false` to fall back to agent-driven paging, which keeps the traversal inside the model's turn budget and the tab open. |
142
142
  | `allowAnonymous` | `boolean` | `null` | Open the chat with no login for visitors without an account. `null` follows the project's own "Allow anonymous users" setting (`getConnectionInfo().conf.require_login`); `true`/`false` pins it. |
143
- | `liveStreaming` | `boolean` | `false` | Paint a chat answer into its bubble as it arrives, instead of at the end. A **request**, not a switch: the widget honours it only when your page's `skapi-js` actually carries skapi's half of the stream flag (it checks for `forwardRequestStream` and `forwardRequestFinalize`, or their older names `clientSecretRequestStream` and `clientSecretRequestFinalize` on an earlier `skapi-js`), and otherwise warns once and falls back to buffered replies. An older SDK silently drops the flag, which would leave the destination streaming SSE into a buffered row that reads back empty. It still also needs a polling worker that relays the response bytes, which the widget cannot check, so leave it off until the region you talk to is deployed. |
143
+ | `webAccess` | `boolean` | `null` | Whether the chat's answers may reach the open web (Claude `web_fetch`, OpenAI `web_search`). `null` follows the project's own **Web access for answers** switch on its Project Settings page (the `web_access` key of the project's `bq::settings` record), which is **off** unless the owner turned it on: answers then come only from the project's files and database. `true`/`false` pins it for this page, both ways. Resolution order: this option, then the project setting, then off. Indexing is not affected. |
144
+ | `liveStreaming` | `boolean` | `true` | Paint a chat answer into its bubble as it arrives, instead of at the end. On by default; pass `false` for buffered replies. Still a **request**, not a switch: the widget honours it only when your page's `skapi-js` actually carries skapi's half of the stream flag (it checks for `forwardRequestStream` and `forwardRequestFinalize`, or their older names `clientSecretRequestStream` and `clientSecretRequestFinalize` on an earlier `skapi-js`), and otherwise warns once and falls back to buffered replies. An older SDK silently drops the flag, which would leave the destination streaming SSE into a buffered row that reads back empty. It also needs a polling worker that relays the response bytes, which every deployed region now has; against a self-hosted worker that does not, pass `false`. |
144
145
  | `liveStreamingRealtime` | `boolean` | `false` | Deliver streamed chunks over skapi's websocket instead of waiting for the next poll tick. Requires `liveStreaming`. Off unless you ask for it: skapi's `joinRealtime` **replaces** the connection's group, so for the length of a turn it takes the room out from under whatever else your app uses realtime for. Purely an accelerator; with it off the reply still streams, on the poll's cadence. |
145
146
 
146
147
  ### Rebranding the widget
@@ -490,7 +491,8 @@ helpers. See the `.d.ts` shipped with `bunnyquery/engine`.
490
491
  | `poll` | `number?` | Value attached as `poll` on every request. Omit it if your `forwardRequest` already resolves with the final body; pass `0` for the deployed `skapi-js@latest` (needed for the early ack + a manual `.poll()` handle that powers queued-send cancel, the widget's case). |
491
492
  | `attachmentParsers` | `array?` | Client-side attachment parsers, registered at configure time. More can be added later with `registerAttachmentParser()`. See [Attachment parser plugins](#attachment-parser-plugins). |
492
493
  | `windowedIndexing` | `boolean?` | Opt in to **server-driven** windowed indexing for text and grid files (see [file types](#supported-file-types)). Off by default in the engine; the widget passes it as `true`. The deployed skapi workers support it; only leave it off against a self-hosted worker that does not yet strip the `_skapi_window` directive, where it would reach the provider as an unknown body field and fail the call terminally with no retry. |
493
- | `liveStreaming` | `boolean?` | Opt in to **live streaming** of chat turns. Off by default, and the backend ships first: a streamed row settles with a status and NO body (the answer was the stream), so against a worker that does not relay, the turn reads back empty. Pair it with `forwardRequestFinalize` and `forwardRequestStream`, and gate it on `skapiSupportsStreaming(skapi)`. |
494
+ | `liveStreaming` | `boolean?` | Opt in to **live streaming** of chat turns. Off by default in the engine (the widget passes it as `true`), and the backend ships first: a streamed row settles with a status and NO body (the answer was the stream), so against a worker that does not relay, the turn reads back empty. Pair it with `forwardRequestFinalize` and `forwardRequestStream`, and gate it on `skapiSupportsStreaming(skapi)`. |
495
+ | `webAccess` | `boolean?` | Whether a chat turn may reach the open web: Claude's `web_fetch` and OpenAI's `web_search` are attached to a chat request only when this resolves to `true`. Leave it out to follow the project's own `web_access` setting (the `bq::settings` record, read through `configureProjectSettings`), which is **off** unless the project owner turned it on; a boolean here overrides the project for your host, both ways. `webAccessEnabled(serviceId)` and `resolveWebAccess(serviceId)` answer the resolved switch (sync from the cache, or awaiting the settings fetch). Indexing passes keep their tools regardless. Pass the same value to `buildChatSystemPrompt({ webAccess })` so the prompt matches the tool list. |
494
496
  | `forwardRequestFinalize` | `function?` | `skapi.forwardRequestFinalize`, bound to your Skapi instance. Stores the version of a streamed turn that history keeps (the engine sends the assembled provider body, so it reads back exactly like a buffered turn) and releases that request's chunks. Without it a streamed turn is never finalized and its row stays empty. |
495
497
  | `forwardRequestStream` | `function?` | `skapi.forwardRequestStream`, bound to your Skapi instance. The **second half of the durability guarantee**: a row that settles while no poll is attached (closed tab, discarded background tab, slept device) is never finalized, so its answer stays in the chunk store and its history row is terminal and empty. Given the request id this drains that turn's chunks in one pass; the engine parses them exactly as it parses a live stream and finalizes what it read, so each row is recovered at most once. Without it the engine mints no recovery marker at all and behaves as it did before streaming. |
496
498
  | `onLiveStreamUpdate` | `function?` | Observation hook for a streaming turn (`{ serverItemId, ownerKey, phase, text, thinkingText, toolNames, complete, errored }`). The engine already paints the answer text itself, so this is only for affordances it does not decide the presentation of. Never throw from it. |
package/bunnyquery.css CHANGED
@@ -1241,6 +1241,37 @@
1241
1241
  font-style: italic;
1242
1242
  clear: both;
1243
1243
  }
1244
+ /* ---- citations + the no-source mark -------------------------------------*/
1245
+ /* Under an answer that read something: one chip per cited file (and page, in
1246
+ the label only). The chips are the ordinary stored-file link chips
1247
+ (.bq-link-button, emitted by renderInlineLinkHtml), so they inherit the
1248
+ expired / refreshing / unavailable states and the hover rule; this only lays
1249
+ them out as a row under a hairline. Absent entirely when there is nothing to
1250
+ cite, so a plain bubble is laid out exactly as before. */
1251
+ .bq-citations {
1252
+ display: flex;
1253
+ flex-wrap: wrap;
1254
+ align-items: baseline;
1255
+ gap: 0.25rem 0.6rem;
1256
+ margin-top: 0.45rem;
1257
+ padding-top: 0.35rem;
1258
+ border-top: 1px solid var(--bq-line);
1259
+ font-size: 0.72rem;
1260
+ line-height: 1.35;
1261
+ white-space: normal;
1262
+ clear: both;
1263
+ }
1264
+ .bq-citations .bq-link-button { max-width: 16rem; }
1265
+ /* The answer used no data tool: a small muted line, never a colour that reads
1266
+ as an error (the answer may still be right; what it was not is READ). */
1267
+ .bq-no-source-note {
1268
+ display: block;
1269
+ margin-top: 0.35rem;
1270
+ font-size: 0.68rem;
1271
+ font-style: italic;
1272
+ color: var(--bq-muted);
1273
+ clear: both;
1274
+ }
1244
1275
  /* Timestamp under a settled bubble (created for a user turn, response time for an
1245
1276
  assistant turn). Muted and small so it never competes with the message. */
1246
1277
  .bq-msg-time {